--- linux/fs/exec.c.orig Thu Sep 27 08:52:32 2001 +++ linux/fs/exec.c Thu Sep 27 09:33:41 2001 @@ -48,6 +48,12 @@ int core_uses_pid; +/* + * Max exec() argument size in bytes. Kernel aligns + * it to PAGE_SIZE boundary. + */ +int exec_argsize = PAGE_SIZE * 32; + static struct linux_binfmt *formats; static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED; @@ -204,11 +210,11 @@ offset = pos % PAGE_SIZE; i = pos/PAGE_SIZE; - page = bprm->page[i]; + page = bprm->pages[i]; new = 0; if (!page) { page = alloc_page(GFP_HIGHUSER); - bprm->page[i] = page; + bprm->pages[i] = page; if (!page) return -ENOMEM; new = 1; @@ -296,7 +302,7 @@ struct vm_area_struct *mpnt; int i; - stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; + stack_base = STACK_TOP - bprm->nr_pages*PAGE_SIZE; bprm->p += stack_base; if (bprm->loader) @@ -322,10 +328,10 @@ current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; } - for (i = 0 ; i < MAX_ARG_PAGES ; i++) { - struct page *page = bprm->page[i]; + for (i = 0 ; i < bprm->nr_pages ; i++) { + struct page *page = bprm->pages[i]; if (page) { - bprm->page[i] = NULL; + bprm->pages[i] = NULL; put_dirty_page(current,page,stack_base); } stack_base += PAGE_SIZE; @@ -747,7 +753,7 @@ offset = 0; kunmap(page); inside: - page = bprm->page[bprm->p/PAGE_SIZE]; + page = bprm->pages[bprm->p/PAGE_SIZE]; kaddr = kmap(page); } kunmap(page); @@ -778,7 +784,7 @@ fput(bprm->file); bprm->file = NULL; - loader = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); + loader = PAGE_SIZE*bprm->nr_pages-sizeof(void *); file = open_exec(dynloader[0]); retval = PTR_ERR(file); @@ -853,34 +859,38 @@ { struct linux_binprm bprm; struct file *file; + struct page **pages; int retval; - int i; + int i, nr_pages; - file = open_exec(filename); + bprm.file = 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])); + nr_pages = (exec_argsize + PAGE_SIZE-1) / PAGE_SIZE; + pages = kmalloc(sizeof(pages[0]) * nr_pages, GFP_KERNEL); + retval = -ENOMEM; + if (!pages) + goto out; + bprm.p = PAGE_SIZE*nr_pages-sizeof(void *); + memset(pages, 0, nr_pages*sizeof(pages[0])); + bprm.nr_pages = nr_pages; + bprm.pages = pages; bprm.file = file; bprm.filename = filename; bprm.sh_bang = 0; bprm.loader = 0; bprm.exec = 0; - if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) { - allow_write_access(file); - fput(file); - return bprm.argc; - } + retval = bprm.argc = count(argv, bprm.p / sizeof(void *)); + if (retval < 0) + goto out; - if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) { - allow_write_access(file); - fput(file); - return bprm.envc; - } + retval = bprm.envc = count(envp, bprm.p / sizeof(void *)); + if (retval < 0) + goto out; retval = prepare_binprm(&bprm); if (retval < 0) @@ -900,20 +910,29 @@ goto out; retval = search_binary_handler(&bprm,regs); - if (retval >= 0) - /* execve success */ + if (retval >= 0) { + /* + * execve() success + * + * the argument pages now live in the process pagetables, + * but the pages-array must be deallocated. + */ + kfree(pages); return retval; + } out: /* Something went wrong, return the inode and free the argument pages*/ - allow_write_access(bprm.file); - if (bprm.file) - fput(bprm.file); - - for (i = 0 ; i < MAX_ARG_PAGES ; i++) { - struct page * page = bprm.page[i]; - if (page) - __free_page(page); + if (file) { + allow_write_access(file); + fput(file); + } + + if (pages) { + for (i = 0 ; i < nr_pages ; i++) + if (pages[i]) + __free_page(pages[i]); + kfree(pages); } return retval; --- linux/fs/binfmt_elf.c.orig Thu Sep 27 09:12:41 2001 +++ linux/fs/binfmt_elf.c Thu Sep 27 09:15:26 2001 @@ -107,7 +107,8 @@ struct elfhdr * exec, unsigned long load_addr, unsigned long load_bias, - unsigned long interp_load_addr, int ibcs) + unsigned long interp_load_addr, + int ibcs, unsigned int max_argsize) { elf_caddr_t *argv; elf_caddr_t *envp; @@ -198,8 +199,8 @@ current->mm->arg_start = (unsigned long) p; while (argc-->0) { __put_user((elf_caddr_t)(unsigned long)p,argv++); - len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES); - if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) + len = strnlen_user(p, max_argsize); + if (!len || len > max_argsize) return NULL; p += len; } @@ -207,8 +208,8 @@ current->mm->arg_end = current->mm->env_start = (unsigned long) p; while (envc-->0) { __put_user((elf_caddr_t)(unsigned long)p,envp++); - len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES); - if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) + len = strnlen_user(p, max_argsize); + if (!len || len > max_argsize) return NULL; p += len; } @@ -708,7 +709,8 @@ &elf_ex, load_addr, load_bias, interp_load_addr, - (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); + (interpreter_type == INTERPRETER_AOUT ? 0 : 1), + bprm->nr_pages * PAGE_SIZE); /* N.B. passed_fileno might not be initialized? */ if (interpreter_type == INTERPRETER_AOUT) current->mm->arg_start += strlen(passed_fileno) + 1; --- linux/kernel/sysctl.c.orig Thu Sep 27 08:50:58 2001 +++ linux/kernel/sysctl.c Thu Sep 27 08:52:20 2001 @@ -268,6 +268,8 @@ &pgt_cache_water, 2*sizeof(int), 0644, NULL, &proc_dointvec}, {VM_PAGE_CLUSTER, "page-cluster", &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec}, + {VM_EXEC_ARGSIZE, "exec-argsize", + &exec_argsize, sizeof(int), 0644, NULL, &proc_dointvec}, {0} }; --- linux/include/linux/binfmts.h.orig Thu Sep 27 08:49:51 2001 +++ linux/include/linux/binfmts.h Thu Sep 27 09:20:55 2001 @@ -4,12 +4,7 @@ #include #include -/* - * MAX_ARG_PAGES defines the number of pages allocated for arguments - * and envelope for the new program. 32 should suffice, this gives - * a maximum env+arg of 128kB w/4KB pages! - */ -#define MAX_ARG_PAGES 32 +extern int exec_argsize; /* sizeof(linux_binprm->buf) */ #define BINPRM_BUF_SIZE 128 @@ -21,7 +16,8 @@ */ struct linux_binprm{ char buf[BINPRM_BUF_SIZE]; - struct page *page[MAX_ARG_PAGES]; + int nr_pages; + struct page **pages; unsigned long p; /* current top of mem */ int sh_bang; struct file * file; --- linux/include/linux/sysctl.h.orig Thu Sep 27 09:21:58 2001 +++ linux/include/linux/sysctl.h Thu Sep 27 09:22:44 2001 @@ -137,7 +137,8 @@ VM_PAGECACHE=7, /* struct: Set cache memory thresholds */ VM_PAGERDAEMON=8, /* struct: Control kswapd behaviour */ VM_PGT_CACHE=9, /* struct: Set page table cache parameters */ - VM_PAGE_CLUSTER=10 /* int: set number of pages to swap together */ + VM_PAGE_CLUSTER=10, /* int: set number of pages to swap together */ + VM_EXEC_ARGSIZE=11 /* int: maximum exec() argument size in bytes */ };