From: Arnd Bergmann <arnd@arndb.de>
To: linux-arch@vger.kernel.org
Subject: [PATCH 2/4] Consolidate do_execve32
Date: Sun, 4 Apr 2004 02:22:35 +0200 [thread overview]
Message-ID: <200404040222.35467.arnd@arndb.de> (raw)
In-Reply-To: <200404040204.03594.arnd@arndb.de>
The code for sys32_execve/do_execve32 in most of the seven versions
was copied from fs/exec.c but not kept up-to-date. The new
compat_do_execve() function is based on the mips code and has been
resync'ed with do_execve().
IA64 has some special fixup code in sys32_execve, so I'm not touching
that.
Tested with LTP and more 32 bit binaries on x86_64, which previously
used an implementation derived from ia64. The consolidated version
is larger than that but should perform better.
===== arch/mips/kernel/linux32.c 1.23 vs edited =====
--- 1.23/arch/mips/kernel/linux32.c Sat Apr 3 21:51:49 2004
+++ edited/arch/mips/kernel/linux32.c Sat Apr 3 21:20:39 2004
@@ -142,228 +142,6 @@
}
/*
- * count32() counts the number of arguments/envelopes
- */
-static int count32(u32 * argv, int max)
-{
- int i = 0;
-
- if (argv != NULL) {
- for (;;) {
- u32 p; int error;
-
- error = get_user(p,argv);
- if (error)
- return error;
- if (!p)
- break;
- argv++;
- if (++i > max)
- return -E2BIG;
- }
- }
- return i;
-}
-
-
-/*
- * 'copy_strings32()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- */
-int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
-{
- struct page *kmapped_page = NULL;
- char *kaddr = NULL;
- int ret;
-
- while (argc-- > 0) {
- u32 str;
- int len;
- unsigned long pos;
-
- if (get_user(str, argv+argc) || !str ||
- !(len = strnlen_user((char *)A(str), bprm->p))) {
- ret = -EFAULT;
- goto out;
- }
-
- if (bprm->p < len) {
- ret = -E2BIG;
- goto out;
- }
-
- bprm->p -= len;
- /* XXX: add architecture specific overflow check here. */
-
- pos = bprm->p;
- while (len > 0) {
- int i, new, err;
- int offset, bytes_to_copy;
- struct page *page;
-
- offset = pos % PAGE_SIZE;
- i = pos/PAGE_SIZE;
- page = bprm->page[i];
- new = 0;
- if (!page) {
- page = alloc_page(GFP_HIGHUSER);
- bprm->page[i] = page;
- if (!page) {
- ret = -ENOMEM;
- goto out;
- }
- new = 1;
- }
-
- if (page != kmapped_page) {
- if (kmapped_page)
- kunmap(kmapped_page);
- kmapped_page = page;
- kaddr = kmap(kmapped_page);
- }
- if (new && offset)
- memset(kaddr, 0, offset);
- bytes_to_copy = PAGE_SIZE - offset;
- if (bytes_to_copy > len) {
- bytes_to_copy = len;
- if (new)
- memset(kaddr+offset+len, 0,
- PAGE_SIZE-offset-len);
- }
- err = copy_from_user(kaddr + offset, (char *)A(str),
- bytes_to_copy);
- if (err) {
- ret = -EFAULT;
- goto out;
- }
-
- pos += bytes_to_copy;
- str += bytes_to_copy;
- len -= bytes_to_copy;
- }
- }
- ret = 0;
-out:
- if (kmapped_page)
- kunmap(kmapped_page);
- return ret;
-}
-
-#ifdef CONFIG_MMU
-
-#define free_arg_pages(bprm) do { } while (0)
-
-#else
-
-static inline void free_arg_pages(struct linux_binprm *bprm)
-{
- int i;
-
- for (i = 0; i < MAX_ARG_PAGES; i++) {
- if (bprm->page[i])
- __free_page(bprm->page[i]);
- bprm->page[i] = NULL;
- }
-}
-
-#endif /* CONFIG_MMU */
-
-/*
- * sys32_execve() executes a new program.
- */
-static inline int
-do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
-{
- struct linux_binprm bprm;
- struct file * file;
- int retval;
-
- sched_balance_exec();
-
- file = open_exec(filename);
-
- retval = PTR_ERR(file);
- if (IS_ERR(file))
- return retval;
-
- bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
- memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
-
- bprm.file = file;
- bprm.filename = filename;
- bprm.interp = filename;
- bprm.sh_bang = 0;
- bprm.loader = 0;
- bprm.exec = 0;
- bprm.security = NULL;
- bprm.mm = mm_alloc();
- retval = -ENOMEM;
- if (!bprm.mm)
- goto out_file;
-
- retval = init_new_context(current, bprm.mm);
- if (retval < 0)
- goto out_mm;
-
- bprm.argc = count32(argv, bprm.p / sizeof(u32));
- if ((retval = bprm.argc) < 0)
- goto out_mm;
-
- bprm.envc = count32(envp, bprm.p / sizeof(u32));
- if ((retval = bprm.envc) < 0)
- goto out_mm;
-
- retval = security_bprm_alloc(&bprm);
- if (retval)
- goto out;
-
- retval = prepare_binprm(&bprm);
- if (retval < 0)
- goto out;
-
- retval = copy_strings_kernel(1, &bprm.filename, &bprm);
- if (retval < 0)
- goto out;
-
- bprm.exec = bprm.p;
- retval = copy_strings32(bprm.envc, envp, &bprm);
- if (retval < 0)
- goto out;
-
- retval = copy_strings32(bprm.argc, argv, &bprm);
- if (retval < 0)
- goto out;
-
- retval = search_binary_handler(&bprm, regs);
- if (retval >= 0) {
- free_arg_pages(&bprm);
-
- /* execve success */
- security_bprm_free(&bprm);
- return retval;
- }
-
-out:
- /* Something went wrong, return the inode and free the argument pages*/
- free_arg_pages(&bprm);
-
- if (bprm.security)
- security_bprm_free(&bprm);
-
-out_mm:
- if (bprm.mm)
- mmdrop(bprm.mm);
-
-out_file:
- if (bprm.file) {
- allow_write_access(bprm.file);
- fput(bprm.file);
- }
- return retval;
-}
-
-/*
* sys_execve() executes a new program.
*/
asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs)
@@ -371,12 +149,12 @@
int error;
char * filename;
- filename = getname((char *) (long)regs.regs[4]);
+ filename = getname(compat_ptr(regs.regs[4]));
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve32(filename, (u32 *) (long)regs.regs[5],
- (u32 *) (long)regs.regs[6], ®s);
+ error = compat_do_execve(filename, compat_ptr(regs.regs[5]),
+ compat_ptr(regs.regs[6]), ®s);
putname(filename);
out:
===== arch/parisc/kernel/sys_parisc32.c 1.25 vs edited =====
--- 1.25/arch/parisc/kernel/sys_parisc32.c Sat Apr 3 21:51:49 2004
+++ edited/arch/parisc/kernel/sys_parisc32.c Sat Apr 3 21:16:03 2004
@@ -65,189 +65,6 @@
#endif
/*
- * count32() counts the number of arguments/envelopes. It is basically
- * a copy of count() from fs/exec.c, except that it works
- * with 32 bit argv and envp pointers.
- */
-
-static int count32(u32 *argv, int max)
-{
- int i = 0;
-
- if (argv != NULL) {
- for (;;) {
- u32 p;
- int error;
-
- error = get_user(p,argv);
- if (error)
- return error;
- if (!p)
- break;
- argv++;
- if(++i > max)
- return -E2BIG;
- }
- }
- return i;
-}
-
-
-/*
- * copy_strings32() is basically a copy of copy_strings() from fs/exec.c
- * except that it works with 32 bit argv and envp pointers.
- */
-
-
-static int copy_strings32(int argc, u32 *argv, struct linux_binprm *bprm)
-{
- while (argc-- > 0) {
- u32 str;
- int len;
- unsigned long pos;
-
- if (get_user(str, argv + argc) ||
- !str ||
- !(len = strnlen_user((char *)compat_ptr(str), bprm->p)))
- return -EFAULT;
-
- if (bprm->p < len)
- return -E2BIG;
-
- bprm->p -= len;
-
- pos = bprm->p;
- while (len > 0) {
- char *kaddr;
- int i, new, err;
- struct page *page;
- int offset, bytes_to_copy;
-
- offset = pos % PAGE_SIZE;
- i = pos/PAGE_SIZE;
- page = bprm->page[i];
- new = 0;
- if (!page) {
- page = alloc_page(GFP_HIGHUSER);
- bprm->page[i] = page;
- if (!page)
- return -ENOMEM;
- new = 1;
- }
- kaddr = (char *)kmap(page);
-
- if (new && offset)
- memset(kaddr, 0, offset);
- bytes_to_copy = PAGE_SIZE - offset;
- if (bytes_to_copy > len) {
- bytes_to_copy = len;
- if (new)
- memset(kaddr+offset+len, 0, PAGE_SIZE-offset-len);
- }
- err = copy_from_user(kaddr + offset, (char *)compat_ptr(str), bytes_to_copy);
- flush_dcache_page(page);
- kunmap(page);
-
- if (err)
- return -EFAULT;
-
- pos += bytes_to_copy;
- str += bytes_to_copy;
- len -= bytes_to_copy;
- }
- }
- return 0;
-}
-
-/*
- * do_execve32() is mostly a copy of do_execve(), with the exception
- * that it processes 32 bit argv and envp pointers.
- */
-
-static inline int
-do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
-{
- struct linux_binprm bprm;
- struct file *file;
- int retval;
- int i;
-
- file = open_exec(filename);
-
- retval = PTR_ERR(file);
- if (IS_ERR(file))
- return retval;
-
- bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
- memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
-
- DBG(("do_execve32(%s, %p, %p, %p)\n", filename, argv, envp, regs));
-
- bprm.file = file;
- bprm.filename = filename;
- bprm.interp = filename;
- bprm.sh_bang = 0;
- bprm.loader = 0;
- bprm.exec = 0;
-
- bprm.mm = mm_alloc();
- retval = -ENOMEM;
- if (!bprm.mm)
- goto out_file;
-
- retval = init_new_context(current, bprm.mm);
- if (retval < 0)
- goto out_mm;
-
- if ((bprm.argc = count32(argv, bprm.p / sizeof(u32))) < 0)
- goto out_mm;
-
- if ((bprm.envc = count32(envp, bprm.p / sizeof(u32))) < 0)
- goto out_mm;
-
- retval = prepare_binprm(&bprm);
- if (retval < 0)
- goto out;
-
- retval = copy_strings_kernel(1, &bprm.filename, &bprm);
- if (retval < 0)
- goto out;
-
- bprm.exec = bprm.p;
- retval = copy_strings32(bprm.envc, envp, &bprm);
- if (retval < 0)
- goto out;
-
- retval = copy_strings32(bprm.argc, argv, &bprm);
- if (retval < 0)
- goto out;
-
- retval = search_binary_handler(&bprm,regs);
- if (retval >= 0)
- /* execve success */
- return retval;
-
-out:
- /* Something went wrong, return the inode and free the argument pages*/
- for (i = 0; i < MAX_ARG_PAGES; i++) {
- struct page *page = bprm.page[i];
- if (page)
- __free_page(page);
- }
-
-out_mm:
- mmdrop(bprm.mm);
-
-out_file:
- if (bprm.file) {
- allow_write_access(bprm.file);
- fput(bprm.file);
- }
-
- return retval;
-}
-
-/*
* sys32_execve() executes a new program.
*/
@@ -261,8 +78,8 @@
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve32(filename, (u32 *) regs->gr[25],
- (u32 *) regs->gr[24], regs);
+ error = compat_do_execve(filename, compat_ptr(regs->gr[25]),
+ compat_ptr(regs->gr[24]), regs);
if (error == 0)
current->ptrace &= ~PT_DTRACE;
putname(filename);
===== arch/ppc64/kernel/sys_ppc32.c 1.87 vs edited =====
--- 1.87/arch/ppc64/kernel/sys_ppc32.c Sat Apr 3 21:51:49 2004
+++ edited/arch/ppc64/kernel/sys_ppc32.c Sat Apr 3 21:16:41 2004
@@ -1549,191 +1549,6 @@
return ret;
}
-/*
- * count32() counts the number of arguments/envelopes
- */
-static int count32(u32 * argv, int max)
-{
- int i = 0;
-
- if (argv != NULL) {
- for (;;) {
- u32 p; int error;
-
- error = get_user(p,argv);
- if (error)
- return error;
- if (!p)
- break;
- argv++;
- if (++i > max)
- return -E2BIG;
- }
- }
- return i;
-}
-
-/*
- * 'copy_string32()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- */
-static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
-{
- while (argc-- > 0) {
- u32 str;
- int len;
- unsigned long pos;
-
- if (get_user(str, argv + argc) ||
- !str ||
- !(len = strnlen_user((char *)A(str), bprm->p)))
- return -EFAULT;
-
- if (bprm->p < len)
- return -E2BIG;
-
- bprm->p -= len;
-
- pos = bprm->p;
- while (len) {
- char *kaddr;
- struct page *page;
- int offset, bytes_to_copy, new, err;
-
- offset = pos % PAGE_SIZE;
- page = bprm->page[pos / PAGE_SIZE];
- new = 0;
- if (!page) {
- page = alloc_page(GFP_USER);
- bprm->page[pos / PAGE_SIZE] = page;
- if (!page)
- return -ENOMEM;
- new = 1;
- }
- kaddr = (char *)kmap(page);
-
- if (new && offset)
- memset(kaddr, 0, offset);
- bytes_to_copy = PAGE_SIZE - offset;
- if (bytes_to_copy > len) {
- bytes_to_copy = len;
- if (new)
- memset(kaddr+offset+len, 0,
- PAGE_SIZE-offset-len);
- }
-
- err = copy_from_user(kaddr + offset, (char *)A(str),
- bytes_to_copy);
- kunmap((unsigned long)kaddr);
-
- if (err)
- return -EFAULT;
-
- pos += bytes_to_copy;
- str += bytes_to_copy;
- len -= bytes_to_copy;
- }
- }
- return 0;
-}
-
-/*
- * sys32_execve() executes a new program.
- */
-static int do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
-{
- struct linux_binprm bprm;
- struct file * file;
- int retval;
- int i;
-
- sched_balance_exec();
-
- file = open_exec(filename);
-
- retval = PTR_ERR(file);
- if (IS_ERR(file))
- return retval;
-
- bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
- memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
-
- bprm.file = file;
- bprm.filename = filename;
- bprm.interp = filename;
- bprm.sh_bang = 0;
- bprm.loader = 0;
- bprm.exec = 0;
- bprm.security = NULL;
- bprm.mm = mm_alloc();
- retval = -ENOMEM;
- if (!bprm.mm)
- goto out_file;
-
- retval = init_new_context(current, bprm.mm);
- if (retval < 0)
- goto out_mm;
-
- bprm.argc = count32(argv, bprm.p / sizeof(u32));
- if ((retval = bprm.argc) < 0)
- goto out_mm;
-
- bprm.envc = count32(envp, bprm.p / sizeof(u32));
- if ((retval = bprm.envc) < 0)
- goto out_mm;
-
- retval = security_bprm_alloc(&bprm);
- if (retval)
- goto out;
-
- retval = prepare_binprm(&bprm);
- if (retval < 0)
- goto out;
-
- retval = copy_strings_kernel(1, &bprm.filename, &bprm);
- if (retval < 0)
- goto out;
-
- bprm.exec = bprm.p;
- retval = copy_strings32(bprm.envc, envp, &bprm);
- if (retval < 0)
- goto out;
-
- retval = copy_strings32(bprm.argc, argv, &bprm);
- if (retval < 0)
- goto out;
-
- retval = search_binary_handler(&bprm,regs);
- if (retval >= 0) {
- /* execve success */
- security_bprm_free(&bprm);
- return retval;
- }
-
-out:
- /* Something went wrong, return the inode and free the argument pages*/
- for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
- struct page * page = bprm.page[i];
- if (page)
- __free_page(page);
- }
-
- if (bprm.security)
- security_bprm_free(&bprm);
-
-out_mm:
- if (bprm.mm)
- mmdrop(bprm.mm);
-
-out_file:
- if (bprm.file) {
- allow_write_access(bprm.file);
- fput(bprm.file);
- }
- return retval;
-}
-
long sys32_execve(unsigned long a0, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4, unsigned long a5,
struct pt_regs *regs)
@@ -1752,7 +1567,7 @@
giveup_altivec(current);
#endif /* CONFIG_ALTIVEC */
- error = do_execve32(filename, (u32*) a1, (u32*) a2, regs);
+ error = compat_do_execve(filename, compat_ptr(a1), compat_ptr(a2), regs);
if (error == 0)
current->ptrace &= ~PT_DTRACE;
===== arch/s390/kernel/compat_linux.c 1.20 vs edited =====
--- 1.20/arch/s390/kernel/compat_linux.c Sat Apr 3 21:51:49 2004
+++ edited/arch/s390/kernel/compat_linux.c Sat Apr 3 21:17:59 2004
@@ -906,188 +906,6 @@
return ret;
}
-extern void check_pending(int signum);
-
-/*
- * count32() counts the number of arguments/envelopes
- */
-static int count32(u32 * argv)
-{
- int i = 0;
-
- if (argv != NULL) {
- for (;;) {
- u32 p; int error;
-
- error = get_user(p,argv);
- if (error) return error;
- if (!p) break;
- argv++; i++;
- }
- }
- return i;
-}
-
-/*
- * 'copy_string32()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- */
-static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
-{
- while (argc-- > 0) {
- u32 str;
- int len;
- unsigned long pos;
-
- if (get_user(str, argv + argc) ||
- !str ||
- !(len = strnlen_user((char *)A(str), bprm->p)))
- return -EFAULT;
-
- if (bprm->p < len)
- return -E2BIG;
-
- bprm->p -= len;
-
- pos = bprm->p;
- while (len) {
- char *kaddr;
- struct page *page;
- int offset, bytes_to_copy, new, err;
-
- offset = pos % PAGE_SIZE;
- page = bprm->page[pos / PAGE_SIZE];
- new = 0;
- if (!page) {
- page = alloc_page(GFP_USER);
- bprm->page[pos / PAGE_SIZE] = page;
- if (!page)
- return -ENOMEM;
- new = 1;
- }
- kaddr = (char *)kmap(page);
-
- if (new && offset)
- memset(kaddr, 0, offset);
- bytes_to_copy = PAGE_SIZE - offset;
- if (bytes_to_copy > len) {
- bytes_to_copy = len;
- if (new)
- memset(kaddr+offset+len, 0,
- PAGE_SIZE-offset-len);
- }
-
- err = copy_from_user(kaddr + offset, (char *)A(str),
- bytes_to_copy);
- kunmap(page);
-
- if (err)
- return -EFAULT;
-
- pos += bytes_to_copy;
- str += bytes_to_copy;
- len -= bytes_to_copy;
- }
- }
- return 0;
-}
-
-/*
- * sys32_execve() executes a new program.
- */
-static inline int
-do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
-{
- struct linux_binprm bprm;
- struct file * file;
- int retval;
- int i;
-
- sched_balance_exec();
-
- file = open_exec(filename);
-
- retval = PTR_ERR(file);
- if (IS_ERR(file))
- return retval;
-
- bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
- memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
-
- bprm.file = file;
- bprm.filename = filename;
- bprm.interp = filename;
- bprm.sh_bang = 0;
- bprm.loader = 0;
- bprm.exec = 0;
- bprm.mm = mm_alloc();
- retval = -ENOMEM;
- if (!bprm.mm)
- goto out_file;
-
- /* init_new_context is empty for s390x. */
-
- bprm.argc = count32(argv);
- if ((retval = bprm.argc) < 0)
- goto out_mm;
-
- bprm.envc = count32(envp);
- if ((retval = bprm.envc) < 0)
- goto out_mm;
-
- retval = security_bprm_alloc(&bprm);
- if (retval)
- goto out;
-
- retval = prepare_binprm(&bprm);
- if (retval < 0)
- goto out;
-
- retval = copy_strings_kernel(1, &bprm.filename, &bprm);
- if (retval < 0)
- goto out;
-
- bprm.exec = bprm.p;
- retval = copy_strings32(bprm.envc, envp, &bprm);
- if (retval < 0)
- goto out;
-
- retval = copy_strings32(bprm.argc, argv, &bprm);
- if (retval < 0)
- goto out;
-
- retval = search_binary_handler(&bprm, regs);
- if (retval >= 0) {
- /* execve success */
- security_bprm_free(&bprm);
- return retval;
- }
-
-out:
- /* Something went wrong, return the inode and free the argument pages*/
- for (i=0 ; i<MAX_ARG_PAGES ; i++) {
- struct page * page = bprm.page[i];
- if (page)
- __free_page(page);
- }
-
- if (bprm.security)
- security_bprm_free(&bprm);
-
-out_mm:
- if (bprm.mm)
- mmdrop(bprm.mm);
-
-out_file:
- if (bprm.file) {
- allow_write_access(bprm.file);
- fput(bprm.file);
- }
-
- return retval;
-}
-
/*
* sys32_execve() executes a new program after the asm stub has set
* things up for us. This should basically do what I want it to.
@@ -1098,11 +916,12 @@
int error;
char * filename;
- filename = getname((char *)A(regs.orig_gpr2));
+ filename = getname(compat_ptr(regs.orig_gpr2));
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve32(filename, (u32 *)A(regs.gprs[3]), (u32 *)A(regs.gprs[4]), ®s);
+ error = compat_do_execve(filename, compat_ptr(regs.gprs[3]),
+ compat_ptr(regs.gprs[4]), ®s);
if (error == 0)
{
current->ptrace &= ~PT_DTRACE;
===== arch/sparc64/kernel/sys_sparc32.c 1.96 vs edited =====
--- 1.96/arch/sparc64/kernel/sys_sparc32.c Sat Apr 3 21:51:49 2004
+++ edited/arch/sparc64/kernel/sys_sparc32.c Sat Apr 3 21:19:17 2004
@@ -1386,8 +1386,6 @@
return ret;
}
-extern void check_pending(int signum);
-
asmlinkage int sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact)
{
struct k_sigaction new_ka, old_ka;
@@ -1483,193 +1481,6 @@
return ret;
}
-
-/*
- * count32() counts the number of arguments/envelopes
- */
-static int count32(u32 * argv, int max)
-{
- int i = 0;
-
- if (argv != NULL) {
- for (;;) {
- u32 p; int error;
-
- error = get_user(p,argv);
- if (error)
- return error;
- if (!p)
- break;
- argv++;
- if (++i > max)
- return -E2BIG;
- }
- }
- return i;
-}
-
-/*
- * 'copy_string32()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- */
-static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
-{
- while (argc-- > 0) {
- u32 str;
- int len;
- unsigned long pos;
-
- if (get_user(str, argv + argc) ||
- !str ||
- !(len = strnlen_user((char *)A(str), bprm->p)))
- return -EFAULT;
-
- if (bprm->p < len)
- return -E2BIG;
-
- bprm->p -= len;
-
- pos = bprm->p;
- while (len) {
- char *kaddr;
- struct page *page;
- int offset, bytes_to_copy, new, err;
-
- offset = pos % PAGE_SIZE;
- page = bprm->page[pos / PAGE_SIZE];
- new = 0;
- if (!page) {
- page = alloc_page(GFP_USER);
- bprm->page[pos / PAGE_SIZE] = page;
- if (!page)
- return -ENOMEM;
- new = 1;
- }
- kaddr = kmap(page);
-
- if (new && offset)
- memset(kaddr, 0, offset);
- bytes_to_copy = PAGE_SIZE - offset;
- if (bytes_to_copy > len) {
- bytes_to_copy = len;
- if (new)
- memset(kaddr+offset+len, 0,
- PAGE_SIZE-offset-len);
- }
-
- err = copy_from_user(kaddr + offset, (char *)A(str),
- bytes_to_copy);
- kunmap(page);
-
- if (err)
- return -EFAULT;
-
- pos += bytes_to_copy;
- str += bytes_to_copy;
- len -= bytes_to_copy;
- }
- }
- return 0;
-}
-
-/*
- * sys32_execve() executes a new program.
- */
-static inline int
-do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
-{
- struct linux_binprm bprm;
- struct file * file;
- int retval;
- int i;
-
- sched_balance_exec();
-
- file = open_exec(filename);
-
- retval = PTR_ERR(file);
- if (IS_ERR(file))
- return retval;
-
- bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
- memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
-
- bprm.file = file;
- bprm.filename = filename;
- bprm.interp = filename;
- bprm.sh_bang = 0;
- bprm.loader = 0;
- bprm.exec = 0;
- bprm.security = NULL;
- bprm.mm = mm_alloc();
- retval = -ENOMEM;
- if (!bprm.mm)
- goto out_file;
-
- retval = init_new_context(current, bprm.mm);
- if (retval < 0)
- goto out_mm;
-
- bprm.argc = count32(argv, bprm.p / sizeof(u32));
- if ((retval = bprm.argc) < 0)
- goto out_mm;
-
- bprm.envc = count32(envp, bprm.p / sizeof(u32));
- if ((retval = bprm.envc) < 0)
- goto out_mm;
-
- retval = security_bprm_alloc(&bprm);
- if (retval)
- goto out;
-
- retval = prepare_binprm(&bprm);
- if (retval < 0)
- goto out;
-
- retval = copy_strings_kernel(1, &bprm.filename, &bprm);
- if (retval < 0)
- goto out;
-
- bprm.exec = bprm.p;
- retval = copy_strings32(bprm.envc, envp, &bprm);
- if (retval < 0)
- goto out;
-
- retval = copy_strings32(bprm.argc, argv, &bprm);
- if (retval < 0)
- goto out;
-
- retval = search_binary_handler(&bprm, regs);
- if (retval >= 0) {
- /* execve success */
- security_bprm_free(&bprm);
- return retval;
- }
-
-out:
- /* Something went wrong, return the inode and free the argument pages*/
- for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
- struct page * page = bprm.page[i];
- if (page)
- __free_page(page);
- }
-
- if (bprm.security)
- security_bprm_free(&bprm);
-
-out_mm:
- if (bprm.mm)
- mmdrop(bprm.mm);
-
-out_file:
- if (bprm.file) {
- allow_write_access(bprm.file);
- fput(bprm.file);
- }
- return retval;
-}
-
/*
* sparc32_execve() executes a new program after the asm stub has set
* things up for us. This should basically do what I want it to.
@@ -1689,9 +1500,9 @@
error = PTR_ERR(filename);
if(IS_ERR(filename))
goto out;
- error = do_execve32(filename,
- (u32 *)AA((u32)regs->u_regs[base + UREG_I1]),
- (u32 *)AA((u32)regs->u_regs[base + UREG_I2]), regs);
+ error = compat_do_execve(filename,
+ compat_ptr((u32)regs->u_regs[base + UREG_I1]),
+ compat_ptr((u32)regs->u_regs[base + UREG_I2]), regs);
putname(filename);
if(!error) {
===== arch/x86_64/ia32/sys_ia32.c 1.57 vs edited =====
--- 1.57/arch/x86_64/ia32/sys_ia32.c Sat Apr 3 21:51:49 2004
+++ edited/arch/x86_64/ia32/sys_ia32.c Sat Apr 3 20:53:02 2004
@@ -1224,93 +1224,22 @@
return ret;
}
-static int nargs(u32 src, char **dst)
-{
- int cnt;
- u32 val;
-
- cnt = 0;
- do {
- int ret = get_user(val, (__u32 *)(u64)src);
- if (ret)
- return ret;
- if (dst)
- dst[cnt] = (char *)(u64)val;
- cnt++;
- src += 4;
- if (cnt >= (MAX_ARG_PAGES*PAGE_SIZE)/sizeof(void*))
- return -E2BIG;
- } while(val);
- if (dst)
- dst[cnt-1] = 0;
- return cnt;
-}
-
-asmlinkage long sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
-{
- mm_segment_t oldseg;
- char **buf = NULL;
- int na = 0,ne = 0;
- int ret;
- unsigned sz = 0;
-
- if (argv) {
- na = nargs(argv, NULL);
- if (na < 0)
- return -EFAULT;
- }
- if (envp) {
- ne = nargs(envp, NULL);
- if (ne < 0)
- return -EFAULT;
- }
-
- if (argv || envp) {
- sz = (na+ne)*sizeof(void *);
- if (sz > PAGE_SIZE)
- buf = vmalloc(sz);
- else
- buf = kmalloc(sz, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- }
-
- if (argv) {
- ret = nargs(argv, buf);
- if (ret < 0)
- goto free;
- }
-
- if (envp) {
- ret = nargs(envp, buf + na);
- if (ret < 0)
- goto free;
- }
-
- name = getname(name);
- ret = PTR_ERR(name);
- if (IS_ERR(name))
- goto free;
-
- oldseg = get_fs();
- set_fs(KERNEL_DS);
- ret = do_execve(name, argv ? buf : NULL, envp ? buf+na : NULL, ®s);
- set_fs(oldseg);
-
- if (ret == 0)
+asmlinkage long sys32_execve(char *name, compat_uptr_t __user *argv,
+ compat_uptr_t __user *envp, struct pt_regs regs)
+{
+ long error;
+ char * filename;
+
+ filename = getname(name);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
+ return error;
+ error = compat_do_execve(filename, argv, envp, ®s);
+ if (error == 0)
current->ptrace &= ~PT_DTRACE;
-
- putname(name);
-
-free:
- if (argv || envp) {
- if (sz > PAGE_SIZE)
- vfree(buf);
- else
- kfree(buf);
- }
- return ret;
-}
+ putname(filename);
+ return error;
+}
asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
{
===== fs/compat.c 1.23 vs edited =====
--- 1.23/fs/compat.c Sat Apr 3 21:51:49 2004
+++ edited/fs/compat.c Sat Apr 3 21:01:36 2004
@@ -980,3 +980,236 @@
fput(file);
return ret;
}
+
+#ifndef __ia64__ /* ia64 needs some extra tweaks */
+/*
+ * compat_count() counts the number of arguments/envelopes. It is basically
+ * a copy of count() from fs/exec.c, except that it works with 32 bit argv
+ * and envp pointers.
+ */
+static int compat_count(compat_uptr_t *argv, int max)
+{
+ int i = 0;
+
+ if (argv != NULL) {
+ for (;;) {
+ compat_uptr_t p;
+
+ if (get_user(p, argv))
+ return -EFAULT;
+ if (!p)
+ break;
+ argv++;
+ if(++i > max)
+ return -E2BIG;
+ }
+ }
+ return i;
+}
+
+/*
+ * compat_copy_strings() is basically a copy of copy_strings() from fs/exec.c
+ * except that it works with 32 bit argv and envp pointers.
+ */
+static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
+ struct linux_binprm *bprm)
+{
+ struct page *kmapped_page = NULL;
+ char *kaddr = NULL;
+ int ret;
+
+ while (argc-- > 0) {
+ compat_uptr_t str;
+ int len;
+ unsigned long pos;
+
+ if (get_user(str, argv+argc) ||
+ !(len = strnlen_user(compat_ptr(str), bprm->p))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (bprm->p < len) {
+ ret = -E2BIG;
+ goto out;
+ }
+
+ bprm->p -= len;
+ /* XXX: add architecture specific overflow check here. */
+ pos = bprm->p;
+
+ while (len > 0) {
+ int i, new, err;
+ int offset, bytes_to_copy;
+ struct page *page;
+
+ offset = pos % PAGE_SIZE;
+ i = pos/PAGE_SIZE;
+ page = bprm->page[i];
+ new = 0;
+ if (!page) {
+ page = alloc_page(GFP_HIGHUSER);
+ bprm->page[i] = page;
+ if (!page) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ new = 1;
+ }
+
+ if (page != kmapped_page) {
+ if (kmapped_page)
+ kunmap(kmapped_page);
+ kmapped_page = page;
+ kaddr = kmap(kmapped_page);
+ }
+ if (new && offset)
+ memset(kaddr, 0, offset);
+ bytes_to_copy = PAGE_SIZE - offset;
+ if (bytes_to_copy > len) {
+ bytes_to_copy = len;
+ if (new)
+ memset(kaddr+offset+len, 0,
+ PAGE_SIZE-offset-len);
+ }
+ err = copy_from_user(kaddr+offset, compat_ptr(str),
+ bytes_to_copy);
+ if (err) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ pos += bytes_to_copy;
+ str += bytes_to_copy;
+ len -= bytes_to_copy;
+ }
+ }
+ ret = 0;
+out:
+ if (kmapped_page)
+ kunmap(kmapped_page);
+ return ret;
+}
+
+#ifdef CONFIG_MMU
+
+#define free_arg_pages(bprm) do { } while (0)
+
+#else
+
+static inline void free_arg_pages(struct linux_binprm *bprm)
+{
+ int i;
+
+ for (i = 0; i < MAX_ARG_PAGES; i++) {
+ if (bprm->page[i])
+ __free_page(bprm->page[i]);
+ bprm->page[i] = NULL;
+ }
+}
+
+#endif /* CONFIG_MMU */
+
+/*
+ * compat_do_execve() is mostly a copy of do_execve(), with the exception
+ * that it processes 32 bit argv and envp pointers.
+ */
+int compat_do_execve(char * filename,
+ compat_uptr_t __user *argv,
+ compat_uptr_t __user *envp,
+ struct pt_regs * regs)
+{
+ struct linux_binprm bprm;
+ struct file *file;
+ int retval;
+ int i;
+
+ sched_balance_exec();
+
+ file = open_exec(filename);
+
+ retval = PTR_ERR(file);
+ if (IS_ERR(file))
+ return retval;
+
+ bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+ memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
+
+ bprm.file = file;
+ bprm.filename = filename;
+ bprm.interp = filename;
+ bprm.sh_bang = 0;
+ bprm.loader = 0;
+ bprm.exec = 0;
+ bprm.security = NULL;
+ bprm.mm = mm_alloc();
+ retval = -ENOMEM;
+ if (!bprm.mm)
+ goto out_file;
+
+ retval = init_new_context(current, bprm.mm);
+ if (retval < 0)
+ goto out_mm;
+
+ bprm.argc = compat_count(argv, bprm.p / sizeof(compat_uptr_t));
+ if ((retval = bprm.argc) < 0)
+ goto out_mm;
+
+ bprm.envc = compat_count(envp, bprm.p / sizeof(compat_uptr_t));
+ if ((retval = bprm.envc) < 0)
+ goto out_mm;
+
+ retval = security_bprm_alloc(&bprm);
+ if (retval)
+ goto out;
+
+ retval = prepare_binprm(&bprm);
+ if (retval < 0)
+ goto out;
+
+ retval = copy_strings_kernel(1, &bprm.filename, &bprm);
+ if (retval < 0)
+ goto out;
+
+ bprm.exec = bprm.p;
+ retval = compat_copy_strings(bprm.envc, envp, &bprm);
+ if (retval < 0)
+ goto out;
+
+ retval = compat_copy_strings(bprm.argc, argv, &bprm);
+ if (retval < 0)
+ goto out;
+
+ retval = search_binary_handler(&bprm,regs);
+ if (retval >= 0) {
+ free_arg_pages(&bprm);
+
+ /* execve success */
+ security_bprm_free(&bprm);
+ return retval;
+ }
+
+out:
+ /* Something went wrong, return the inode and free the argument pages*/
+ for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+ struct page * page = bprm.page[i];
+ if (page)
+ __free_page(page);
+ }
+
+ if (bprm.security)
+ security_bprm_free(&bprm);
+
+out_mm:
+ if (bprm.mm)
+ mmdrop(bprm.mm);
+
+out_file:
+ if (bprm.file) {
+ allow_write_access(bprm.file);
+ fput(bprm.file);
+ }
+
+ return retval;
+}
+#endif /* !__ia64__ */
===== include/linux/compat.h 1.20 vs edited =====
--- 1.20/include/linux/compat.h Sat Apr 3 22:03:56 2004
+++ edited/include/linux/compat.h Sat Apr 3 20:43:52 2004
@@ -106,5 +106,8 @@
asmlinkage ssize_t compat_sys_writev(unsigned long fd,
const struct compat_iovec __user *vec, unsigned long vlen);
+int compat_do_execve(char * filename, compat_uptr_t __user *argv,
+ compat_uptr_t __user *envp, struct pt_regs * regs);
+
#endif /* CONFIG_COMPAT */
#endif /* _LINUX_COMPAT_H */
next prev parent reply other threads:[~2004-04-04 0:35 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <200404040204.03594.arnd@arndb.de>
2004-04-04 0:22 ` [PATCH 1/4] Consolidate sys32_readv and sys32_writev Arnd Bergmann
2004-04-04 0:22 ` Arnd Bergmann [this message]
2004-04-13 18:45 ` [PATCH 2/4] Consolidate do_execve32 Arun Sharma
2004-04-04 0:22 ` [PATCH 3/4] Consolidate sys32_select Arnd Bergmann
2004-04-04 10:24 ` Andi Kleen
2004-04-04 10:36 ` Arnd Bergmann
2004-04-04 11:04 ` Andi Kleen
2004-04-04 11:07 ` William Lee Irwin III
2004-04-04 22:51 ` Arnd Bergmann
2004-04-04 23:35 ` Andi Kleen
2004-04-04 23:41 ` Arnd Bergmann
2004-04-07 20:46 ` Arun Sharma
2004-04-08 8:22 ` Arnd Bergmann
2004-04-12 18:55 ` Arun Sharma
2004-04-04 0:22 ` [PATCH 4/4] Consolidate sys32_nfsservctl Arnd Bergmann
2004-04-16 16:00 consolidate compat readv/writev/execve/select/nfsservctl [v2] Arnd Bergmann
2004-04-16 16:04 ` [PATCH 2/4] Consolidate do_execve32 Arnd Bergmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200404040222.35467.arnd@arndb.de \
--to=arnd@arndb.de \
--cc=linux-arch@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.