[PATCH] Fix buffer overflow in x86-64/ia64 32bit execve
Linux Kernel Mailing List <[email protected]> Thu, 30 Jun 2005 22:45:00 -0700
| Newsgroups | gmane.linux.kernel.commits.2-4 |
|---|---|
| Message-ID | <[email protected]> |
tree 29e6ef82f987734d97da57af63a5f0410c21996c parent bb6c40830e2f66b33c22275829a730ed078e430a author Andi Kleen <[email protected]> Tue, 28 Jun 2005 15:16:52 +0200 committer Marcelo Tosatti <[email protected]> Wed, 29 Jun 2005 16:49:46 -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 <[email protected]> arch/ia64/ia32/sys_ia32.c | 13 ++++++++----- arch/x86_64/ia32/sys_ia32.c | 17 +++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) 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; diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c --- a/arch/x86_64/ia32/sys_ia32.c +++ b/arch/x86_64/ia32/sys_ia32.c @@ -2200,7 +2200,7 @@ asmlinkage long sys32_ustat(dev_t dev, s return ret; } -static int nargs(u32 src, char **dst) +static int nargs(u32 src, char **dst, int max) { int cnt; u32 val; @@ -2210,13 +2210,13 @@ static int nargs(u32 src, char **dst) int ret = get_user(val, (__u32 *)(u64)src); if (ret) return ret; + if (cnt > max) + return -E2BIG; if (dst) dst[cnt] = (char *)(u64)val; cnt++; src += 4; - if (cnt >= (MAX_ARG_PAGES * PAGE_SIZE) / sizeof(char *)) - return -E2BIG; - } while(val); + } while(val); if (dst) dst[cnt-1] = 0; return cnt; @@ -2230,13 +2230,14 @@ asmlinkage long sys32_execve(char *name, 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; } @@ -2252,13 +2253,13 @@ asmlinkage long sys32_execve(char *name, } 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; }