Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 3013

kernel-2.6.18-194.11.1.el5.src.rpm

From: Anton Arapov <aarapov@redhat.com>
Subject: [RHEL5.1 PATCH] *REPOST* BZ275991: CVE-2007-3731 NULL pointer 	dereference triggered by ptrace
Date: Sat, 08 Sep 2007 21:02:16 +0200
Bugzilla: 275991
Message-Id: <h8lkbhyo93.fsf@pepelac.englab.brq.redhat.com>
Changelog: [ptrace] NULL pointer dereference triggered by ptrace


BZ#275991: (tracking bug number)
  https://bugzilla.redhat.com/show_bug.cgi?id=275991

Description:
  From Evan Teran: [http://bugzilla.kernel.org/show_bug.cgi?id=8765]
    it is possible to cause the kernel to reference a null pointer
  with simple ptrace code. the OOPS seems to indicate that it occurs
  in arch_ptrace. I noticed  when working on my debugger, that if i
  set the childs CS to certain invalid values, instead of a segfault
  (i believe this is the correct response to invalid cs). Not only
  would the ptraced app crash, but so would the debugger. After
  further investigation, I realized that the debugger crash was the
  kernel terminating the ptracer due to a null pointer in one of the
  ptrace functions.

Upstream status:
  commit# 29eb51101c02df517ca64ec472d7501127ad1da8
    - The code for LDT segment selectors was not robust in the face of
  a bogus selector set in %cs via ptrace before the single-step was
  done.
  commit# a10d9a71bafd3a283da240d2868e71346d2aef6f
    - The TRACE_IRQS_ON function in iret_exc: calls a C function
  without ensuring that the segments are set properly. Move the trace
  function and the enabling of interrupt into the C stub.

Test status:
  Has been tested for compilation, boot.
  Issue was reproduced by the test program(included to bugzilla).
  Patch fixes the problem.

Notice:
  BZ#248324 - original bugzilla number.

==
diff -aBburpN linux-2.6.18.noarch.orig/arch/i386/kernel/entry.S linux-2.6.18.noarch/arch/i386/kernel/entry.S
--- linux-2.6.18.noarch.orig/arch/i386/kernel/entry.S	2007-09-08 16:26:26.000000000 +0200
+++ linux-2.6.18.noarch/arch/i386/kernel/entry.S	2007-09-08 16:26:41.000000000 +0200
@@ -384,8 +384,6 @@ restore_nocheck_notrace:
 1:	iret
 .section .fixup,"ax"
 iret_exc:
-	TRACE_IRQS_ON
-	sti
 	pushl $0			# no error code
 	pushl $do_iret_error
 	jmp error_code
diff -aBburpN linux-2.6.18.noarch.orig/arch/i386/kernel/entry-xen.S linux-2.6.18.noarch/arch/i386/kernel/entry-xen.S
--- linux-2.6.18.noarch.orig/arch/i386/kernel/entry-xen.S	2007-09-08 16:26:26.000000000 +0200
+++ linux-2.6.18.noarch/arch/i386/kernel/entry-xen.S	2007-09-08 16:26:41.000000000 +0200
@@ -443,10 +443,6 @@ restore_nocheck_notrace:
 1:	iret
 .section .fixup,"ax"
 iret_exc:
-#ifndef CONFIG_XEN
-	TRACE_IRQS_ON
-	sti
-#endif
 	pushl $0			# no error code
 	pushl $do_iret_error
 	jmp error_code
diff -aBburpN linux-2.6.18.noarch.orig/arch/i386/kernel/ptrace.c linux-2.6.18.noarch/arch/i386/kernel/ptrace.c
--- linux-2.6.18.noarch.orig/arch/i386/kernel/ptrace.c	2007-09-08 16:26:26.000000000 +0200
+++ linux-2.6.18.noarch/arch/i386/kernel/ptrace.c	2007-09-08 16:26:41.000000000 +0200
@@ -186,14 +186,22 @@ static unsigned long convert_eip_to_line
 		u32 *desc;
 		unsigned long base;
 
+		seg &= ~7UL;
+		
 		down(&child->mm->context.sem);
-		desc = child->mm->context.ldt + (seg & ~7);
-		base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000);
+		if (unlikely((seg >> 3) >= child->mm->context.size))
+			addr = -1L; /* bogus selector, access would fault */
+		else {
+			desc = child->mm->context.ldt + seg;
+			base = ((desc[0] >> 16) |
+				((desc[1] & 0xff) << 16) |
+				(desc[1] & 0xff000000));
 
 		/* 16-bit code segment? */
 		if (!((desc[1] >> 22) & 1))
 			addr &= 0xffff;
 		addr += base;
+		}
 		up(&child->mm->context.sem);
 	}
 	return addr;
