[PATCH] arch/i386/kernel/ldt.c broken in 2.3.x?

From: Mikael Pettersson (mikpe@csd.uu.se)
Date: Thu May 18 2000 - 19:34:48 EST


In 2.3.x, when arch/i386/kernel/ldt.c:write_ldt() vmalloc():s
a new LDT, it does not clear that memory before using it.
The previous contents of that memory becomes the LDT, and it
can also leak to user-space if the user calls modify_ldt(0,,)
to get a copy of the LDT.

I believe this is broken:

1. Leaking someone else's old data to the user is usually
   not acceptable.

2. Making the LDT register point to partially initialised
   memory is at best lazy. In theory, it could be used by
   an adversarial user to transition to CPL 0 while still
   executing the user's own code, if the LDT could be made to
   contain a "suitable" call-gate and code-segment pair.(*)
   Invoking a call-gate to go to CPL 0 causes a stack switch
   to a stack segment whose selector is recorded in the TSS.
   This may or may not succeed, depending on whether the linear
   address for the CPL 0 stack is valid in the user's page
   tables or not. (I don't know if this will be the case.)

   (*) The adversary would use other kernel services to flood
   the kernel's memory pools with doctored LDT entries, and
   then use modify_ldt() to attach these prepared memory areas
   to the LDT. With some diligence, this could work.

3. Legitimate user-space code may be confused by non-NULL
   LDT entries which it hasn't written itself.

2.2.x clears the memory with a memset() before using it.
The memset() was removed in 2.3.11.

Unless there's a good reason why a new LDT shouldn't be cleared,
I suggest that the patch below be applied to 2.3.x ASAP.

/Mikael

--- linux-2.3.99-pre8/arch/i386/kernel/ldt.c.~1~ Tue Aug 10 23:48:36 1999
+++ linux-2.3.99-pre8/arch/i386/kernel/ldt.c Fri May 19 00:26:00 2000
@@ -93,6 +93,7 @@
                 mm->segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
                 if (!mm->segments)
                         goto out_unlock;
+ memset(mm->segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
                 
                 if (atomic_read(&mm->mm_users) > 1)
                         printk(KERN_WARNING "LDT allocated for cloned task!\n");

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue May 23 2000 - 21:00:16 EST