Part 1: fix the kernel leak. init_new_context was called, and then __init_new_context; they both clear the LDT (by setting its size to 0) and alloc a new one; and since the LDT size has been cleared, alloc_ldt does not free() the LDT. It it exposed only if actually the UML process has an LDT to allocate, i.e. if the UML kernel thread had an LDT on the host when forking the init process. Part 2: avoid allocating a useless LDT for the init inside UML. Until now, when opening /proc/mm the SKAS patch copied the current LDT like on fork(). Since currently UML does not expect the userspace thread to inherit its own LDT, we can avoid this and save 4k for each child (useful when hosting lots of UML). And besides, that was waste memory. Actually UML never sets its one LDT, since it does not use TLS; it can just inherits it from his fathers, but it's useless. Signed-off-by: Paolo 'Blaisorblade' Giarrusso --- clean-linux-2.6.11-paolo/arch/i386/kernel/ldt.c | 8 ++++---- clean-linux-2.6.11-paolo/include/asm-i386/mmu_context.h | 14 +++++++++++++- clean-linux-2.6.11-paolo/include/asm-i386/processor.h | 2 -- clean-linux-2.6.11-paolo/mm/proc_mm.c | 10 ++++------ 4 files changed, 21 insertions(+), 13 deletions(-) diff -puN arch/i386/kernel/ldt.c~skas-new-leak-fix arch/i386/kernel/ldt.c --- clean-linux-2.6.11/arch/i386/kernel/ldt.c~skas-new-leak-fix 2005-07-10 16:55:33.000000000 +0200 +++ clean-linux-2.6.11-paolo/arch/i386/kernel/ldt.c 2005-07-10 16:57:39.000000000 +0200 @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ static void flush_ldt(void *null) @@ -89,12 +90,10 @@ static inline int copy_ldt(mm_context_t * we do not have to muck with descriptors here, that is * done in switch_mm() as needed. */ -int __init_new_context(struct mm_struct *mm, struct mm_struct *old_mm) +int copy_context(struct mm_struct *mm, struct mm_struct *old_mm) { int retval = 0; - init_MUTEX(&mm->context.sem); - mm->context.size = 0; if (old_mm && old_mm->context.size > 0) { down(&old_mm->context.sem); retval = copy_ldt(&mm->context, &old_mm->context); @@ -105,7 +104,8 @@ int __init_new_context(struct mm_struct int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { - return __init_new_context(mm, current->mm); + init_new_empty_context(mm); + return copy_context(mm, current->mm); } /* diff -puN include/asm-i386/mmu_context.h~skas-new-leak-fix include/asm-i386/mmu_context.h --- clean-linux-2.6.11/include/asm-i386/mmu_context.h~skas-new-leak-fix 2005-07-10 16:55:33.000000000 +0200 +++ clean-linux-2.6.11-paolo/include/asm-i386/mmu_context.h 2005-07-10 16:55:33.000000000 +0200 @@ -6,13 +6,25 @@ #include #include #include +#include /* - * Used for LDT copy/destruction. + * Used for LDT initialization/destruction. You cannot copy an LDT with + * init_new_context, since it thinks you are passing it a new LDT and won't + * deallocate its old content. */ int init_new_context(struct task_struct *tsk, struct mm_struct *mm); void destroy_context(struct mm_struct *mm); +/* LDT initialization for a clean environment - needed for SKAS.*/ +static inline void init_new_empty_context(struct mm_struct *mm) +{ + init_MUTEX(&mm->context.sem); + mm->context.size = 0; +} + +/* LDT copy for SKAS - for the above problem.*/ +int copy_context(struct mm_struct *mm, struct mm_struct *old_mm); static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { diff -puN mm/proc_mm.c~skas-new-leak-fix mm/proc_mm.c --- clean-linux-2.6.11/mm/proc_mm.c~skas-new-leak-fix 2005-07-10 16:55:33.000000000 +0200 +++ clean-linux-2.6.11-paolo/mm/proc_mm.c 2005-07-10 16:57:40.000000000 +0200 @@ -102,7 +102,9 @@ static ssize_t write_proc_mm(struct file break; } - __init_new_context(mm, from); + ret = copy_context(mm, from); + if(ret == 0) + ret = count; break; } default: @@ -122,9 +124,7 @@ static int open_proc_mm(struct inode *in if(mm == NULL) goto out_mem; - ret = init_new_context(current, mm); - if(ret) - goto out_free; + init_new_empty_context(mm); spin_lock(&mmlist_lock); list_add(&mm->mmlist, ¤t->mm->mmlist); @@ -135,8 +135,6 @@ static int open_proc_mm(struct inode *in return(0); - out_free: - mmput(mm); out_mem: return(ret); } diff -puN include/asm-i386/processor.h~skas-new-leak-fix include/asm-i386/processor.h --- clean-linux-2.6.11/include/asm-i386/processor.h~skas-new-leak-fix 2005-07-10 16:55:33.000000000 +0200 +++ clean-linux-2.6.11-paolo/include/asm-i386/processor.h 2005-07-10 16:55:33.000000000 +0200 @@ -664,8 +664,6 @@ extern inline void prefetchw(const void extern void select_idle_routine(const struct cpuinfo_x86 *c); -extern int __init_new_context(struct mm_struct *mm, struct mm_struct *old_mm); - #define cache_line_size() (boot_cpu_data.x86_cache_alignment) extern unsigned long boot_option_idle_override; _