diff -aBburpN linux-2.6.18.noarch.orig/arch/i386/kernel/traps.c linux-2.6.18.noarch/arch/i386/kernel/traps.c
--- linux-2.6.18.noarch.orig/arch/i386/kernel/traps.c	2007-09-08 16:26:26.000000000 +0200
+++ linux-2.6.18.noarch/arch/i386/kernel/traps.c	2007-09-08 16:27:17.000000000 +0200
@@ -639,7 +639,9 @@ check_lazy_exec_limit(int cpu, struct pt
  */
 fastcall void do_iret_error(struct pt_regs *regs, long error_code)
 {
-	int ok = check_lazy_exec_limit(get_cpu(), regs, error_code);
+	int ok;
+	local_irq_enable();
+	ok = check_lazy_exec_limit(get_cpu(), regs, error_code);
 	put_cpu();
 	if (!ok && notify_die(DIE_TRAP, "iret exception", regs,
 			      error_code, 32, SIGSEGV) != NOTIFY_STOP) {
diff -aBburpN linux-2.6.18.noarch.orig/arch/i386/kernel/traps-xen.c linux-2.6.18.noarch/arch/i386/kernel/traps-xen.c
--- linux-2.6.18.noarch.orig/arch/i386/kernel/traps-xen.c	2007-09-08 16:26:26.000000000 +0200
+++ linux-2.6.18.noarch/arch/i386/kernel/traps-xen.c	2007-09-08 16:27:34.000000000 +0200
@@ -641,7 +641,11 @@ check_lazy_exec_limit(int cpu, struct pt
  */
 fastcall void do_iret_error(struct pt_regs *regs, long error_code)
 {
-	int ok = check_lazy_exec_limit(get_cpu(), regs, error_code);
+	int ok;
+#ifndef CONFIG_XEN	
+	local_irq_enable();
+#endif
+	ok = check_lazy_exec_limit(get_cpu(), regs, error_code);
 	put_cpu();
 	if (!ok && notify_die(DIE_TRAP, "iret exception", regs,
 			      error_code, 32, SIGSEGV) != NOTIFY_STOP) {
diff -aBburpN linux-2.6.18.noarch.orig/arch/x86_64/kernel/ptrace.c linux-2.6.18.noarch/arch/x86_64/kernel/ptrace.c
--- linux-2.6.18.noarch.orig/arch/x86_64/kernel/ptrace.c	2007-09-08 16:26:26.000000000 +0200
+++ linux-2.6.18.noarch/arch/x86_64/kernel/ptrace.c	2007-09-08 16:26:41.000000000 +0200
@@ -107,14 +107,22 @@ unsigned long convert_rip_to_linear(stru
 		u32 *desc;
 		unsigned long base;
 
+		seg &= ~7UL;
+		
 		down(&child->mm->context.sem);
-		desc = child->mm->context.ldt + (seg & ~7);
-		base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000);
+		if (unlikely((seg >> 3) >= child->mm->context.size))
+			addr = -1L; /* bogus selector, access would fault */
+		else {
+			desc = child->mm->context.ldt + seg;
+			base = ((desc[0] >> 16) |
+				((desc[1] & 0xff) << 16) |
+				(desc[1] & 0xff000000));
 
 		/* 16-bit code segment? */
 		if (!((desc[1] >> 22) & 1))
 			addr &= 0xffff;
 		addr += base;
+		}
 		up(&child->mm->context.sem);
 	}
 	return addr;

-- 
Anton Arapov, <aarapov@redhat.com>
Kernel Development, Red Hat
GPG Key ID: 0x6FA8C812