From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Ollie Wild" Subject: Re: [patch] remove MAX_ARG_PAGES Date: Sun, 31 Dec 2006 22:51:40 -0800 Message-ID: <65dd6fd50612312251x5d266ab3l8306236152b33585@mail.gmail.com> References: <65dd6fd50610101705t3db93a72sc0847cd120aa05d3@mail.gmail.com> <1160572460.2006.79.camel@taijtu> <65dd6fd50610111448q7ff210e1nb5f14917c311c8d4@mail.gmail.com> <65dd6fd50610241048h24af39d9ob49c3816dfe1ca64@mail.gmail.com> <20061229200357.GA5940@elte.hu> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0310451956==" Return-path: In-Reply-To: <20061229200357.GA5940@elte.hu> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Mime-version: 1.0 Sender: parisc-linux-bounces@lists.parisc-linux.org Errors-To: parisc-linux-bounces@lists.parisc-linux.org To: Ingo Molnar Cc: Andrew Morton , linux-arch@vger.kernel.org, Peter Zijlstra , Andi Kleen , linux-kernel@vger.kernel.org, David Howells , linux-mm@kvack.org, Linus Torvalds , parisc-linux@lists.parisc-linux.org, Arjan van de Ven List-Id: linux-mm.kvack.org --===============0310451956== Content-Type: multipart/alternative; boundary="----=_Part_147502_21702467.1167634300468" ------=_Part_147502_21702467.1167634300468 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inline There are still a couple outstanding issues which need to be resolved before this is ready for inclusion in the mainline kernel. The main one is support for CONFIG_STACK_GROWSUP, which I think is just parisc. I've been meaning to look into this for a while, but I was out of commision for most of November so it got punted to the back burner. I'll try to revisit it soonish. If someone from the parisc-linux list wants to take a look, though, that's fine by me. The other is support for the various executable formats. I've tested elf and script pretty thoroughly, but I'm not sure how to go about testing most of the others -- does anyone use aout anymore? Maybe the solution is just to check it in and wait to see if someone complains. Ollie On 12/29/06, Ingo Molnar wrote: > > > FYI, i have forward ported your MAX_ARG_PAGES limit removal patch to > 2.6.20-rc2 and have included it in the -rt kernel. It's working great - > i can now finally do a "ls -t patches/*.patch" in my patch repository - > something i havent been able to do for years ;-) > > what is keeping this fix from going upstream? > > Ingo > > --------------> > Subject: [patch] remove MAX_ARG_PAGES > From: Ollie Wild > > this patch removes the MAX_ARG_PAGES limit by copying between VMs. This > makes process argv/env limited by the stack limit (and it's thus > arbitrarily sizable). No more: > > -bash: /bin/ls: Argument list too long > > Signed-off-by: Ingo Molnar > --- > arch/x86_64/ia32/ia32_binfmt.c | 55 ----- > fs/binfmt_elf.c | 12 - > fs/binfmt_misc.c | 4 > fs/binfmt_script.c | 4 > fs/compat.c | 118 ++++-------- > fs/exec.c | 382 > +++++++++++++++++++---------------------- > include/linux/binfmts.h | 14 - > include/linux/mm.h | 7 > kernel/auditsc.c | 5 > mm/mprotect.c | 2 > mm/mremap.c | 2 > 11 files changed, 250 insertions(+), 355 deletions(-) > > Index: linux/arch/x86_64/ia32/ia32_binfmt.c > =================================================================== > --- linux.orig/arch/x86_64/ia32/ia32_binfmt.c > +++ linux/arch/x86_64/ia32/ia32_binfmt.c > @@ -279,9 +279,6 @@ do > { \ > #define load_elf_binary load_elf32_binary > > #define ELF_PLAT_INIT(r, load_addr) elf32_init(r) > -#define setup_arg_pages(bprm, stack_top, exec_stack) \ > - ia32_setup_arg_pages(bprm, stack_top, exec_stack) > -int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long > stack_top, int executable_stack); > > #undef start_thread > #define start_thread(regs,new_rip,new_rsp) do { \ > @@ -336,57 +333,7 @@ static void elf32_init(struct pt_regs *r > int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long > stack_top, > int executable_stack) > { > - unsigned long stack_base; > - struct vm_area_struct *mpnt; > - struct mm_struct *mm = current->mm; > - int i, ret; > - > - stack_base = stack_top - MAX_ARG_PAGES * PAGE_SIZE; > - mm->arg_start = bprm->p + stack_base; > - > - bprm->p += stack_base; > - if (bprm->loader) > - bprm->loader += stack_base; > - bprm->exec += stack_base; > - > - mpnt = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); > - if (!mpnt) > - return -ENOMEM; > - > - memset(mpnt, 0, sizeof(*mpnt)); > - > - down_write(&mm->mmap_sem); > - { > - mpnt->vm_mm = mm; > - mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; > - mpnt->vm_end = stack_top; > - if (executable_stack == EXSTACK_ENABLE_X) > - mpnt->vm_flags = VM_STACK_FLAGS | VM_EXEC; > - else if (executable_stack == EXSTACK_DISABLE_X) > - mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC; > - else > - mpnt->vm_flags = VM_STACK_FLAGS; > - mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC) ? > - PAGE_COPY_EXEC : PAGE_COPY; > - if ((ret = insert_vm_struct(mm, mpnt))) { > - up_write(&mm->mmap_sem); > - kmem_cache_free(vm_area_cachep, mpnt); > - return ret; > - } > - mm->stack_vm = mm->total_vm = vma_pages(mpnt); > - } > - > - for (i = 0 ; i < MAX_ARG_PAGES ; i++) { > - struct page *page = bprm->page[i]; > - if (page) { > - bprm->page[i] = NULL; > - install_arg_page(mpnt, page, stack_base); > - } > - stack_base += PAGE_SIZE; > - } > - up_write(&mm->mmap_sem); > - > - return 0; > + return setup_arg_pages(bprm, stack_top, executable_stack); > } > EXPORT_SYMBOL(ia32_setup_arg_pages); > > Index: linux/fs/binfmt_elf.c > =================================================================== > --- linux.orig/fs/binfmt_elf.c > +++ linux/fs/binfmt_elf.c > @@ -253,8 +253,8 @@ create_elf_tables(struct linux_binprm *b > size_t len; > if (__put_user((elf_addr_t)p, argv++)) > return -EFAULT; > - len = strnlen_user((void __user *)p, > PAGE_SIZE*MAX_ARG_PAGES); > - if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) > + len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); > + if (!len || len > MAX_ARG_STRLEN) > return 0; > p += len; > } > @@ -265,8 +265,8 @@ create_elf_tables(struct linux_binprm *b > size_t len; > if (__put_user((elf_addr_t)p, envp++)) > return -EFAULT; > - len = strnlen_user((void __user *)p, > PAGE_SIZE*MAX_ARG_PAGES); > - if (!len || len > PAGE_SIZE*MAX_ARG_PAGES) > + len = strnlen_user((void __user *)p, MAX_ARG_STRLEN); > + if (!len || len > MAX_ARG_STRLEN) > return 0; > p += len; > } > @@ -767,10 +767,6 @@ static int load_elf_binary(struct linux_ > } > > /* OK, This is the point of no return */ > - current->mm->start_data = 0; > - current->mm->end_data = 0; > - current->mm->end_code = 0; > - current->mm->mmap = NULL; > current->flags &= ~PF_FORKNOEXEC; > current->mm->def_flags = def_flags; > > Index: linux/fs/binfmt_misc.c > =================================================================== > --- linux.orig/fs/binfmt_misc.c > +++ linux/fs/binfmt_misc.c > @@ -126,7 +126,9 @@ static int load_misc_binary(struct linux > goto _ret; > > if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) { > - remove_arg_zero(bprm); > + retval = remove_arg_zero(bprm); > + if (retval) > + goto _ret; > } > > if (fmt->flags & MISC_FMT_OPEN_BINARY) { > Index: linux/fs/binfmt_script.c > =================================================================== > --- linux.orig/fs/binfmt_script.c > +++ linux/fs/binfmt_script.c > @@ -68,7 +68,9 @@ static int load_script(struct linux_binp > * This is done in reverse order, because of how the > * user environment and arguments are stored. > */ > - remove_arg_zero(bprm); > + retval = remove_arg_zero(bprm); > + if (retval) > + return retval; > retval = copy_strings_kernel(1, &bprm->interp, bprm); > if (retval < 0) return retval; > bprm->argc++; > Index: linux/fs/compat.c > =================================================================== > --- linux.orig/fs/compat.c > +++ linux/fs/compat.c > @@ -1389,6 +1389,7 @@ static int compat_copy_strings(int argc, > { > struct page *kmapped_page = NULL; > char *kaddr = NULL; > + unsigned long kpos = 0; > int ret; > > while (argc-- > 0) { > @@ -1397,92 +1398,72 @@ static int compat_copy_strings(int argc, > unsigned long pos; > > if (get_user(str, argv+argc) || > - !(len = strnlen_user(compat_ptr(str), bprm->p))) { > + !(len = strnlen_user(compat_ptr(str), > MAX_ARG_STRLEN))) { > ret = -EFAULT; > goto out; > } > > - if (bprm->p < len) { > + if (MAX_ARG_STRLEN < len) { > ret = -E2BIG; > goto out; > } > > - bprm->p -= len; > - /* XXX: add architecture specific overflow check here. */ > + /* We're going to work our way backwords. */ > pos = bprm->p; > + str += len; > + bprm->p -= len; > > 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; > + if (offset == 0) > + offset = PAGE_SIZE; > + > + bytes_to_copy = offset; > + if (bytes_to_copy > len) > + bytes_to_copy = len; > + > + offset -= bytes_to_copy; > + pos -= bytes_to_copy; > + str -= bytes_to_copy; > + len -= bytes_to_copy; > + > + if (!kmapped_page || kpos != (pos & PAGE_MASK)) { > + struct page *page; > + > + ret = get_user_pages(current, bprm->mm, > pos, > + 1, 1, 1, &page, > NULL); > + if (ret <= 0) { > + /* We've exceed the stack rlimit. > */ > + ret = -E2BIG; > goto out; > } > - new = 1; > - } > > - if (page != kmapped_page) { > - if (kmapped_page) > + if (kmapped_page) { > kunmap(kmapped_page); > + put_page(kmapped_page); > + } > kmapped_page = page; > kaddr = kmap(kmapped_page); > + kpos = pos & PAGE_MASK; > } > - 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) { > + if (copy_from_user(kaddr+offset, compat_ptr(str), > + bytes_to_copy)) { > ret = -EFAULT; > goto out; > } > - > - pos += bytes_to_copy; > - str += bytes_to_copy; > - len -= bytes_to_copy; > } > } > ret = 0; > out: > - if (kmapped_page) > + 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; > + put_page(kmapped_page); > } > + return ret; > } > > -#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. > @@ -1495,7 +1476,6 @@ int compat_do_execve(char * filename, > struct linux_binprm *bprm; > struct file *file; > int retval; > - int i; > > retval = -ENOMEM; > bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); > @@ -1509,24 +1489,19 @@ int compat_do_execve(char * filename, > > sched_exec(); > > - bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); > bprm->file = file; > bprm->filename = filename; > bprm->interp = filename; > - 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; > + retval = bprm_mm_init(bprm); > + if (retval) > + goto out_file; > > - bprm->argc = compat_count(argv, bprm->p / sizeof(compat_uptr_t)); > + bprm->argc = compat_count(argv, MAX_ARG_STRINGS); > if ((retval = bprm->argc) < 0) > goto out_mm; > > - bprm->envc = compat_count(envp, bprm->p / sizeof(compat_uptr_t)); > + bprm->envc = compat_count(envp, MAX_ARG_STRINGS); > if ((retval = bprm->envc) < 0) > goto out_mm; > > @@ -1551,10 +1526,8 @@ int compat_do_execve(char * filename, > if (retval < 0) > goto out; > > - retval = search_binary_handler(bprm, regs); > + retval = search_binary_handler(bprm,regs); > if (retval >= 0) { > - free_arg_pages(bprm); > - > /* execve success */ > security_bprm_free(bprm); > acct_update_integrals(current); > @@ -1563,19 +1536,12 @@ int compat_do_execve(char * filename, > } > > 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); > + mmput (bprm->mm); > > out_file: > if (bprm->file) { > Index: linux/fs/exec.c > =================================================================== > --- linux.orig/fs/exec.c > +++ linux/fs/exec.c > @@ -174,6 +174,79 @@ exit: > goto out; > } > > +#ifdef CONFIG_STACK_GROWSUP > +#error I broke your build because I rearchitected the stack code, and I \ > + don't have access to an architecture where CONFIG_STACK_GROWSUP is > \ > + set. Please fixe this or send me a machine which I can test this > on. \ > + \ > + -- Ollie Wild > +#endif > + > +/* Create a new mm_struct and populate it with a temporary stack > + * vm_area_struct. We don't have enough context at this point to set the > + * stack flags, permissions, and offset, so we use temporary > values. We'll > + * update them later in setup_arg_pages(). */ > +int bprm_mm_init(struct linux_binprm *bprm) > +{ > + int err; > + struct mm_struct *mm = NULL; > + struct vm_area_struct *vma = NULL; > + > + bprm->mm = mm = mm_alloc(); > + err = -ENOMEM; > + if (!mm) > + goto err; > + > + if ((err = init_new_context(current, mm))) > + goto err; > + > + bprm->vma = vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); > + err = -ENOMEM; > + if (!vma) > + goto err; > + > + down_write(&mm->mmap_sem); > + { > + vma->vm_mm = mm; > + > + /* Place the stack at the top of user memory. Later, > we'll > + * move this to an appropriate place. We don't use > STACK_TOP > + * because that can depend on attributes which aren't > + * configured yet. */ > + vma->vm_end = TASK_SIZE; > + vma->vm_start = vma->vm_end - PAGE_SIZE; > + > + vma->vm_flags = VM_STACK_FLAGS; > + vma->vm_page_prot = protection_map[vma->vm_flags & 0x7]; > + if ((err = insert_vm_struct(mm, vma))) { > + up_write(&mm->mmap_sem); > + goto err; > + } > + > + mm->stack_vm = mm->total_vm = 1; > + } > + up_write(&mm->mmap_sem); > + > + bprm->p = vma->vm_end - sizeof(void *); > + > + return 0; > + > +err: > + if (vma) { > + bprm->vma = NULL; > + kmem_cache_free(vm_area_cachep, vma); > + } > + > + if (mm) { > + bprm->mm = NULL; > + mmdrop(mm); > + } > + > + return err; > +} > + > +EXPORT_SYMBOL(bprm_mm_init); > + > /* > * count() counts the number of strings in array ARGV. > */ > @@ -199,15 +272,16 @@ static int count(char __user * __user * > } > > /* > - * 'copy_strings()' copies argument/environment 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. > + * 'copy_strings()' copies argument/environment strings from the old > + * processes's memory to the new process's stack. The call to > get_user_pages() > + * ensures the destination page is created and not swapped out. > */ > static int copy_strings(int argc, char __user * __user * argv, > struct linux_binprm *bprm) > { > struct page *kmapped_page = NULL; > char *kaddr = NULL; > + unsigned long kpos = 0; > int ret; > > while (argc-- > 0) { > @@ -216,69 +290,68 @@ static int copy_strings(int argc, char _ > unsigned long pos; > > if (get_user(str, argv+argc) || > - !(len = strnlen_user(str, bprm->p))) { > + !(len = strnlen_user(str, > MAX_ARG_STRLEN))) { > ret = -EFAULT; > goto out; > } > > - if (bprm->p < len) { > + if (MAX_ARG_STRLEN < len) { > ret = -E2BIG; > goto out; > } > > - bprm->p -= len; > - /* XXX: add architecture specific overflow check here. */ > + /* We're going to work our way backwords. */ > pos = bprm->p; > + str += len; > + bprm->p -= len; > > 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; > + if (offset == 0) > + offset = PAGE_SIZE; > + > + bytes_to_copy = offset; > + if (bytes_to_copy > len) > + bytes_to_copy = len; > + > + offset -= bytes_to_copy; > + pos -= bytes_to_copy; > + str -= bytes_to_copy; > + len -= bytes_to_copy; > + > + if (!kmapped_page || kpos != (pos & PAGE_MASK)) { > + struct page *page; > + > + ret = get_user_pages(current, bprm->mm, > pos, > + 1, 1, 1, &page, > NULL); > + if (ret <= 0) { > + /* We've exceed the stack rlimit. > */ > + ret = -E2BIG; > goto out; > } > - new = 1; > - } > > - if (page != kmapped_page) { > - if (kmapped_page) > + if (kmapped_page) { > kunmap(kmapped_page); > + put_page(kmapped_page); > + } > kmapped_page = page; > kaddr = kmap(kmapped_page); > + kpos = pos & PAGE_MASK; > } > - 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, str, > bytes_to_copy); > - if (err) { > + if (copy_from_user(kaddr+offset, str, > bytes_to_copy)) { > ret = -EFAULT; > goto out; > } > - > - pos += bytes_to_copy; > - str += bytes_to_copy; > - len -= bytes_to_copy; > } > } > ret = 0; > out: > - if (kmapped_page) > + if (kmapped_page) { > kunmap(kmapped_page); > + put_page(kmapped_page); > + } > return ret; > } > > @@ -297,157 +370,79 @@ int copy_strings_kernel(int argc,char ** > > EXPORT_SYMBOL(copy_strings_kernel); > > -#ifdef CONFIG_MMU > -/* > - * This routine is used to map in a page into an address space: needed by > - * execve() for the initial stack and environment pages. > - * > - * vma->vm_mm->mmap_sem is held for writing. > - */ > -void install_arg_page(struct vm_area_struct *vma, > - struct page *page, unsigned long address) > -{ > - struct mm_struct *mm = vma->vm_mm; > - pte_t * pte; > - spinlock_t *ptl; > - > - if (unlikely(anon_vma_prepare(vma))) > - goto out; > - > - flush_dcache_page(page); > - pte = get_locked_pte(mm, address, &ptl); > - if (!pte) > - goto out; > - if (!pte_none(*pte)) { > - pte_unmap_unlock(pte, ptl); > - goto out; > - } > - inc_mm_counter(mm, anon_rss); > - lru_cache_add_active(page); > - set_pte_at(mm, address, pte, pte_mkdirty(pte_mkwrite(mk_pte( > - page, vma->vm_page_prot)))); > - page_add_new_anon_rmap(page, vma, address); > - pte_unmap_unlock(pte, ptl); > - > - /* no need for flush_tlb */ > - return; > -out: > - __free_page(page); > - force_sig(SIGKILL, current); > -} > - > #define EXTRA_STACK_VM_PAGES 20 /* random */ > > +/* Finalizes the stack vm_area_struct. The flags and permissions are > updated, > + * the stack is optionally relocated, and some extra space is added. > + */ > int setup_arg_pages(struct linux_binprm *bprm, > unsigned long stack_top, > int executable_stack) > { > - unsigned long stack_base; > - struct vm_area_struct *mpnt; > + unsigned long ret; > + unsigned long stack_base, stack_shift; > struct mm_struct *mm = current->mm; > - int i, ret; > - long arg_size; > > -#ifdef CONFIG_STACK_GROWSUP > - /* Move the argument and environment strings to the bottom of the > - * stack space. > - */ > - int offset, j; > - char *to, *from; > + BUG_ON(stack_top > TASK_SIZE); > + BUG_ON(stack_top & ~PAGE_MASK); > > - /* Start by shifting all the pages down */ > - i = 0; > - for (j = 0; j < MAX_ARG_PAGES; j++) { > - struct page *page = bprm->page[j]; > - if (!page) > - continue; > - bprm->page[i++] = page; > - } > - > - /* Now move them within their pages */ > - offset = bprm->p % PAGE_SIZE; > - to = kmap(bprm->page[0]); > - for (j = 1; j < i; j++) { > - memmove(to, to + offset, PAGE_SIZE - offset); > - from = kmap(bprm->page[j]); > - memcpy(to + PAGE_SIZE - offset, from, offset); > - kunmap(bprm->page[j - 1]); > - to = from; > - } > - memmove(to, to + offset, PAGE_SIZE - offset); > - kunmap(bprm->page[j - 1]); > - > - /* Limit stack size to 1GB */ > - stack_base = current->signal->rlim[RLIMIT_STACK].rlim_max; > - if (stack_base > (1 << 30)) > - stack_base = 1 << 30; > - stack_base = PAGE_ALIGN(stack_top - stack_base); > - > - /* Adjust bprm->p to point to the end of the strings. */ > - bprm->p = stack_base + PAGE_SIZE * i - offset; > - > - mm->arg_start = stack_base; > - arg_size = i << PAGE_SHIFT; > - > - /* zero pages that were copied above */ > - while (i < MAX_ARG_PAGES) > - bprm->page[i++] = NULL; > -#else > - stack_base = arch_align_stack(stack_top - > MAX_ARG_PAGES*PAGE_SIZE); > + stack_base = arch_align_stack(stack_top - mm->stack_vm*PAGE_SIZE); > stack_base = PAGE_ALIGN(stack_base); > - bprm->p += stack_base; > - mm->arg_start = bprm->p; > - arg_size = stack_top - (PAGE_MASK & (unsigned long) > mm->arg_start); > -#endif > > - arg_size += EXTRA_STACK_VM_PAGES * PAGE_SIZE; > + stack_shift = (bprm->p & PAGE_MASK) - stack_base; > + BUG_ON(stack_shift < 0); > + bprm->p -= stack_shift; > + mm->arg_start = bprm->p; > > if (bprm->loader) > - bprm->loader += stack_base; > - bprm->exec += stack_base; > - > - mpnt = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); > - if (!mpnt) > - return -ENOMEM; > - > - memset(mpnt, 0, sizeof(*mpnt)); > + bprm->loader -= stack_shift; > + bprm->exec -= stack_shift; > > down_write(&mm->mmap_sem); > { > - mpnt->vm_mm = mm; > -#ifdef CONFIG_STACK_GROWSUP > - mpnt->vm_start = stack_base; > - mpnt->vm_end = stack_base + arg_size; > -#else > - mpnt->vm_end = stack_top; > - mpnt->vm_start = mpnt->vm_end - arg_size; > -#endif > + struct vm_area_struct *vma = bprm->vma; > + struct vm_area_struct *prev = NULL; > + unsigned long vm_flags = vma->vm_flags; > + > /* Adjust stack execute permissions; explicitly enable > * for EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X > * and leave alone (arch default) otherwise. */ > if (unlikely(executable_stack == EXSTACK_ENABLE_X)) > - mpnt->vm_flags = VM_STACK_FLAGS | VM_EXEC; > + vm_flags |= VM_EXEC; > else if (executable_stack == EXSTACK_DISABLE_X) > - mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC; > - else > - mpnt->vm_flags = VM_STACK_FLAGS; > - mpnt->vm_flags |= mm->def_flags; > - mpnt->vm_page_prot = protection_map[mpnt->vm_flags & 0x7]; > - if ((ret = insert_vm_struct(mm, mpnt))) { > + vm_flags &= ~VM_EXEC; > + vm_flags |= mm->def_flags; > + > + ret = mprotect_fixup(vma, &prev, vma->vm_start, > vma->vm_end, > + vm_flags); > + if (ret) { > up_write(&mm->mmap_sem); > - kmem_cache_free(vm_area_cachep, mpnt); > return ret; > } > - mm->stack_vm = mm->total_vm = vma_pages(mpnt); > - } > + BUG_ON(prev != vma); > + > + /* Move stack pages down in memory. */ > + if (stack_shift) { > + /* This should be safe even with overlap because > we > + * are shifting down. */ > + ret = move_vma(vma, vma->vm_start, > + vma->vm_end - vma->vm_start, > + vma->vm_end - vma->vm_start, > + vma->vm_start - stack_shift); > + if (ret & ~PAGE_MASK) { > + up_write(&mm->mmap_sem); > + return ret; > + } > + } > > - for (i = 0 ; i < MAX_ARG_PAGES ; i++) { > - struct page *page = bprm->page[i]; > - if (page) { > - bprm->page[i] = NULL; > - install_arg_page(mpnt, page, stack_base); > + // Expand the stack. > + vma = find_vma(mm, bprm->p); > + BUG_ON(!vma || bprm->p < vma->vm_start); > + if (expand_stack(vma, stack_base - > + EXTRA_STACK_VM_PAGES * PAGE_SIZE)) > { > + up_write(&mm->mmap_sem); > + return -EFAULT; > } > - stack_base += PAGE_SIZE; > } > up_write(&mm->mmap_sem); > > @@ -456,23 +451,6 @@ int setup_arg_pages(struct linux_binprm > > EXPORT_SYMBOL(setup_arg_pages); > > -#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 */ > - > struct file *open_exec(const char *name) > { > struct nameidata nd; > @@ -993,8 +971,10 @@ void compute_creds(struct linux_binprm * > > EXPORT_SYMBOL(compute_creds); > > -void remove_arg_zero(struct linux_binprm *bprm) > +int remove_arg_zero(struct linux_binprm *bprm) > { > + int ret = 0; > + > if (bprm->argc) { > unsigned long offset; > char * kaddr; > @@ -1008,13 +988,23 @@ void remove_arg_zero(struct linux_binprm > continue; > offset = 0; > kunmap_atomic(kaddr, KM_USER0); > + put_page(page); > inside: > - page = bprm->page[bprm->p/PAGE_SIZE]; > + ret = get_user_pages(current, bprm->mm, bprm->p, > + 1, 0, 1, &page, NULL); > + if (ret <= 0) { > + ret = -EFAULT; > + goto out; > + } > kaddr = kmap_atomic(page, KM_USER0); > } > kunmap_atomic(kaddr, KM_USER0); > bprm->argc--; > + ret = 0; > } > + > +out: > + return ret; > } > > EXPORT_SYMBOL(remove_arg_zero); > @@ -1041,7 +1031,7 @@ int search_binary_handler(struct linux_b > fput(bprm->file); > bprm->file = NULL; > > - loader = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); > + loader = bprm->vma->vm_end - sizeof(void *); > > file = open_exec("/sbin/loader"); > retval = PTR_ERR(file); > @@ -1134,7 +1124,6 @@ int do_execve(char * filename, > struct linux_binprm *bprm; > struct file *file; > int retval; > - int i; > > retval = -ENOMEM; > bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); > @@ -1148,25 +1137,19 @@ int do_execve(char * filename, > > sched_exec(); > > - bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); > - > bprm->file = file; > bprm->filename = filename; > bprm->interp = filename; > - 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; > + retval = bprm_mm_init(bprm); > + if (retval) > + goto out_file; > > - bprm->argc = count(argv, bprm->p / sizeof(void *)); > + bprm->argc = count(argv, MAX_ARG_STRINGS); > if ((retval = bprm->argc) < 0) > goto out_mm; > > - bprm->envc = count(envp, bprm->p / sizeof(void *)); > + bprm->envc = count(envp, MAX_ARG_STRINGS); > if ((retval = bprm->envc) < 0) > goto out_mm; > > @@ -1193,8 +1176,6 @@ int do_execve(char * filename, > > retval = search_binary_handler(bprm,regs); > if (retval >= 0) { > - free_arg_pages(bprm); > - > /* execve success */ > security_bprm_free(bprm); > acct_update_integrals(current); > @@ -1203,19 +1184,12 @@ int do_execve(char * filename, > } > > 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); > + mmput (bprm->mm); > > out_file: > if (bprm->file) { > Index: linux/include/linux/binfmts.h > =================================================================== > --- linux.orig/include/linux/binfmts.h > +++ linux/include/linux/binfmts.h > @@ -5,12 +5,9 @@ > > struct pt_regs; > > -/* > - * 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 > +/* FIXME: Find real limits, or none. */ > +#define MAX_ARG_STRLEN (PAGE_SIZE * 32) > +#define MAX_ARG_STRINGS 0x7FFFFFFF > > /* sizeof(linux_binprm->buf) */ > #define BINPRM_BUF_SIZE 128 > @@ -22,7 +19,7 @@ struct pt_regs; > */ > struct linux_binprm{ > char buf[BINPRM_BUF_SIZE]; > - struct page *page[MAX_ARG_PAGES]; > + struct vm_area_struct *vma; > struct mm_struct *mm; > unsigned long p; /* current top of mem */ > int sh_bang; > @@ -65,7 +62,7 @@ extern int register_binfmt(struct linux_ > extern int unregister_binfmt(struct linux_binfmt *); > > extern int prepare_binprm(struct linux_binprm *); > -extern void remove_arg_zero(struct linux_binprm *); > +extern int __must_check remove_arg_zero(struct linux_binprm *); > extern int search_binary_handler(struct linux_binprm *,struct pt_regs *); > extern int flush_old_exec(struct linux_binprm * bprm); > > @@ -82,6 +79,7 @@ extern int suid_dumpable; > extern int setup_arg_pages(struct linux_binprm * bprm, > unsigned long stack_top, > int executable_stack); > +extern int bprm_mm_init(struct linux_binprm *bprm); > extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm > *bprm); > extern void compute_creds(struct linux_binprm *binprm); > extern int do_coredump(long signr, int exit_code, struct pt_regs * regs); > Index: linux/include/linux/mm.h > =================================================================== > --- linux.orig/include/linux/mm.h > +++ linux/include/linux/mm.h > @@ -775,7 +775,6 @@ static inline int handle_mm_fault(struct > > extern int make_pages_present(unsigned long addr, unsigned long end); > extern int access_process_vm(struct task_struct *tsk, unsigned long addr, > void *buf, int len, int write); > -void install_arg_page(struct vm_area_struct *, struct page *, unsigned > long); > > int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned > long start, > int len, int write, int force, struct page **pages, struct > vm_area_struct **vmas); > @@ -791,9 +790,15 @@ int FASTCALL(set_page_dirty(struct page > int set_page_dirty_lock(struct page *page); > int clear_page_dirty_for_io(struct page *page); > > +extern unsigned long move_vma(struct vm_area_struct *vma, > + unsigned long old_addr, unsigned long old_len, > + unsigned long new_len, unsigned long new_addr); > extern unsigned long do_mremap(unsigned long addr, > unsigned long old_len, unsigned long > new_len, > unsigned long flags, unsigned long > new_addr); > +extern int mprotect_fixup(struct vm_area_struct *vma, > + struct vm_area_struct **pprev, unsigned long > start, > + unsigned long end, unsigned long newflags); > > /* > * Prototype to add a shrinker callback for ageable caches. > Index: linux/kernel/auditsc.c > =================================================================== > --- linux.orig/kernel/auditsc.c > +++ linux/kernel/auditsc.c > @@ -1755,6 +1755,10 @@ int __audit_ipc_set_perm(unsigned long q > > int audit_bprm(struct linux_binprm *bprm) > { > + /* FIXME: Don't do anything for now until I figure out how to > handle > + * this. With the latest changes, kmalloc could well fail under > good > + * scenarios. */ > +#if 0 > struct audit_aux_data_execve *ax; > struct audit_context *context = current->audit_context; > unsigned long p, next; > @@ -1782,6 +1786,7 @@ int audit_bprm(struct linux_binprm *bprm > ax->d.type = AUDIT_EXECVE; > ax->d.next = context->aux; > context->aux = (void *)ax; > +#endif > return 0; > } > > Index: linux/mm/mprotect.c > =================================================================== > --- linux.orig/mm/mprotect.c > +++ linux/mm/mprotect.c > @@ -128,7 +128,7 @@ static void change_protection(struct vm_ > flush_tlb_range(vma, start, end); > } > > -static int > +int > mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, > unsigned long start, unsigned long end, unsigned long newflags) > { > Index: linux/mm/mremap.c > =================================================================== > --- linux.orig/mm/mremap.c > +++ linux/mm/mremap.c > @@ -155,7 +155,7 @@ static unsigned long move_page_tables(st > return len + old_addr - old_end; /* how much done */ > } > > -static unsigned long move_vma(struct vm_area_struct *vma, > +unsigned long move_vma(struct vm_area_struct *vma, > unsigned long old_addr, unsigned long old_len, > unsigned long new_len, unsigned long new_addr) > { > ------=_Part_147502_21702467.1167634300468 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline There are still a couple outstanding issues which need to be resolved befor= e this is ready for inclusion in the mainline kernel.

The main one i= s support for CONFIG_STACK_GROWSUP, which I think is just parisc.  I&#= 39;ve been meaning to look into this for a while, but I was out of commisio= n for most of November so it got punted to the back burner.  I'll = try to revisit it soonish.  If someone from the parisc-linux list want= s to take a look, though, that's fine by me.

The other is support for the various executable formats.  I= 9;ve tested elf and script pretty thoroughly, but I'm not sure how to g= o about testing most of the others -- does anyone use aout anymore?  M= aybe the solution is just to check it in and wait to see if someone complai= ns.

Ollie

On 12/29/06, Ingo Molnar <= mingo@elte.hu> wrote:

FYI, i have forward ported your MAX_ARG_PAGES limit removal patch to2.6.20-rc2 and have included it in the -rt kernel. It's working great = -
i can now finally do a "ls -t patches/*.patch" in my patch r= epository -
something i havent been able to do for years ;-)

what is keeping= this fix from going upstream?

      &= nbsp; Ingo

-------------->
Subject: [patch] remove MAX_AR= G_PAGES
From: Ollie Wild < aaw@google.com>

this patch removes the MAX_ARG_PAGES limit by= copying between VMs. This
makes process argv/env limited by the stack l= imit (and it's thus
arbitrarily sizable). No more:

 &nbs= p;-bash: /bin/ls: Argument list too long

Signed-off-by: Ingo Molnar <min= go@elte.hu>
---
arch/x86_64/ia32/ia32_binfmt.c |   = 55 -----
fs/binfmt_elf.c        = ;        |   12 -
fs/= binfmt_misc.c          &n= bsp;    |    4
fs/binfmt_script.c        &nbs= p;    |    4
fs/compat.c  =             &nb= sp;     |  118 ++++--------
fs/exec.= c            &n= bsp;         |  382 = +++++++++++++++++++----------------------
include/linux/binfmts.h =        |   14 -
include/linux/mm.h        &nbs= p;    |    7
kernel/auditsc.c &= nbsp;           &nbs= p; |    5
mm/mprotect.c    &nbs= p;            &= nbsp;|    2
mm/mremap.c    &nbs= p;            &= nbsp;  |    2
11 files changed, 250 inser= tions(+), 355 deletions(-)

Index: linux/arch/x86_64/ia32/ia32_binfmt.c
=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- linux.orig/arch/x86_64/ia32/ia32_b= infmt.c
+++ linux/arch/x86_64/ia32/ia32_binfmt.c
@@ -279,9 +279,6 @@ = do {            = ;            &n= bsp;            = ;            &n= bsp;      \
#define load_elf_binary load_elf32_binary

#define ELF_PLAT_INI= T(r, load_addr)    elf32_init(r)
-#define setup_arg_= pages(bprm, stack_top, exec_stack) \
-     &nbs= p; ia32_setup_arg_pages(bprm, stack_top, exec_stack)
-int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long stac= k_top, int executable_stack);

#undef start_thread
#define start= _thread(regs,new_rip,new_rsp) do { \
@@ -336,57 +333,7 @@ static void el= f32_init(struct pt_regs *r
int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long stac= k_top,
           = ;            &n= bsp; int executable_stack)
{
-       u= nsigned long stack_base;
-       struct vm= _area_struct *mpnt;
-       struct mm_stru= ct *mm =3D current->mm;
-       int i, ret;
-
-  =      stack_base =3D stack_top - MAX_ARG_PAGES * PAGE_SI= ZE;
-       mm->arg_start =3D bprm->= p + stack_base;
-
-       bprm->p += =3D stack_base;
-       if (bprm->loade= r)
-            &n= bsp;  bprm->loader +=3D stack_base;
-    &nb= sp;  bprm->exec +=3D stack_base;
-
-    &= nbsp;  mpnt =3D kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
-&nbs= p;      if (!mpnt)
-    &nb= sp;          return -ENOMEM;-
-       memset(mpnt, 0, sizeof(*mpnt));
-<= br>-       down_write(&mm->mmap_sem);<= br>-       {
-    &nbs= p;          mpnt->vm_mm =3D= mm;
-           =     mpnt->vm_start =3D PAGE_MASK & (unsigned long) bp= rm->p;
-           &nbs= p;   mpnt->vm_end =3D stack_top;
-    &= nbsp;          if (executable_= stack =3D=3D EXSTACK_ENABLE_X)
-      &nbs= p;            &= nbsp;   mpnt->vm_flags =3D VM_STACK_FLAGS |  VM_EXEC= ;
-           &nb= sp;   else if (executable_stack =3D=3D EXSTACK_DISABLE_X)
-           &nbs= p;           mpnt->vm_= flags =3D VM_STACK_FLAGS & ~VM_EXEC;
-     =           else
-  = ;            &n= bsp;        mpnt->vm_flags =3D VM_STA= CK_FLAGS;
-          &= nbsp;    mpnt->vm_page_prot =3D (mpnt->vm_flags & = VM_EXEC) ?
-           &nbs= p;           PAGE_COPY_EX= EC : PAGE_COPY;
-         &= nbsp;     if ((ret =3D insert_vm_struct(mm, mpnt))) {-            =            up_write(&= mm->mmap_sem);
-         = ;            &n= bsp; kmem_cache_free(vm_area_cachep, mpnt);
-           &nbs= p;           return ret;<= br>-            = ;   }
-         &= nbsp;     mm->stack_vm =3D mm->total_vm =3D vma_p= ages(mpnt);
-       }
-
-  = ;     for (i =3D 0 ; i < MAX_ARG_PAGES ; i++) {
-=             &nb= sp;  struct page *page =3D bprm->page[i];
-           &nbs= p;   if (page) {
-       &n= bsp;            = ;   bprm->page[i] =3D NULL;
-     =             &nb= sp;     install_arg_page(mpnt, page, stack_base);
-&= nbsp;           &nbs= p;  }
-          =      stack_base +=3D PAGE_SIZE;
-       }
-     &= nbsp; up_write(&mm->mmap_sem);
-
-    &nbs= p;  return 0;
+       return setup_ar= g_pages(bprm, stack_top, executable_stack);
}
EXPORT_SYMBOL(ia32_se= tup_arg_pages);

Index: linux/fs/binfmt_elf.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- linux.orig= /fs/binfmt_elf.c
+++ linux/fs/binfmt_elf.c
@@ -253,8 +253,8 @@ create= _elf_tables(struct linux_binprm *b
      &= nbsp;         size_t len;
            = ;    if (__put_user((elf_addr_t)p, argv++))
 &n= bsp;            = ;          return -EFAULT= ;
-           &nb= sp;   len =3D strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PA= GES);
-           = ;    if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+           &nbs= p;   len =3D strnlen_user((void __user *)p, MAX_ARG_STRLEN);
+=             &nb= sp;  if (!len || len > MAX_ARG_STRLEN)
    &= nbsp;           &nbs= p;       return 0;
   =             &nb= sp;p +=3D len;
        }
@@ -= 265,8 +265,8 @@ create_elf_tables(struct linux_binprm *b
            = ;    size_t len;
      = ;          if (__put_user= ((elf_addr_t)p, envp++))
        = ;            &n= bsp;   return -EFAULT;
-     &nb= sp;         len =3D strnlen_user((v= oid __user *)p, PAGE_SIZE*MAX_ARG_PAGES);
-     = ;          if (!len || len >= ; PAGE_SIZE*MAX_ARG_PAGES)
+           &nbs= p;   len =3D strnlen_user((void __user *)p, MAX_ARG_STRLEN);
+=             &nb= sp;  if (!len || len > MAX_ARG_STRLEN)
    &= nbsp;           &nbs= p;       return 0;
   =             &nb= sp;p +=3D len;
        }
@@ -= 767,10 +767,6 @@ static int load_elf_binary(struct linux_
        }

  &n= bsp;     /* OK, This is the point of no return */<= br>-       current->mm->start_data =3D = 0;
-       current->mm->end_data =3D= 0;
-       current->mm->end_code = =3D 0;
-       current->mm->mmap =3D= NULL;
        current->flags &= =3D ~PF_FORKNOEXEC;
        curr= ent->mm->def_flags =3D def_flags;

Index: linux/fs/binfmt_misc.= c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
---=20 linux.orig/fs/binfmt_misc.c
+++ linux/fs/binfmt_misc.c
@@ -126,7 +126= ,9 @@ static int load_misc_binary(struct linux
    &= nbsp;           goto= _ret;

        if (!(fmt->= ;flags & MISC_FMT_PRESERVE_ARGV0)) {
-            &n= bsp;  remove_arg_zero(bprm);
+      &= nbsp;        retval =3D remove_arg_zero(= bprm);
+          &nbs= p;    if (retval)
+      &n= bsp;            = ;    goto _ret;
       = ; }

        if (fmt->= ;flags & MISC_FMT_OPEN_BINARY) {
Index: linux/fs/binfmt_script.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D
--- linux.orig/fs/binfmt_script.c
+++ linux/fs/binfmt= _script.c
@@ -68,7 +68,9 @@ static int load_script(struct linux_binp
         * This is done in reve= rse order, because of how the
       =   * user environment and arguments are stored.
   &n= bsp;     */
-       re= move_arg_zero(bprm);
+       retval =3D re= move_arg_zero(bprm);
+       if (retval)
+           &nbs= p;   return retval;
       =  retval =3D copy_strings_kernel(1, &bprm->interp, bprm);
&nb= sp;       if (retval < 0) return retv= al;
        bprm->argc++;
= Index: linux/fs/compat.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D
--- linux.orig/fs/compat.c
+++ linux/fs/compat.c
@@ -1389,6 +1389= ,7 @@ static int compat_copy_strings(int argc,
{
   &= nbsp;    struct page *kmapped_page =3D NULL;
 &= nbsp;      char *kaddr =3D NULL;
+ &n= bsp;     unsigned long kpos =3D 0;
        int ret;

 &= nbsp;      while (argc-- > 0) {
@@ -139= 7,92 +1398,72 @@ static int compat_copy_strings(int argc,
  &n= bsp;            = ; unsigned long pos;

       =          if (get_user(str, arg= v+argc) ||
-            &n= bsp;          !(len =3D strnle= n_user(compat_ptr(str), bprm->p))) {
+     &= nbsp;           &nbs= p; !(len =3D strnlen_user(compat_ptr(str), MAX_ARG_STRLEN))) {
 &nb= sp;            =           ret =3D -EFAULT= ;
           &nbs= p;            g= oto out;
            = ;    }

-      &nbs= p;        if (bprm->p < len) =  {
+          &nb= sp;    if (MAX_ARG_STRLEN < len) {
   &= nbsp;           &nbs= p;        ret =3D -E2BIG;
 =             &nb= sp;          goto out;            &n= bsp;   }

-           =     bprm->p -=3D len;
-     &= nbsp;         /* XXX: add architect= ure specific overflow check here. */
+     &nbs= p;         /* We're going to wo= rk our way backwords. */
        = ;        pos =3D bprm->p;
+           &nbs= p;   str +=3D len;
+       =         bprm->p -=3D len;

&nbs= p;            &= nbsp;  while (len > 0) {
-     &nb= sp;            =      int i, new, err;
     =             &nb= sp;      int offset, bytes_to_copy;
- = ;            &n= bsp;         struct page *page;

           &= nbsp;           &nbs= p;offset =3D pos % PAGE_SIZE;
-       = ;            &n= bsp;   i =3D pos/PAGE_SIZE;
-     &nb= sp;            =      page =3D bprm->page[i];
-   &= nbsp;           &nbs= p;       new =3D 0;
-   &nb= sp;            =        if (!page) {
-           &nbs= p;            &= nbsp;      page =3D alloc_page(GFP_HIGHUSER);
-=             &nb= sp;            =       bprm->page[i] =3D page;
-  &= nbsp;           &nbs= p;            &= nbsp;   if (!page) {
-      &nbs= p;            &= nbsp;           &nbs= p;       ret =3D -ENOMEM;
+           &nbs= p;           if (offset = =3D=3D 0)
+          &= nbsp;           &nbs= p;        offset =3D PAGE_SIZE;
+
= +            &n= bsp;          bytes_to_copy = =3D offset;
+          = ;             i= f (bytes_to_copy > len)
+       &n= bsp;            = ;           bytes_to_copy= =3D len;
+
+           = ;            offset = -=3D bytes_to_copy;
+        &nb= sp;            =   pos -=3D bytes_to_copy;
+      &nbs= p;            &= nbsp;   str -=3D bytes_to_copy;
+     = ;            &n= bsp;     len -=3D bytes_to_copy;
+
+  &= nbsp;           &nbs= p;        if (!kmapped_page || kpos !=3D= (pos & PAGE_MASK)) {
+           &nbs= p;            &= nbsp;      struct page *page;
+
+  = ;            &n= bsp;            = ;    ret =3D get_user_pages(current, bprm->mm, pos,
+&= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp; 1, 1, 1, &page, NULL);
+           &nbs= p;            &= nbsp;      if (ret <=3D 0) {
+  &n= bsp;            = ;            &n= bsp;           /* We'= ve exceed the stack rlimit. */
+      &nbs= p;            &= nbsp;           &nbs= p;       ret =3D -E2BIG;
   = ;            &n= bsp;            = ;            go= to out;
            = ;            &n= bsp;       }
-    = ;            &n= bsp;            = ;  new =3D 1;
-        &nbs= p;            &= nbsp; }

-          = ;             i= f (page !=3D kmapped_page) {
-       =             &nb= sp;           if (kmapped= _page)
+           &nbs= p;            &= nbsp;      if (kmapped_page) {
  &nbs= p;            &= nbsp;           &nbs= p;            k= unmap(kmapped_page);
+        &n= bsp;            = ;            &n= bsp;     put_page(kmapped_page);
+   =             &nb= sp;            =    }
            = ;            &n= bsp;       kmapped_page =3D page;
&nb= sp;            =             &nb= sp;      kaddr =3D kmap(kmapped_page);
+&n= bsp;            = ;            &n= bsp;     kpos =3D pos & PAGE_MASK;
  &= nbsp;           &nbs= p;         }
-  &= nbsp;           &nbs= p;        if (new && offset)
-           &nbs= p;            &= nbsp;      memset(kaddr, 0, offset);
- &nb= sp;            =          bytes_to_copy =3D PAGE_SIZ= E - offset;
-          = ;             i= f (bytes_to_copy > len) {
-       =             &nb= sp;           bytes_to_co= py =3D len;
-           &nbs= p;            &= nbsp;      if (new)
-    &n= bsp;            = ;            &n= bsp;         memset(kaddr+offset+le= n, 0,
-           = ;            &n= bsp;            = ;           PAGE_SIZE-off= set-len);
-          &= nbsp;            } -            &n= bsp;          err =3D copy_fro= m_user(kaddr+offset, compat_ptr(str),
-     &nb= sp;            =             &nb= sp;            =     bytes_to_copy);
-      =             &nb= sp;    if (err) {
+      &n= bsp;            = ;    if (copy_from_user(kaddr+offset, compat_ptr(str),
+           &nbs= p;            &= nbsp;           &nbs= p;          bytes_to_copy)) {<= br>            =             &nb= sp;       ret =3D -EFAULT;
 &nbs= p;            &= nbsp;           &nbs= p;     goto out;
     =             &nb= sp;      }
-
-    &= nbsp;           &nbs= p;      pos +=3D bytes_to_copy;
-           &nbs= p;           str +=3D byt= es_to_copy;
-          = ;             l= en -=3D bytes_to_copy;
        &= nbsp;       }
    = ;    }
       &nb= sp;ret =3D 0;
out:
-       if (kmapped= _page)
+       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 =3D 0; i < MAX_ARG_PAGES; i++) {
-&n= bsp;            = ;  if (bprm->page[i])
-       = ;            &n= bsp;   __free_page(bprm->page[i]);
-    = ;           bprm->page= [i] =3D NULL;
+           &nbs= p;   put_page(kmapped_page);
     &nb= sp;  }
+       return ret;
}=

-#endif /* CONFIG_MMU */
-
/*
  * compat_do_exe= cve() is mostly a copy of do_execve(), with the exception
  * = that it processes 32 bit argv and envp pointers.
@@ -1495,7 +1476,6 @@ int compat_do_execve(char * filename,
 &n= bsp;      struct linux_binprm *bprm;
 = ;       struct file *file;
 &nbs= p;      int retval;
-   &nb= sp;   int i;

       &nb= sp;retval =3D -ENOMEM;
        b= prm =3D kzalloc(sizeof(*bprm), GFP_KERNEL);
@@ -1509,24 +1489,19 @@ int compat_do_execve(char * filename,

&n= bsp;       sched_exec();

- &= nbsp;     bprm->p =3D PAGE_SIZE*MAX_ARG_PAGES-sizeof= (void *);
        bprm->file = =3D file;
        bprm->filen= ame =3D filename;
        bprm->interp =3D fil= ename;
-       bprm->mm =3D mm_alloc();=
-       retval =3D -ENOMEM;
- &nb= sp;     if (!bprm->mm)
-    &= nbsp;          goto out_file;<= br>
-       retval =3D init_new_context(cu= rrent, bprm->mm);
-       if (retval < 0)
- &nbs= p;             = goto out_mm;
+       retval =3D bprm_mm_in= it(bprm);
+       if (retval)
+ &n= bsp;            = ; goto out_file;

-       bprm->argc= =3D compat_count(argv, bprm->p / sizeof(compat_uptr_t));
+       bprm->argc =3D compat_count(ar= gv, MAX_ARG_STRINGS);
        if= ((retval =3D bprm->argc) < 0)
      = ;          goto out_mm;
-       bprm->envc =3D compat_count(= envp, bprm->p / sizeof(compat_uptr_t));
+       bprm->envc =3D compat_count(en= vp, MAX_ARG_STRINGS);
        if= ((retval =3D bprm->envc) < 0)
      = ;          goto out_mm;
@@ -1551,10 +1526,8 @@ int compat_do_execve(char * filename,
 = ;       if (retval < 0)
            = ;    goto out;

-     &n= bsp; retval =3D search_binary_handler(bprm, regs);
+   &n= bsp;   retval =3D search_binary_handler(bprm,regs);
 &nbs= p;      if (retval >=3D 0) {
- &nb= sp;            = free_arg_pages(bprm);
-
            = ;    /* execve success */
    &n= bsp;           secur= ity_bprm_free(bprm);
        &nb= sp;       acct_update_integrals(current)= ;
@@ -1563,19 +1536,12 @@ int compat_do_execve(char * filename,
 = ;       }

out:
-       /* Something went wrong, ret= urn the inode and free the argument pages*/
-    &nb= sp;  for (i =3D 0 ; i < MAX_ARG_PAGES ; i++) {
-  &nbs= p;            struct= page * page =3D bprm->page[i];
-      =          if (page)
-           &nbs= p;           __free_page(= page);
-       }
-
   = ;     if (bprm->security)
   =             &nb= sp;security_bprm_free(bprm);

out_mm:
    &nb= sp;   if (bprm->mm)
-     &nb= sp;         mmdrop(bprm->mm);
+           &nbs= p;   mmput (bprm->mm);

out_file:
   =      if (bprm->file) {
Index: linux/fs/exec.= c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- linux.orig= /fs/exec.c
+++ linux/fs/exec.c
@@ -174,6 +174,79 @@ exit:
       = ; goto out;
}

+#ifdef CONFIG_STACK_GROWSUP
+#error I bro= ke your build because I rearchitected the stack code, and I \
+ &nb= sp;     don't have access to an architecture where = CONFIG_STACK_GROWSUP is \
+       set.  Please fixe this = or send me a machine which I can test this on. \
+   &nbs= p;   \
+       -- Ollie Wild <= ;aaw@google.com>
+#endif
++/* Create a new mm_struct and populate it with a temporary stack
+ * vm_area_struct.  We don't have enough context at this= point to set the
+ * stack flags, permissions, and offset, so we use te= mporary values.  We'll
+ * update them later in setup_arg_= pages(). */
+int bprm_mm_init(struct linux_binprm *bprm)
+{
+       int err;
+  &n= bsp;    struct mm_struct *mm =3D NULL;
+   = ;    struct vm_area_struct *vma =3D NULL;
+
+ &nb= sp;     bprm->mm =3D mm =3D mm_alloc();
+ &n= bsp;     err =3D -ENOMEM;
+    &= nbsp;  if (!mm)
+        &n= bsp;      goto err;
+
+       if ((err =3D init_new_contex= t(current, mm)))
+         =       goto err;
+
+    &= nbsp;  bprm->vma =3D vma =3D kmem_cache_zalloc(vm_area_cachep, GFP_= KERNEL);
+       err =3D -ENOMEM;
+&nbs= p;      if (!vma)
+            &n= bsp;  goto err;
+
+       down_wri= te(&mm->mmap_sem);
+       {
+&n= bsp;            = ;  vma->vm_mm =3D mm;
+
+      =          /* Place the stack at the = top of user memory.  Later, we'll
+    = ;            * = move this to an appropriate place.  We don't use STACK_TOP
+           &nbs= p;    * because that can depend on attributes which are= n't
+          &nb= sp;     * configured yet. */
+   = ;            vma->= ;vm_end =3D TASK_SIZE;
+        =        vma->vm_start =3D vma->vm_end - = PAGE_SIZE;
+
+           = ;    vma->vm_flags =3D VM_STACK_FLAGS;
+  &n= bsp;            vma-= >vm_page_prot =3D protection_map[vma->vm_flags & 0x7];
+ =             &nb= sp; if ((err =3D insert_vm_struct(mm, vma))) {
+    =             &nb= sp;      up_write(&mm->mmap_sem);
+           &nbs= p;           goto err;+            &= nbsp;  }
+
+        &nbs= p;      mm->stack_vm =3D mm->total_vm =3D 1;=
+       }
+    &nb= sp;  up_write(&mm->mmap_sem);
+
+    =    bprm->p =3D vma->vm_end - sizeof(void *);
+
+       return 0;
+
+err:
+=        if (vma) {
+    = ;           bprm->vma = =3D NULL;
+          &= nbsp;    kmem_cache_free(vm_area_cachep, vma);
+ &nb= sp;     }
+
+      = if (mm) {
+          =      bprm->mm =3D NULL;
+           &nbs= p;   mmdrop(mm);
+       }
+<= br>+       return err;
+}
+
+EXPORT_= SYMBOL(bprm_mm_init);
+
/*
  * count() counts the numbe= r of strings in array ARGV.
  */
@@ -199,15 +272,16 @@ stat= ic int count(char __user * __user *
}

/*
- * 'copy_strings()' copies argument/environme= nt strings from user
- * memory to free pages in kernel mem. These are i= n a format ready
- * to be put directly into the top of new user memory.
+ * 'copy_strings()' copies argument/environment strings from t= he old
+ * processes's memory to the new process's stack. &= nbsp;The call to get_user_pages()
+ * ensures the destination page is cr= eated and not swapped out.
  */
static int copy_strings(int argc, char __user * __us= er * argv,
          &= nbsp;           &nbs= p; struct linux_binprm *bprm)
{
     &= nbsp;  struct page *kmapped_page =3D NULL;
   &= nbsp;    char *kaddr =3D NULL;
+   &n= bsp;   unsigned long kpos =3D 0;
        int ret;

 &= nbsp;      while (argc-- > 0) {
@@ -216= ,69 +290,68 @@ static int copy_strings(int argc, char _
  &nbs= p;            &= nbsp;unsigned long pos;

       &n= bsp;        if (get_user(str, argv+= argc) ||
-            &n= bsp;            = ;      !(len =3D strnlen_user(str, bprm->p))) {=
+           &nbs= p;            &= nbsp;      !(len =3D strnlen_user(str, MAX_ARG_STR= LEN))) {
          &nb= sp;            =  ret =3D -EFAULT;
        &= nbsp;           &nbs= p;   goto out;
            = ;    }

-      &nbs= p;        if (bprm->p < len) =  {
+          &nb= sp;    if (MAX_ARG_STRLEN < len) {
   &= nbsp;           &nbs= p;        ret =3D -E2BIG;
 =             &nb= sp;          goto out;            &n= bsp;   }

-           =     bprm->p -=3D len;
-     &= nbsp;         /* XXX: add architect= ure specific overflow check here. */
+     &nbs= p;         /* We're going to wo= rk our way backwords. */
        = ;        pos =3D bprm->p;
+           &nbs= p;   str +=3D len;
+       =         bprm->p -=3D len;

&nbs= p;            &= nbsp;  while (len > 0) {
-     &nb= sp;            =      int i, new, err;
     =             &nb= sp;      int offset, bytes_to_copy;
- = ;            &n= bsp;         struct page *page;

           &= nbsp;           &nbs= p;offset =3D pos % PAGE_SIZE;
-       = ;            &n= bsp;   i =3D pos/PAGE_SIZE;
-     &nb= sp;            =      page =3D bprm->page[i];
-   &= nbsp;           &nbs= p;       new =3D 0;
-   &nb= sp;            =        if (!page) {
-           &nbs= p;            &= nbsp;      page =3D alloc_page(GFP_HIGHUSER);
-=             &nb= sp;            =       bprm->page[i] =3D page;
-  &= nbsp;           &nbs= p;            &= nbsp;   if (!page) {
-      &nbs= p;            &= nbsp;           &nbs= p;       ret =3D -ENOMEM;
+           &nbs= p;           if (offset = =3D=3D 0)
+          &= nbsp;           &nbs= p;        offset =3D PAGE_SIZE;
+
= +            &n= bsp;          bytes_to_copy = =3D offset;
+          = ;             i= f (bytes_to_copy > len)
+       &n= bsp;            = ;           bytes_to_copy= =3D len;
+
+           = ;            offset = -=3D bytes_to_copy;
+        &nb= sp;            =   pos -=3D bytes_to_copy;
+      &nbs= p;            &= nbsp;   str -=3D bytes_to_copy;
+     = ;            &n= bsp;     len -=3D bytes_to_copy;
+
+  &= nbsp;           &nbs= p;        if (!kmapped_page || kpos !=3D= (pos & PAGE_MASK)) {
+           &nbs= p;            &= nbsp;      struct page *page;
+
+  = ;            &n= bsp;            = ;    ret =3D get_user_pages(current, bprm->mm, pos,
+&= nbsp;           &nbs= p;            &= nbsp;           &nbs= p;            &= nbsp; 1, 1, 1, &page, NULL);
+           &nbs= p;            &= nbsp;      if (ret <=3D 0) {
+  &n= bsp;            = ;            &n= bsp;           /* We'= ve exceed the stack rlimit. */
+      &nbs= p;            &= nbsp;           &nbs= p;       ret =3D -E2BIG;
   = ;            &n= bsp;            = ;            go= to out;
            = ;            &n= bsp;       }
-    = ;            &n= bsp;            = ;  new =3D 1;
-        &nbs= p;            &= nbsp; }

-          = ;             i= f (page !=3D kmapped_page) {
-       =             &nb= sp;           if (kmapped= _page)
+           &nbs= p;            &= nbsp;      if (kmapped_page) {
  &nbs= p;            &= nbsp;           &nbs= p;            k= unmap(kmapped_page);
+        &n= bsp;            = ;            &n= bsp;     put_page(kmapped_page);
+   =             &nb= sp;            =    }
            = ;            &n= bsp;       kmapped_page =3D page;
&nb= sp;            =             &nb= sp;      kaddr =3D kmap(kmapped_page);
+&n= bsp;            = ;            &n= bsp;     kpos =3D pos & PAGE_MASK;
  &= nbsp;           &nbs= p;         }
-  &= nbsp;           &nbs= p;        if (new && offset)
-           &nbs= p;            &= nbsp;      memset(kaddr, 0, offset);
- &nb= sp;            =          bytes_to_copy =3D PAGE_SIZ= E - offset;
-          = ;             i= f (bytes_to_copy > len) {
-       =             &nb= sp;           bytes_to_co= py =3D len;
-           &nbs= p;            &= nbsp;      if (new)
-    &n= bsp;            = ;            &n= bsp;         memset(kaddr+offset+le= n, 0,
-           = ;            &n= bsp;            = ;           PAGE_SIZE-off= set-len);
-          &= nbsp;            } -            &n= bsp;          err =3D copy_fro= m_user(kaddr+offset, str, bytes_to_copy);
-     = ;            &n= bsp;     if (err) {
+     &= nbsp;           &nbs= p;     if (copy_from_user(kaddr+offset, str, bytes_to_c= opy)) {
          &nbs= p;            &= nbsp;        ret =3D -EFAULT;
            = ;            &n= bsp;       goto out;
  &nbs= p;            &= nbsp;        }
-
-  = ;            &n= bsp;        pos +=3D bytes_to_copy;
-=             &nb= sp;          str +=3D bytes_to= _copy;
-          &nbs= p;            len -= =3D bytes_to_copy;
            = ;    }
       &nb= sp;}
        ret =3D 0;
out:=
-       if (kmapped_page)
+  = ;     if (kmapped_page) {
    &n= bsp;           kunma= p(kmapped_page);
+         =       put_page(kmapped_page);
+  &nbs= p;    }
        return ret;
}

@@= -297,157 +370,79 @@ int copy_strings_kernel(int argc,char **

EXPOR= T_SYMBOL(copy_strings_kernel);

-#ifdef CONFIG_MMU
-/*
- * This= routine is used to map in a page into an address space: needed by
- * execve() for the initial stack and environment pages.
- *
- *= vma->vm_mm->mmap_sem is held for writing.
- */
-void install_a= rg_page(struct vm_area_struct *vma,
-      = ;            &n= bsp;    struct page *page, unsigned long address)
-{
-       struct mm_struct *mm =3D vm= a->vm_mm;
-       pte_t * pte;
-&nbs= p;      spinlock_t *ptl;
-
-  &nbs= p;    if (unlikely(anon_vma_prepare(vma)))
-  &= nbsp;            got= o out;
-
-       flush_dcache_page(page= );
-       pte =3D get_locked_pte(mm, addres= s, &ptl);
-       if (!pte)
- =             &nb= sp; goto out;
-       if (!pte_none(*pte))= {
-           &n= bsp;   pte_unmap_unlock(pte, ptl);
-    &n= bsp;          goto out;
-&n= bsp;      }
-       inc_mm_counter(mm, anon_rss);
= -       lru_cache_add_active(page);
- = ;      set_pte_at(mm, address, pte, pte_mkdirty(pt= e_mkwrite(mk_pte(
-         = ;            &n= bsp;            = ;     page, vma->vm_page_prot))));
-       page_add_new_anon_rmap(page, vma,= address);
-       pte_unmap_unlock(pte, p= tl);
-
-       /* no need for flush_tlb= */
-       return;
-out:
- &nb= sp;     __free_page(page);
-    =    force_sig(SIGKILL, current);
-}
-
#define EXTRA_STACK_VM_PAGES   20  &nbs= p;   /* random */

+/* Finalizes the stack vm_area_str= uct.  The flags and permissions are updated,
+ * the stack is = optionally relocated, and some extra space is added.
+ */
int setup_arg_pages(struct linux_binprm *bprm,
  =             &nb= sp;     unsigned long stack_top,
  &n= bsp;            = ;     int executable_stack)
{
-  =      unsigned long stack_base;
-   &n= bsp;   struct vm_area_struct *mpnt;
+       unsigned long ret;
+ &nbs= p;     unsigned long stack_base, stack_shift;
 =        struct mm_struct *mm =3D current-= >mm;
-       int i, ret;
- &nbs= p;     long arg_size;

-#ifdef CONFIG_STACK_GROWS= UP
-       /* Move the argument and enviro= nment strings to the bottom of the
-        * stack space.
-&nb= sp;       */
-    = ;   int offset, j;
-       char = *to, *from;
+       BUG_ON(stack_top > = TASK_SIZE);
+       BUG_ON(stack_top &= ~PAGE_MASK);

-       /* Start by shif= ting all the pages down */
-       i =3D 0;
-   &n= bsp;   for (j =3D 0; j < MAX_ARG_PAGES; j++) {
-  = ;             s= truct page *page =3D bprm->page[j];
-     &n= bsp;         if (!page)
- &= nbsp;           &nbs= p;         continue;
- &nbs= p;             = bprm->page[i++] =3D page;
-       }
-
-   &nbs= p;   /* Now move them within their pages */
-   = ;    offset =3D bprm->p % PAGE_SIZE;
-  &nbs= p;    to =3D kmap(bprm->page[0]);
-   &= nbsp;   for (j =3D 1; j < i; j++) {
-   &nbs= p;           memmove(to, = to + offset, PAGE_SIZE - offset);
-           &nbs= p;   from =3D kmap(bprm->page[j]);
-    = ;           memcpy(to + P= AGE_SIZE - offset, from, offset);
-      &= nbsp;        kunmap(bprm->page[j - 1]= );
-           &n= bsp;   to =3D from;
-       }-       memmove(to, to + offset, PAGE_SIZE -= offset);
-       kunmap(bprm->page[j - 1]);
= -
-       /* Limit stack size to 1GB */-       stack_base =3D current->signal-&g= t;rlim[RLIMIT_STACK].rlim_max;
-       if = (stack_base > (1 << 30))
-      &= nbsp;        stack_base =3D 1 << 3= 0;
-       stack_base =3D PAGE_ALIGN(stack_t= op - stack_base);
-
-       /* Adjust b= prm->p to point to the end of the strings. */
-   &nbs= p;   bprm->p =3D stack_base + PAGE_SIZE * i - offset;
-
= -       mm->arg_start =3D stack_base;
-       arg_size =3D i << PAGE_SHIF= T;
-
-       /* zero pages that were co= pied above */
-       while (i < MAX_AR= G_PAGES)
-          &n= bsp;    bprm->page[i++] =3D NULL;
-#else
- &nb= sp;     stack_base =3D arch_align_stack(stack_top - MAX= _ARG_PAGES*PAGE_SIZE);
+       stack_base =3D arch_align_stack(s= tack_top - mm->stack_vm*PAGE_SIZE);
     &nb= sp;  stack_base =3D PAGE_ALIGN(stack_base);
-   = ;    bprm->p +=3D stack_base;
-    = ;   mm->arg_start =3D bprm->p;
-    =    arg_size =3D stack_top - (PAGE_MASK & (unsigned long) mm-&= gt;arg_start);
-#endif

-       arg_size +=3D EXTR= A_STACK_VM_PAGES * PAGE_SIZE;
+       stac= k_shift =3D (bprm->p & PAGE_MASK) - stack_base;
+  &nbs= p;    BUG_ON(stack_shift < 0);
+   &nbs= p;   bprm->p -=3D stack_shift;
+       mm->arg_start =3D bprm->p;
<= br>        if (bprm->loader)
= -            &n= bsp;  bprm->loader +=3D stack_base;
-    &nb= sp;  bprm->exec +=3D stack_base;
-
-    &= nbsp;  mpnt =3D kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
-       if (!mpnt)
-   =             return -= ENOMEM;
-
-       memset(mpnt, 0, sizeo= f(*mpnt));
+          =      bprm->loader -=3D stack_shift;
+  =      bprm->exec -=3D stack_shift;

  = ;      down_write(&mm->mmap_sem);
        {
-   = ;            mpnt-&g= t;vm_mm =3D mm;
-#ifdef CONFIG_STACK_GROWSUP
-    = ;           mpnt->vm_s= tart =3D stack_base;
-        &n= bsp;      mpnt->vm_end =3D stack_base + arg_siz= e;
-#else
-         &nbs= p;     mpnt->vm_end =3D stack_top;
-           &nbs= p;   mpnt->vm_start =3D mpnt->vm_end - arg_size;
-#endif=
+           &nbs= p;   struct vm_area_struct *vma =3D bprm->vma;
+  = ;             s= truct vm_area_struct *prev =3D NULL;
+     &nbs= p;         unsigned long vm_flags = =3D vma->vm_flags;
+
           =      /* Adjust stack execute permissions; explicit= ly enable
          &n= bsp;      * for EXSTACK_ENABLE_X, disable for EXST= ACK_DISABLE_X
         &nbs= p;       * and leave alone (arch default) oth= erwise. */
            &nb= sp;   if (unlikely(executable_stack =3D=3D EXSTACK_ENABLE_X)= )
-           &nb= sp;           mpnt->vm= _flags =3D VM_STACK_FLAGS |  VM_EXEC;
+    = ;            &n= bsp;      vm_flags |=3D VM_EXEC;
  &n= bsp;            = ; else if (executable_stack =3D=3D EXSTACK_DISABLE_X)
-           &nbs= p;           mpnt->vm_= flags =3D VM_STACK_FLAGS & ~VM_EXEC;
-     =           else
-  = ;            &n= bsp;        mpnt->vm_flags =3D VM_STA= CK_FLAGS;
-          &= nbsp;    mpnt->vm_flags |=3D mm->def_flags;
-           &nbs= p;   mpnt->vm_page_prot =3D protection_map[mpnt->vm_flags &= amp; 0x7];
-          =      if ((ret =3D insert_vm_struct(mm, mpnt))) {
+&n= bsp;            = ;          vm_flags &=3D ~= VM_EXEC;
+          &n= bsp;    vm_flags |=3D mm->def_flags;
+
+           = ;    ret =3D mprotect_fixup(vma, &prev, vma->vm_start= , vma->vm_end,
+         = ;            &n= bsp;         vm_flags);
+ &= nbsp;           &nbs= p; if (ret) {
         &nbs= p;            &= nbsp; up_write(&mm->mmap_sem);
-           &nbs= p;           kmem_cache_f= ree(vm_area_cachep, mpnt);
       &nb= sp;            =     return ret;
      =           }
- &nb= sp;            = mm->stack_vm =3D mm->total_vm =3D vma_pages(mpnt);
-  &= nbsp;    }
+       &nb= sp;       BUG_ON(prev !=3D vma);
+
+           = ;    /* Move stack pages down in memory. */
+  =              if= (stack_shift) {
+         =             &nb= sp; /* This should be safe even with overlap because we
+  &nb= sp;            =          * are shifting down. = */
+           &nbs= p;           ret =3D move= _vma(vma, vma->vm_start,
+       &= nbsp;           &nbs= p;            &= nbsp;      vma->vm_end - vma->vm_start,
+=             &nb= sp;            =             &nb= sp; vma->vm_end - vma->vm_start,
+           &nbs= p;            &= nbsp;           &nbs= p;  vma->vm_start - stack_shift);
+     = ;            &n= bsp;     if (ret & ~PAGE_MASK) {
+  &n= bsp;            = ;            &n= bsp;   up_write(&mm->mmap_sem);
+   &nbs= p;            &= nbsp;           &nbs= p;  return ret;
+           &nbs= p;           }
+ =             &nb= sp; }

-       for (i =3D 0 ; i < MA= X_ARG_PAGES ; i++) {
-        &n= bsp;      struct page *page =3D bprm->page[i];<= br>-            = ;   if (page) {
-       &nb= sp;            =    bprm->page[i] =3D NULL;
-           &nbs= p;           install_arg_= page(mpnt, page, stack_base);
+       = ;        // Expand the stack.
+ =             &nb= sp; vma =3D find_vma(mm, bprm->p);
+     &nb= sp;         BUG_ON(!vma || bprm->= ;p < vma->vm_start);
+           &nbs= p;   if (expand_stack(vma, stack_base -
+   &nb= sp;            =             &nb= sp;          EXTRA_STACK_VM_PA= GES * PAGE_SIZE)) {
+        &nb= sp;            =   up_write(&mm->mmap_sem);
+     &n= bsp;            = ;     return -EFAULT;
            = ;    }
-       &n= bsp;       stack_base +=3D PAGE_SIZE;
&nbs= p;       }
    &n= bsp;   up_write(&mm->mmap_sem);

@@ -456,23 +45= 1,6 @@ int setup_arg_pages(struct linux_binprm

EXPORT_SYMBOL(setup_= arg_pages);

-#define free_arg_pages(bprm) do { } while (0)
-
-#else
-<= br>-static inline void free_arg_pages(struct linux_binprm *bprm)
-{
-=        int i;
-
-   &nbs= p;   for (i =3D 0; i < MAX_ARG_PAGES; i++) {
-            &n= bsp;  if (bprm->page[i])
-      &n= bsp;            = ;    __free_page(bprm->page[i]);
-   &n= bsp;           bprm->p= age[i] =3D NULL;
-       }
-}
-
-= #endif /* CONFIG_MMU */
-
struct file *open_exec(const char *name)
{
        struct nameidata = nd;
@@ -993,8 +971,10 @@ void compute_creds(struct linux_binprm *
EXPORT_SYMBOL(compute_creds);

-void remove_arg_zero(struct linux_b= inprm *bprm)
+int remove_arg_zero(struct linux_binprm *bprm)
{
+       int ret =3D 0;
+
&nbs= p;       if (bprm->argc) {
 &= nbsp;           &nbs= p;  unsigned long offset;
      =           char * kaddr;@@ -1008,13 +988,23 @@ void remove_arg_zero(struct linux_binprm
 =             &nb= sp;            =       continue;
            = ;            of= fset =3D 0;
          =             &nb= sp; kunmap_atomic(kaddr, KM_USER0);
+     =             &nb= sp;     put_page(page);
inside:
-  &nb= sp;            =         page =3D bprm->page[bprm->= p/PAGE_SIZE];
+           &nbs= p;           ret =3D get_= user_pages(current, bprm->mm, bprm->p,
+    &n= bsp;            = ;            &n= bsp;            = ;  1, 0, 1, &page, NULL);
+     &= nbsp;           &nbs= p;     if (ret <=3D 0) {
+    = ;            &n= bsp;            = ;  ret =3D -EFAULT;
+           &nbs= p;            &= nbsp;      goto out;
+    &= nbsp;           &nbs= p;      }
      &= nbsp;           &nbs= p;     kaddr =3D kmap_atomic(page, KM_USER0);
&= nbsp;           &nbs= p;   }
        &n= bsp;       kunmap_atomic(kaddr, KM_USER0= );
           &nb= sp;    bprm->argc--;
+           &nbs= p;   ret =3D 0;
       &nbs= p;}
+
+out:
+       return ret;
= }

EXPORT_SYMBOL(remove_arg_zero);
@@ -1041,7 +1031,7 @@ int sear= ch_binary_handler(struct linux_b
      &nb= sp;         fput(bprm->file= );
            = ;    bprm->file =3D NULL;

-   =             loader = =3D PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+    &nb= sp;          loader =3D bprm-&= gt;vma->vm_end - sizeof(void *);

     &n= bsp;          file =3D op= en_exec("/sbin/loader");
            = ;    retval =3D PTR_ERR(file);
@@ -1134,7 +1124,6 @@= int do_execve(char * filename,
      &nbs= p; struct linux_binprm *bprm;
      &= nbsp; struct file *file;
       =  int retval;
-       int i;

&n= bsp;       retval =3D -ENOMEM;
        bprm =3D kzalloc(sizeof= (*bprm), GFP_KERNEL);
@@ -1148,25 +1137,19 @@ int do_execve(char * filen= ame,

        sched_exec();
-       bprm->p =3D PAGE_SIZE*MAX_AR= G_PAGES-sizeof(void *);
-
       &= nbsp;bprm->file =3D file;
        bprm->filename =3D f= ilename;
        bprm->interp= =3D filename;
-       bprm->mm =3D mm_= alloc();
-       retval =3D -ENOMEM;
-&= nbsp;      if (!bprm->mm)
-   = ;            goto ou= t_file;

-       retval =3D init_new_co= ntext(current, bprm->mm);
-       if (retval < 0)
- &nbs= p;             = goto out_mm;
+       retval =3D bprm_mm_in= it(bprm);
+       if (retval)
+ &n= bsp;            = ; goto out_file;

-       bprm->argc= =3D count(argv, bprm->p / sizeof(void *));
+       bprm->argc =3D count(argv, MAX= _ARG_STRINGS);
        if ((retv= al =3D bprm->argc) < 0)
       =          goto out_mm;

-=        bprm->envc =3D count(envp, bprm->= ;p / sizeof(void *));
+       bprm->env= c =3D count(envp, MAX_ARG_STRINGS);
        if ((retval =3D bprm-&g= t;envc) < 0)
         &n= bsp;      goto out_mm;

@@ -1193,8 +117= 6,6 @@ int do_execve(char * filename,

     =    retval =3D search_binary_handler(bprm,regs);
 &nb= sp;      if (retval >=3D 0) {
-           &nbs= p;   free_arg_pages(bprm);
-
     =            /* execve= success */
          =       security_bprm_free(bprm);
 &nbs= p;            &= nbsp; acct_update_integrals(current);
@@ -1203,19 +1184,12 @@ int d= o_execve(char * filename,
        }

out:
-&nbs= p;      /* Something went wrong, return the inode = and free the argument pages*/
-       for = (i =3D 0 ; i < MAX_ARG_PAGES ; i++) {
-     =           struct page * page = =3D bprm->page[i];
-           &nbs= p;   if (page)
-       &nbs= p;            &= nbsp;  __free_page(page);
-       }-
        if (bprm->securit= y)
           &nb= sp;    security_bprm_free(bprm);

out_mm:
&nb= sp;       if (bprm->mm)
- &nb= sp;            = mmdrop(bprm->mm);
+           &nbs= p;   mmput (bprm->mm);

out_file:
   =      if (bprm->file) {
Index: linux/include/= linux/binfmts.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D--- linux.orig/include/linux/binfmts.h
+++ linux/include/linux/binfmts.h
@@ -5,12 +5,9 @@

struct pt= _regs;

-/*
- * MAX_ARG_PAGES defines the number of pages allocate= d 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
+/* FIXME: Find real limits, or none. */
+#define MAX_ARG_S= TRLEN (PAGE_SIZE * 32)
+#define MAX_ARG_STRINGS 0x7FFFFFFF

/* si= zeof(linux_binprm->buf) */
#define BINPRM_BUF_SIZE 128
@@ -22,7 +19,7 @@ struct pt_regs;
&n= bsp; */
struct linux_binprm{
     &nbs= p;  char buf[BINPRM_BUF_SIZE];
-     =   struct page *page[MAX_ARG_PAGES];
+     =   struct vm_area_struct *vma;
        struct mm_struct *mm;        unsigned long p; /* curre= nt top of mem */
        int sh_= bang;
@@ -65,7 +62,7 @@ extern int register_binfmt(struct linux_
ext= ern int unregister_binfmt(struct linux_binfmt *);

extern int prepare_binprm(struct linux_binprm *);
-extern void = remove_arg_zero(struct linux_binprm *);
+extern int __must_check remove_= arg_zero(struct linux_binprm *);
extern int search_binary_handler(struc= t linux_binprm *,struct pt_regs *);
extern int flush_old_exec(struct linux_binprm * bprm);

@@ -82,6= +79,7 @@ extern int suid_dumpable;
extern int setup_arg_pages(struct l= inux_binprm * bprm,
        &nbs= p;            &= nbsp;     unsigned long stack_top,
            = ;            &n= bsp;  int executable_stack);
+extern int bprm_mm_init(struct linux_= binprm *bprm);
extern int copy_strings_kernel(int argc,char ** argv,str= uct linux_binprm *bprm);
extern void compute_creds(struct linux_binprm = *binprm);
extern int do_coredump(long signr, int exit_code, struct pt_regs * reg= s);
Index: linux/include/linux/mm.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D
--- linux.orig/include/linux/mm.h
+++ linux/include/linux/mm.h
@@ -775,7 +775,6 @@ static inline int h= andle_mm_fault(struct

extern int make_pages_present(unsigned long a= ddr, unsigned long end);
extern int access_process_vm(struct task_struc= t *tsk, unsigned long addr, void *buf, int len, int write);
-void install_arg_page(struct vm_area_struct *, struct page *, unsigned= long);

int get_user_pages(struct task_struct *tsk, struct mm_struc= t *mm, unsigned long start,
       &n= bsp;        int len, int write, int= force, struct page **pages, struct vm_area_struct **vmas);
@@ -791,9 +790,15 @@ int FASTCALL(set_page_dirty(struct page
int se= t_page_dirty_lock(struct page *page);
int clear_page_dirty_for_io(struc= t page *page);

+extern unsigned long move_vma(struct vm_area_struct = *vma,
+           &nbs= p;   unsigned long old_addr, unsigned long old_len,
+ &nb= sp;            = unsigned long new_len, unsigned long new_addr);
extern unsigned long d= o_mremap(unsigned long addr,
       &= nbsp;           &nbs= p;           unsigned lon= g old_len, unsigned long new_len,
            = ;            &n= bsp;      unsigned long flags, unsigned long new_a= ddr);
+extern int mprotect_fixup(struct vm_area_struct *vma,
+ &= nbsp;           &nbs= p;           struct vm_ar= ea_struct **pprev, unsigned long start,
+            &n= bsp;            unsi= gned long end, unsigned long newflags);

/*
  * Prototy= pe to add a shrinker callback for ageable caches.
Index: linux/kernel/au= ditsc.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- linux.orig/kernel/auditsc.c
+++ linux/kernel/auditsc.c
@@ -17= 55,6 +1755,10 @@ int __audit_ipc_set_perm(unsigned long q

int audit= _bprm(struct linux_binprm *bprm)
{
+     &n= bsp; /* FIXME: Don't do anything for now until I figure out how to hand= le
+        * this.  Wit= h the latest changes, kmalloc could well fail under good
+  &n= bsp;     * scenarios. */
+#if 0
  =       struct audit_aux_data_execve *ax;
&n= bsp;       struct audit_context *context= =3D current->audit_context;
        unsigned long p, next;<= br>@@ -1782,6 +1786,7 @@ int audit_bprm(struct linux_binprm *bprm
 =        ax->d.type =3D AUDIT_EXECVE;        ax->d.next =3D context= ->aux;
        context->au= x =3D (void *)ax;
+#endif
        return 0; }

Index: linux/mm/mprotect.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D
--- linux.orig/mm/mprotect.c
+++ linux/mm/mprotect= .c
@@ -128,7 +128,7 @@ static void change_protection(struct vm_
        flush_tlb_range(vma, st= art, end);
}

-static int
+int
mprotect_fixup(struct vm_ar= ea_struct *vma, struct vm_area_struct **pprev,
    &= nbsp;   unsigned long start, unsigned long end, unsigned lon= g newflags)
{
Index: linux/mm/mremap.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D
--- linux.orig/mm/mremap.c
+++ linux/mm/mremap.c
@= @ -155,7 +155,7 @@ static unsigned long move_page_tables(st
        return len + old_addr -= old_end;        /* how much done *= /
}

-static unsigned long move_vma(struct vm_area_struct *vma,+unsigned long move_vma(struct vm_area_struct *vma,
   =             &nb= sp;unsigned long old_addr, unsigned long old_len,
            = ;    unsigned long new_len, unsigned long new_addr)
= {

------=_Part_147502_21702467.1167634300468-- --===============0310451956== Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ parisc-linux mailing list parisc-linux@lists.parisc-linux.org http://lists.parisc-linux.org/mailman/listinfo/parisc-linux --===============0310451956==--