mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* 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