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: