From 788e4ffb5c4d6e4a32d147f30d2601d0d34281a3 Mon Sep 17 00:00:00 2001 From: Kanoj Sarcar Date: Tue, 29 Feb 2000 22:13:07 +0000 Subject: Get some code in to make sure that 32 bit execs do not fail. This does not mean they work yet. --- arch/mips64/kernel/linux32.c | 67 +++++++++++++++++++++++++++++++++++++++++- arch/mips64/kernel/scall_o32.S | 2 +- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/arch/mips64/kernel/linux32.c b/arch/mips64/kernel/linux32.c index 404d1cf95..69c853437 100644 --- a/arch/mips64/kernel/linux32.c +++ b/arch/mips64/kernel/linux32.c @@ -1,9 +1,10 @@ -/* $Id$ +/* $Id: linux32.c,v 1.4 2000/02/29 20:49:15 ulfc Exp $ * * Conversion between 32-bit and 64-bit native system calls. * * Copyright (C) 2000 Silicon Graphics, Inc. * Written by Ulf Carlsson (ulfc@engr.sgi.com) + * sys32_execve from ia64/ia32 code, Feb 2000, Kanoj Sarcar (kanoj@sgi.com) */ #include @@ -13,6 +14,7 @@ #include #include +#include /* * Revalidate the inode. This is required for proper NFS attribute caching. @@ -170,3 +172,66 @@ asmlinkage int sys_fstat64(unsigned int fd, struct stat *statbuf) { return sys_fstat(fd, statbuf); } + +static int +nargs(unsigned int arg, char **ap) +{ + char *ptr; + int n, err; + + n = 0; + for (; ptr; ) { + if ((err = get_user(ptr, (int *)arg))) + return(err); + if (ap) + *ap++ = ptr; + arg += sizeof(unsigned int); + n++; + } + return(n - 1); +} + +asmlinkage long +sys32_execve(abi64_no_regargs, struct pt_regs regs) +{ + extern asmlinkage int sys_execve(abi64_no_regargs, struct pt_regs regs); + extern asmlinkage long sys_munmap(unsigned long addr, size_t len); + unsigned int argv = (unsigned int)regs.regs[5]; + unsigned int envp = (unsigned int)regs.regs[6]; + char **av, **ae; + int na, ne, r, len; + + na = nargs(argv, NULL); + ne = nargs(envp, NULL); + len = (na + ne + 2) * sizeof(*av); + /* + * kmalloc won't work because the `sys_exec' code will attempt + * to do a `get_user' on the arg list and `get_user' will fail + * on a kernel address (simplifies `get_user'). Instead we + * do an mmap to get a user address. Note that since a successful + * `execve' frees all current memory we only have to do an + * `munmap' if the `execve' failes. + */ + down(¤t->mm->mmap_sem); + lock_kernel(); + + av = do_mmap_pgoff(0, NULL, len, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0); + + unlock_kernel(); + up(¤t->mm->mmap_sem); + + if (IS_ERR(av)) + return(av); + ae = av + na + 1; + av[na] = (char *)0; + ae[ne] = (char *)0; + (void)nargs(argv, av); + (void)nargs(envp, ae); + regs.regs[5] = av; + regs.regs[6] = ae; + r = sys_execve(__dummy0,__dummy0,__dummy0,__dummy0,__dummy0,__dummy0,__dummy0,__dummy0, regs); + if (IS_ERR(r)) + sys_munmap(av, len); + return(r); +} diff --git a/arch/mips64/kernel/scall_o32.S b/arch/mips64/kernel/scall_o32.S index 4ee2cbace..2e6f56ce8 100644 --- a/arch/mips64/kernel/scall_o32.S +++ b/arch/mips64/kernel/scall_o32.S @@ -202,7 +202,7 @@ illegal_syscall: sys sys_creat 2 sys sys_link 2 sys sys_unlink 1 /* 4010 */ - sys sys_execve 0 + sys sys32_execve 0 sys sys_chdir 1 sys sys_time 1 sys sys_mknod 3 -- cgit v1.2.3