* [EMAIL PROTECTED] ([EMAIL PROTECTED]) wrote:
> Make the LDT a desc_struct pointer, since this is what it actually is.

I like that plan.

> There is code which relies on the fact that LDTs are allocated in page
> chunks, and it is both cleaner and more convenient to keep the rather
> poorly named "size" variable from the LDT in terms of LDT pages.

I noticed it's replaced by context.ldt and context.ldt_pages, which
appear to be decoupling the overloaded use from before.  Looks sane.
More comments below.

> Signed-off-by: Zachary Amsden <[EMAIL PROTECTED]>
> Index: linux-2.6.13/include/asm-i386/mmu.h
> ===================================================================
> --- linux-2.6.13.orig/include/asm-i386/mmu.h  2005-08-15 11:16:59.000000000 
> -0700
> +++ linux-2.6.13/include/asm-i386/mmu.h       2005-08-15 11:19:49.000000000 
> -0700
> @@ -9,9 +9,9 @@
>   * cpu_vm_mask is used to optimize ldt flushing.
>   */
>  typedef struct { 
> -     int size;
>       struct semaphore sem;
> -     void *ldt;
> +     struct desc_struct *ldt;
> +     int ldt_pages;
>  } mm_context_t;
>  
>  #endif
> Index: linux-2.6.13/include/asm-i386/desc.h
> ===================================================================
> --- linux-2.6.13.orig/include/asm-i386/desc.h 2005-08-15 11:16:59.000000000 
> -0700
> +++ linux-2.6.13/include/asm-i386/desc.h      2005-08-15 11:19:49.000000000 
> -0700
> @@ -6,6 +6,9 @@
>  
>  #define CPU_16BIT_STACK_SIZE 1024
>  
> +/* The number of LDT entries per page */
> +#define LDT_ENTRIES_PER_PAGE (PAGE_SIZE / LDT_ENTRY_SIZE)
> +
>  #ifndef __ASSEMBLY__
>  
>  #include <linux/preempt.h>
> @@ -30,7 +33,7 @@
>  static inline unsigned long get_desc_base(struct desc_struct *desc)
>  {
>       unsigned long base;
> -     base = ((desc->a >> 16)  & 0x0000ffff) |
> +     base = (desc->a >> 16) |

Seemingly unrelated.

>               ((desc->b << 16) & 0x00ff0000) |
>               (desc->b & 0xff000000);
>       return base;
> @@ -171,7 +174,7 @@
>  static inline void load_LDT_nolock(mm_context_t *pc, int cpu)
>  {
>       void *segments = pc->ldt;
> -     int count = pc->size;
> +     int count = pc->ldt_pages * LDT_ENTRIES_PER_PAGE;
>  
>       if (likely(!count)) {
>               segments = &default_ldt[0];
> Index: linux-2.6.13/include/asm-i386/mmu_context.h
> ===================================================================
> --- linux-2.6.13.orig/include/asm-i386/mmu_context.h  2005-08-15 
> 11:16:59.000000000 -0700
> +++ linux-2.6.13/include/asm-i386/mmu_context.h       2005-08-15 
> 11:19:49.000000000 -0700
> @@ -19,7 +19,7 @@
>       memset(&mm->context, 0, sizeof(mm->context));
>       init_MUTEX(&mm->context.sem);
>       old_mm = current->mm;
> -     if (old_mm && unlikely(old_mm->context.size > 0)) {
> +     if (old_mm && unlikely(old_mm->context.ldt)) {
>               retval = copy_ldt(&mm->context, &old_mm->context);
>       }
>       if (retval == 0)
> @@ -32,7 +32,7 @@
>   */
>  static inline void destroy_context(struct mm_struct *mm)
>  {
> -     if (unlikely(mm->context.size))
> +     if (unlikely(mm->context.ldt))
>               destroy_ldt(mm);
>       del_lazy_mm(mm);
>  }
> Index: linux-2.6.13/include/asm-i386/mach-default/mach_desc.h
> ===================================================================
> --- linux-2.6.13.orig/include/asm-i386/mach-default/mach_desc.h       
> 2005-08-15 11:16:59.000000000 -0700
> +++ linux-2.6.13/include/asm-i386/mach-default/mach_desc.h    2005-08-15 
> 11:19:49.000000000 -0700
> @@ -62,11 +62,10 @@
>       _set_tssldt_desc(&get_cpu_gdt_table(cpu)[GDT_ENTRY_LDT], (int)addr, 
> ((size << 3)-1), 0x82);
>  }
>  
> -static inline int write_ldt_entry(void *ldt, int entry, __u32 entry_a, __u32 
> entry_b)
> +static inline int write_ldt_entry(struct desc_struct *ldt, int entry, __u32 
> entry_a, __u32 entry_b)
>  {
> -     __u32 *lp = (__u32 *)((char *)ldt + entry*8);
> -     *lp = entry_a;
> -     *(lp+1) = entry_b;
> +     ldt[entry].a = entry_a;
> +     ldt[entry].b = entry_b;
>       return 0;
>  }
>  
> Index: linux-2.6.13/arch/i386/kernel/ptrace.c
> ===================================================================
> --- linux-2.6.13.orig/arch/i386/kernel/ptrace.c       2005-08-15 
> 11:16:59.000000000 -0700
> +++ linux-2.6.13/arch/i386/kernel/ptrace.c    2005-08-15 11:19:49.000000000 
> -0700
> @@ -164,18 +164,20 @@
>        * and APM bios ones we just ignore here.
>        */
>       if (segment_from_ldt(seg)) {
> -             u32 *desc;
> +             mm_context_t *context;
> +             struct desc_struct *desc;
>               unsigned long base;
>  
> -             down(&child->mm->context.sem);
> -             desc = child->mm->context.ldt + (seg & ~7);
> -             base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 
> 0xff000000);
> +             context = &child->mm->context;
> +             down(&context->sem);
> +             desc = &context->ldt[segment_index(seg)];
> +             base = get_desc_base(desc);
>  
>               /* 16-bit code segment? */
> -             if (!((desc[1] >> 22) & 1))
> +             if (!get_desc_32bit(desc))
>                       addr &= 0xffff;
>               addr += base;
> -             up(&child->mm->context.sem);
> +             up(&context->sem);
>       }
>       return addr;
>  }
> Index: linux-2.6.13/arch/i386/kernel/ldt.c
> ===================================================================
> --- linux-2.6.13.orig/arch/i386/kernel/ldt.c  2005-08-15 11:16:59.000000000 
> -0700
> +++ linux-2.6.13/arch/i386/kernel/ldt.c       2005-08-15 11:19:49.000000000 
> -0700
> @@ -28,28 +28,27 @@
>  }
>  #endif
>  
> -static inline int alloc_ldt(mm_context_t *pc, const int oldsize, int 
> mincount, const int reload)
> +static inline int alloc_ldt(mm_context_t *pc, const int old_pages, int 
> new_pages, const int reload)
>  {
> -     void *oldldt;
> -     void *newldt;
> +     struct desc_struct *oldldt;
> +     struct desc_struct *newldt;
>  

Not quite related here (since change was introduced in earlier patch),
but old alloc_ldt special cased when room was available.  This is gone,
so am I reading this correctly, each time through it will allocate a
new one, and free the old one (if it existed)?  Just double checking
that change doesn't introduce possible mem leak.

> -     mincount = (mincount+511)&(~511);
> -     if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE)
> -             newldt = vmalloc(mincount*LDT_ENTRY_SIZE);
> +     if (new_pages > 1)
> +             newldt = vmalloc(new_pages*PAGE_SIZE);
>       else
> -             newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL);
> +             newldt = kmalloc(PAGE_SIZE, GFP_KERNEL);

