* Re: [PATCH 3/6] i386 virtualization - Make ldt a desc struct @ 2005-08-16 17:03 Chuck Ebbert 2005-08-16 18:44 ` Zachary Amsden 0 siblings, 1 reply; 6+ messages in thread From: Chuck Ebbert @ 2005-08-16 17:03 UTC (permalink / raw) To: Zachary Amsden; +Cc: linux-kernel On Mon, 15 Aug 2005 at 15:59:39 -0700, zach@vmware.com wrote: > --- 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); > } Here you changed the code so it no longer tests the size field, however: > --- 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 <--SNIP--> > @@ -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) destroy_ldt does not zero "ldt", just the size. Potential bug? Also: > --- 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; Can't this be declared on one line? ...and BTW could you add: QUILT_DIFF_OPTS=-p to your shell env? It makes the patches much easier to review. __ Chuck ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 3/6] i386 virtualization - Make ldt a desc struct 2005-08-16 17:03 [PATCH 3/6] i386 virtualization - Make ldt a desc struct Chuck Ebbert @ 2005-08-16 18:44 ` Zachary Amsden 2005-08-16 19:05 ` [PATCH] i386 / desc_empty macro is incorrect Chris Wright 2005-08-16 20:41 ` [PATCH 3/6] i386 virtualization - Make ldt a desc struct Chris Wright 0 siblings, 2 replies; 6+ messages in thread From: Zachary Amsden @ 2005-08-16 18:44 UTC (permalink / raw) To: Chuck Ebbert, Chris Wright, Andrew Morton Cc: linux-kernel, virtualization, Pratap Subrahmanyam [-- Attachment #1: Type: text/plain, Size: 808 bytes --] Chuck Ebbert wrote: > >>@@ -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) >> >> > > destroy_ldt does not zero "ldt", just the size. Potential bug? > > Not a bug, truly unnecessary at all. [-- Attachment #2: remove-useless-zeroing --] [-- Type: text/plain, Size: 1231 bytes --] Several reviewers noticed that initialization and destruction of the mm->context is unnecessary, since the entire MM struct is zeroed on allocation anyways. Verified with BUG_ON(mm->context.ldt || mm->context.ldt_pages); Signed-off-by: Zachary Amsden <zach@vmware.com> 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:23:32.000000000 -0700 +++ linux-2.6.13/include/asm-i386/mmu_context.h 2005-08-16 11:35:11.000000000 -0700 @@ -16,7 +16,6 @@ struct mm_struct * old_mm; int retval = 0; - memset(&mm->context, 0, sizeof(mm->context)); init_MUTEX(&mm->context.sem); old_mm = current->mm; if (old_mm && unlikely(old_mm->context.ldt)) { Index: linux-2.6.13/arch/i386/kernel/ldt.c =================================================================== --- linux-2.6.13.orig/arch/i386/kernel/ldt.c 2005-08-15 11:23:32.000000000 -0700 +++ linux-2.6.13/arch/i386/kernel/ldt.c 2005-08-16 11:12:59.000000000 -0700 @@ -105,7 +105,6 @@ vfree(mm->context.ldt); else kfree(mm->context.ldt); - mm->context.ldt_pages = 0; } static int read_ldt(void __user * ptr, unsigned long bytecount) ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH] i386 / desc_empty macro is incorrect 2005-08-16 18:44 ` Zachary Amsden @ 2005-08-16 19:05 ` Chris Wright 2005-08-16 19:18 ` Linus Torvalds 2005-08-16 20:41 ` [PATCH 3/6] i386 virtualization - Make ldt a desc struct Chris Wright 1 sibling, 1 reply; 6+ messages in thread From: Chris Wright @ 2005-08-16 19:05 UTC (permalink / raw) To: torvalds, akpm Cc: Zachary Amsden, Chuck Ebbert, Chris Wright, virtualization, linux-kernel From: Zachary Amsden <zach@vmware.com> Chuck Ebbert wrote: > I think that should be "|" instead of "+". I think so too. I merely moved the code here and didn't notice it in all this excitement. 0x00cf9a000xff306600 => Present CPL-0 32-bit code segment, base 0x0000ff30, limit 0xf6601 pages, for which desc_empty(desc) is true. Thankfully, this is not used as a security check, but it can falsely overwrite TLS segments with carefully chosen base / limits. I do not believe this is an issue in practice, but it is a kernel bug. Nice catch. Looks like it affects all 2.6.X kernels. Chuck Ebbert noticed that the desc_empty macro is incorrect. Fix it. Signed-off-by: Zachary Amsden <zach@vmware.com> Signed-off-by: Chris Wright <chrisw@osdl.org> --- diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h --- a/include/asm-i386/processor.h +++ b/include/asm-i386/processor.h @@ -29,7 +29,7 @@ struct desc_struct { }; #define desc_empty(desc) \ - (!((desc)->a + (desc)->b)) + (!((desc)->a | (desc)->b)) #define desc_equal(desc1, desc2) \ (((desc1)->a == (desc2)->a) && ((desc1)->b == (desc2)->b)) ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] i386 / desc_empty macro is incorrect 2005-08-16 19:05 ` [PATCH] i386 / desc_empty macro is incorrect Chris Wright @ 2005-08-16 19:18 ` Linus Torvalds 0 siblings, 0 replies; 6+ messages in thread From: Linus Torvalds @ 2005-08-16 19:18 UTC (permalink / raw) To: Chris Wright Cc: Andrew Morton, Zachary Amsden, Chuck Ebbert, virtualization, linux-kernel, Andi Kleen On Tue, 16 Aug 2005, Chris Wright wrote: > > Chuck Ebbert noticed that the desc_empty macro is incorrect. Fix it. x86-64 had the same thing. I added that to the fix as obvious. Linus ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 3/6] i386 virtualization - Make ldt a desc struct 2005-08-16 18:44 ` Zachary Amsden 2005-08-16 19:05 ` [PATCH] i386 / desc_empty macro is incorrect Chris Wright @ 2005-08-16 20:41 ` Chris Wright 2005-08-16 20:56 ` Zachary Amsden 1 sibling, 1 reply; 6+ messages in thread From: Chris Wright @ 2005-08-16 20:41 UTC (permalink / raw) To: Zachary Amsden Cc: Chuck Ebbert, Chris Wright, Andrew Morton, linux-kernel, virtualization, Pratap Subrahmanyam * Zachary Amsden (zach@vmware.com) wrote: > Several reviewers noticed that initialization and destruction of the > mm->context is unnecessary, since the entire MM struct is zeroed on > allocation anyways. well, on fork it should be just shallow copied rather than zeroed. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 3/6] i386 virtualization - Make ldt a desc struct 2005-08-16 20:41 ` [PATCH 3/6] i386 virtualization - Make ldt a desc struct Chris Wright @ 2005-08-16 20:56 ` Zachary Amsden 0 siblings, 0 replies; 6+ messages in thread From: Zachary Amsden @ 2005-08-16 20:56 UTC (permalink / raw) To: Chris Wright Cc: Chuck Ebbert, Andrew Morton, linux-kernel, virtualization, Pratap Subrahmanyam [-- Attachment #1: Type: text/plain, Size: 462 bytes --] Chris Wright wrote: >* Zachary Amsden (zach@vmware.com) wrote: > > >>Several reviewers noticed that initialization and destruction of the >>mm->context is unnecessary, since the entire MM struct is zeroed on >>allocation anyways. >> >> > >well, on fork it should be just shallow copied rather than zeroed. > > Right you are. That turned out to be a really bad idea (TM). Updated my ldt test and got the expected panic with the BUG_ON left in. Zach [-- Attachment #2: bobo.gif --] [-- Type: image/gif, Size: 9944 bytes --] [-- Attachment #3: ldt.c --] [-- Type: text/plain, Size: 3663 bytes --] /* * Copyright (c) 2005, Zachary Amsden (zach@vmware.com) * This is licensed under the GPL. */ #include <stdio.h> #include <signal.h> #include <asm/ldt.h> #include <asm/segment.h> #include <sys/types.h> #include <unistd.h> #include <sys/mman.h> #include <sched.h> #define __KERNEL__ #include <asm/page.h> /* * Spin modifying LDT entry 1 to get contention on the mm->context * semaphore. */ void evil_child(void *addr) { struct user_desc desc; while (1) { desc.entry_number = 1; desc.base_addr = addr; desc.limit = 1; desc.seg_32bit = 1; desc.contents = MODIFY_LDT_CONTENTS_CODE; desc.read_exec_only = 0; desc.limit_in_pages = 1; desc.seg_not_present = 0; desc.useable = 1; if (modify_ldt(1, &desc, sizeof(desc)) != 0) { perror("modify_ldt"); abort(); } } exit(0); } void catch_sig(int signo, struct sigcontext ctx) { return; } void main(void) { struct user_desc desc; char *code; unsigned long long tsc; char *stack; pid_t child; int i; unsigned long long lasttsc = 0; code = (char *)mmap(0, 8192, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); /* Test 1 - CODE, 32-BIT, 2 page limit */ desc.entry_number = 0; desc.base_addr = code; desc.limit = 1; desc.seg_32bit = 1; desc.contents = MODIFY_LDT_CONTENTS_CODE; desc.read_exec_only = 0; desc.limit_in_pages = 1; desc.seg_not_present = 0; desc.useable = 1; if (modify_ldt(1, &desc, sizeof(desc)) != 0) { perror("modify_ldt"); abort(); } printf("INFO: code base is 0x%08x\n", (unsigned)code); code[0x0ffe] = 0x0f; /* rdtsc */ code[0x0fff] = 0x31; code[0x1000] = 0xcb; /* lret */ __asm__ __volatile("lcall $7,$0xffe" : "=A" (tsc)); printf("INFO: TSC is 0x%016llx\n", tsc); /* * Fork an evil child that shares the same MM context */ stack = malloc(8192); child = clone(evil_child, stack, CLONE_VM, 0xb0b0); if (child == -1) { perror("clone"); abort(); } /* Test 2 - CODE, 32-BIT, 4097 byte limit */ desc.entry_number = 512; desc.base_addr = code; desc.limit = 4096; desc.seg_32bit = 1; desc.contents = MODIFY_LDT_CONTENTS_CODE; desc.read_exec_only = 0; desc.limit_in_pages = 0; desc.seg_not_present = 0; desc.useable = 1; if (modify_ldt(1, &desc, sizeof(desc)) != 0) { perror("modify_ldt"); abort(); } code[0x0ffe] = 0x0f; /* rdtsc */ code[0x0fff] = 0x31; code[0x1000] = 0xcb; /* lret */ __asm__ __volatile("lcall $0x1007,$0xffe" : "=A" (tsc)); /* * Test 3 - CODE, 32-BIT, maximal LDT. Race against evil * child while taking debug traps on LDT CS. */ for (i = 0; i < 1000; i++) { signal(SIGTRAP, catch_sig); desc.entry_number = 8191; desc.base_addr = code; desc.limit = 4097; desc.seg_32bit = 1; desc.contents = MODIFY_LDT_CONTENTS_CODE; desc.read_exec_only = 0; desc.limit_in_pages = 0; desc.seg_not_present = 0; desc.useable = 1; if (modify_ldt(1, &desc, sizeof(desc)) != 0) { perror("modify_ldt"); abort(); } code[0x0ffe] = 0x0f; /* rdtsc */ code[0x0fff] = 0x31; code[0x1000] = 0xcc; /* int3 */ code[0x1001] = 0xcb; /* lret */ __asm__ __volatile("lcall $0xffff,$0xffe" : "=A" (tsc)); if (tsc < lasttsc) { printf("WARNING: TSC went backwards\n"); } lasttsc = tsc; } if (kill(child, SIGTERM) != 0) { perror("kill"); abort(); } if (fork() == 0) { printf("PASS: LDT code segment\n"); } } ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2005-08-16 20:57 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2005-08-16 17:03 [PATCH 3/6] i386 virtualization - Make ldt a desc struct Chuck Ebbert 2005-08-16 18:44 ` Zachary Amsden 2005-08-16 19:05 ` [PATCH] i386 / desc_empty macro is incorrect Chris Wright 2005-08-16 19:18 ` Linus Torvalds 2005-08-16 20:41 ` [PATCH 3/6] i386 virtualization - Make ldt a desc struct Chris Wright 2005-08-16 20:56 ` Zachary Amsden
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
Powered by JetHome