SKAS3: Bug for PTRACE_LDT on SMP host. From: Bodo Stroesser The SKAS3 host patch isn't smp-safe. The wrong part is the implementation of PTRACE_LDT. If the ptraced child runs on an other processor than its parent, and the child's mm still is the active_mm, the changed LDT isn't flushed out. The problem occurs in alloc_ldt, but to fix this, I had to change the params of copy_ldt, too. Signed-off-by: Paolo 'Blaisorblade' Giarrusso --- linux-2.6.11-paolo/arch/x86_64/kernel/ldt.c | 23 +++++++++++++---------- 1 files changed, 13 insertions(+), 10 deletions(-) Index: linux-2.6.git/arch/x86_64/kernel/ldt.c =================================================================== --- linux-2.6.git.orig/arch/x86_64/kernel/ldt.c +++ linux-2.6.git/arch/x86_64/kernel/ldt.c @@ -32,11 +32,12 @@ static void flush_ldt(void *null) } #endif -static int alloc_ldt(mm_context_t *pc, unsigned mincount, int reload) +static int alloc_ldt(struct mm_struct *mm, unsigned mincount, int reload) { void *oldldt; void *newldt; unsigned oldsize; + mm_context_t * pc = &mm->context; if (mincount <= (unsigned)pc->size) return 0; @@ -59,18 +60,20 @@ static int alloc_ldt(mm_context_t *pc, u wmb(); pc->size = mincount; wmb(); - if (reload && (¤t->active_mm->context == pc)) { + if (reload) { #ifdef CONFIG_SMP cpumask_t mask; preempt_disable(); mask = cpumask_of_cpu(smp_processor_id()); - load_LDT(pc); - if (!cpus_equal(current->mm->cpu_vm_mask, mask)) + if (¤t->active_mm->context == pc) + load_LDT(pc); + if (!cpus_equal(mm->cpu_vm_mask, mask)) smp_call_function(flush_ldt, NULL, 1, 1); preempt_enable(); #else - load_LDT(pc); + if (¤t->active_mm->context == pc) + load_LDT(pc); #endif } if (oldsize) { @@ -82,12 +85,12 @@ static int alloc_ldt(mm_context_t *pc, u return 0; } -static inline int copy_ldt(mm_context_t *new, mm_context_t *old) +static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old) { - int err = alloc_ldt(new, old->size, 0); + int err = alloc_ldt(new, old->context.size, 0); if (err < 0) return err; - memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); + memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE); return 0; } @@ -101,7 +104,7 @@ int copy_context(struct mm_struct *mm, s if (old_mm && old_mm->context.size > 0) { down(&old_mm->context.sem); - retval = copy_ldt(&mm->context, &old_mm->context); + retval = copy_ldt(mm, old_mm); up(&old_mm->context.sem); } return retval; @@ -198,7 +201,7 @@ static int write_ldt(struct mm_struct * down(&mm->context.sem); if (ldt_info.entry_number >= (unsigned)mm->context.size) { - error = alloc_ldt(&mm->context, ldt_info.entry_number+1, 1); + error = alloc_ldt(mm, ldt_info.entry_number+1, 1); if (error < 0) goto out_unlock; }