If so, then full page is likely to be reusable in common case, no? (If
there's such a thing as LDT common case ;-)

>       if (!newldt)
>               return -ENOMEM;
>  
> -     if (oldsize)
> -             memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE);
> +     if (old_pages)
> +             memcpy(newldt, pc->ldt, old_pages*PAGE_SIZE);
>       oldldt = pc->ldt;
>       if (reload)
> -             memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, 
> (mincount-oldsize)*LDT_ENTRY_SIZE);
> +             memset(newldt+old_pages*LDT_ENTRIES_PER_PAGE, 0, 
> (new_pages-old_pages)*PAGE_SIZE);

In fact, I _think_ this causes a problem.  Who says newldt is bigger
than old one?  This looks like user-triggerable oops to me.

>       pc->ldt = newldt;
>       wmb();
> -     pc->size = mincount;
> +     pc->ldt_pages = new_pages;
>       wmb();
>  
>       /*
> @@ -60,20 +59,20 @@
>  #ifdef CONFIG_SMP
>               cpumask_t mask;
>               preempt_disable();
> -             SetPagesLDT(pc->ldt, (pc->size * LDT_ENTRY_SIZE) / PAGE_SIZE);
> +             SetPagesLDT(pc->ldt, pc->ldt_pages);
>               load_LDT(pc);
>               mask = cpumask_of_cpu(smp_processor_id());
>               if (!cpus_equal(current->mm->cpu_vm_mask, mask))
>                       smp_call_function(flush_ldt, NULL, 1, 1);
>               preempt_enable();
>  #else
> -             SetPagesLDT(pc->ldt, (pc->size * LDT_ENTRY_SIZE) / PAGE_SIZE);
> +             SetPagesLDT(pc->ldt, pc->ldt_pages);
>               load_LDT(pc);
>  #endif
>       }
> -     if (oldsize) {
> -             ClearPagesLDT(oldldt, (oldsize * LDT_ENTRY_SIZE) / PAGE_SIZE);
> -             if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE)
> +     if (old_pages) {
> +             ClearPagesLDT(oldldt, old_pages);
> +             if (old_pages > 1)
>                       vfree(oldldt);
>               else
>                       kfree(oldldt);
> @@ -86,10 +85,10 @@
>       int err;
>  
>       down(&old->sem);
> -     err = alloc_ldt(new, 0, old->size, 0);
> +     err = alloc_ldt(new, 0, old->ldt_pages, 0);
>       if (!err) {
> -             memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
> -             SetPagesLDT(new->ldt, (new->size * LDT_ENTRY_SIZE) / PAGE_SIZE);
> +             memcpy(new->ldt, old->ldt, old->ldt_pages*PAGE_SIZE);
> +             SetPagesLDT(new->ldt, new->ldt_pages);
>       }
>       up(&old->sem);
>       return err;
> @@ -97,14 +96,16 @@
>  
>  void destroy_ldt(struct mm_struct *mm)
>  {
> +     int pages = mm->context.ldt_pages;
> +
>       if (mm == current->active_mm)
>               clear_LDT();
> -     ClearPagesLDT(mm->context.ldt, (mm->context.size * LDT_ENTRY_SIZE) / 
> PAGE_SIZE);
> -     if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE)
> +     ClearPagesLDT(mm->context.ldt, pages);
> +     if (pages > 1)
>               vfree(mm->context.ldt);
>       else
>               kfree(mm->context.ldt);
> -     mm->context.size = 0;
> +     mm->context.ldt_pages = 0;
>  }
>  
>  static int read_ldt(void __user * ptr, unsigned long bytecount)
> @@ -113,13 +114,13 @@
>       unsigned long size;
>       struct mm_struct * mm = current->mm;
>  
> -     if (!mm->context.size)
> +     if (!mm->context.ldt_pages)
>               return 0;
>       if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES)
>               bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES;
>  
>       down(&mm->context.sem);
> -     size = mm->context.size*LDT_ENTRY_SIZE;
> +     size = mm->context.ldt_pages*PAGE_SIZE;
>       if (size > bytecount)
>               size = bytecount;

This now looks like you can leak data?  Since full page is unlikely
used, but accounting is done in page sizes.  Asking to read_ldt with
bytcount of PAGE_SIZE could give some uninitialzed data back to user.
Did I miss the spot where this is always zero-filled?

> @@ -166,6 +167,7 @@
>       __u32 entry_1, entry_2;
>       int error;
>       struct user_desc ldt_info;
> +     int page_number;
>  
>       error = -EINVAL;
>       if (bytecount != sizeof(ldt_info))
> @@ -184,10 +186,11 @@
>                       goto out;
>       }
>  
> +     page_number = ldt_info.entry_number / LDT_ENTRIES_PER_PAGE;
>       down(&mm->context.sem);
> -     if (ldt_info.entry_number >= mm->context.size) {
> -             error = alloc_ldt(&current->mm->context, mm->context.size,
> -                                     ldt_info.entry_number+1, 1);
> +     if (page_number >= mm->context.ldt_pages) {
> +             error = alloc_ldt(&current->mm->context, mm->context.ldt_pages,
> +                                     page_number+1, 1);
>               if (error < 0)
>                       goto out_unlock;
>       }
> Index: linux-2.6.13/arch/i386/kernel/kprobes.c
> ===================================================================
> --- linux-2.6.13.orig/arch/i386/kernel/kprobes.c      2005-08-15 
> 11:16:59.000000000 -0700
> +++ linux-2.6.13/arch/i386/kernel/kprobes.c   2005-08-15 11:19:49.000000000 
> -0700
> @@ -164,8 +164,7 @@
>        */
>       if (segment_from_ldt(regs->xcs) && (current->mm)) {
>               struct desc_struct *desc;
> -             desc = (struct desc_struct *) ((char *) 
> current->mm->context.ldt +
> -                                              (segment_index(regs->xcs) * 
> 8));
> +             desc = &current->mm->context.ldt[segment_index(regs->xcs)];
>               addr = (kprobe_opcode_t *) (get_desc_base(desc) + regs->eip -
>                                               sizeof(kprobe_opcode_t));
>       } else {
> 
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to