[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#319629: [CAN-2005-1768]: Race condition in ia32 compatability code for execve causes local DoS



tag 319629 +patch
thanks

On Sat, Jul 23, 2005 at 10:42:24AM -0500, Micah Anderson wrote:
> Package: kernel-source-2.4.27
> Version: 2.4.27-10
> Severity: normal
> Tags: security
> 
> http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-1768 reads:
> 
> Race condition in the ia32 compatibility code for the execve system
> call in Linux kernel 2.4 before 2.4.31 and 2.6 before 2.6.6 allows
> local users to cause a denial of service (kernel panic) and possibly
> execute arbitrary code via a concurrent thread that increments a
> pointer count after the nargs function has counted the pointers, but
> before the count is copied from user space to kernel space, which
> leads to a buffer overflow. 
> 
> I looked in the pending Changelog for 2.4.27 and did not see this CAN
> number listed. Please be sure to reference this CAN number in the
> changelog when fixed, as you always do.
> 
> Additional reference:
> http://marc.theaimsgroup.com/?l=bugtraq&m=112110120216116&w=2

Thanks, I have put the attached patch into svn and it shold appear
in the next release. amd64 does not have a 2.4 kernel (and techincally
isn't part of sarge anyway) so only ia64 is affected. However 
the patch should fix both.

-- 
Horms
commit 1e483bdd0ac8852a53e32e09059df9788619b3e8
tree 29e6ef82f987734d97da57af63a5f0410c21996c
parent bb6c40830e2f66b33c22275829a730ed078e430a
author Andi Kleen <ak@suse.de> 1119964612 +0200
committer Marcelo Tosatti <marcelo.tosatti@cyclades.com> 1120052986 -0300

[PATCH] Fix buffer overflow in x86-64/ia64 32bit execve

Fix buffer overflow in x86-64/ia64 32bit execve

Originally noted by Ilja van Sprundel

I fixed it for both x86-64 and IA64. Other architectures
are not affected.

Signed-off-by: Andi Kleen <ak@suse.de>

I:100644 100644 d398d537c16b1a744e4bf76136d19d1d80c25099 acfa7e6bb6307923a3c6738b0c498d99c8ce890a M	arch/ia64/ia32/sys_ia32.c
R:100644 100644 0c43987ce7ab3032b96036c7d9d22b81a22a151f 3692043ab57ab273234a2af15dc2d01560f3297a M	arch/x86_64/ia32/sys_ia32.c

arch/x86_64/ia32/sys_ia32.c manually applied and rediffed for 2.4.27
for Debian - Horms 25th July 2005

Key:
S: Skipped
I: Included Included verbatim
D: Deleted  Manually deleted by subsequent user edit
R: Revised  Manually revised by subsequent user edit

diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -94,7 +94,7 @@ asmlinkage unsigned long sys_brk(unsigne
 static DECLARE_MUTEX(ia32_mmap_sem);
 
 static int
-nargs (unsigned int arg, char **ap)
+nargs (unsigned int arg, char **ap, int max)
 {
 	unsigned int addr;
 	int n, err;
@@ -107,6 +107,8 @@ nargs (unsigned int arg, char **ap)
 		err = get_user(addr, (unsigned int *)A(arg));
 		if (err)
 			return err;
+		if (n > max)
+			return -E2BIG;
 		if (ap)
 			*ap++ = (char *) A(addr);
 		arg += sizeof(unsigned int);
@@ -128,10 +130,11 @@ sys32_execve (char *filename, unsigned i
 	int na, ne, len;
 	long r;
 
-	na = nargs(argv, NULL);
+	/* Allocates upto 2x MAX_ARG_PAGES */
+	na = nargs(argv, NULL, (MAX_ARG_PAGES*PAGE_SIZE) / sizeof(char *) - 1);
 	if (na < 0)
 		return na;
-	ne = nargs(envp, NULL);
+	ne = nargs(envp, NULL, (MAX_ARG_PAGES*PAGE_SIZE) / sizeof(char *) - 1 );
 	if (ne < 0)
 		return ne;
 	len = (na + ne + 2) * sizeof(*av);
@@ -143,10 +146,10 @@ sys32_execve (char *filename, unsigned i
 	av[na] = NULL;
 	ae[ne] = NULL;
 
-	r = nargs(argv, av);
+	r = nargs(argv, av, na);
 	if (r < 0)
 		goto out;
-	r = nargs(envp, ae);
+	r = nargs(envp, ae, ne);
 	if (r < 0)
 		goto out;
 
--- a/arch/x86_64/ia32/sys_ia32.c	2004-04-14 22:05:28.000000000 +0900
+++ b/arch/x86_64/ia32/sys_ia32.c	2005-07-25 17:29:16.000000000 +0900
@@ -2193,7 +2193,7 @@
 	return ret;
 } 
 
-static int nargs(u32 src, char **dst) 
+static int nargs(u32 src, char **dst, int max) 
 { 
 	int cnt;
 	u32 val; 
@@ -2207,7 +2207,7 @@
 			dst[cnt] = (char *)(u64)val; 
 		cnt++;
 		src += 4;
-		if (cnt >= (MAX_ARG_PAGES*PAGE_SIZE)/sizeof(void*))
+		if (cnt > max)
 			return -E2BIG; 
 	} while(val); 
 	if (dst)
@@ -2223,13 +2223,14 @@
 	int ret;
 	unsigned sz = 0; 
 	
+	/* Can actually allocate 2*MAX_ARG_PAGES */
 	if (argv) {
-	na = nargs(argv, NULL); 
+	na = nargs(argv, NULL, (MAX_ARG_PAGES * PAGE_SIZE)/sizeof(char*) - 1); 
 	if (na < 0) 
 		return -EFAULT; 
 	} 	
 	if (envp) { 
-	ne = nargs(envp, NULL); 
+	ne = nargs(envp, NULL, (MAX_ARG_PAGES * PAGE_SIZE)/sizeof(char*) - 1); 
 	if (ne < 0) 
 		return -EFAULT; 
 	}
@@ -2245,13 +2246,13 @@
 	} 
 	
 	if (argv) { 
-	ret = nargs(argv, buf);
+	ret = nargs(argv, buf, na);
 	if (ret < 0)
 		goto free;
 	}
 
 	if (envp) { 
-	ret = nargs(envp, buf + na); 
+	ret = nargs(envp, buf + na, ne); 
 	if (ret < 0)
 		goto free; 
 	}

Reply to: