no MAX_ARG_PAGES -v2
Subsystems (9)
cover no MAX_ARG_PAGES -v2
This patch-set aims at removing the current limit on argv+env space aka. MAX_ARG_PAGES.
The new mm is created before the binfmt code runs, the stack is placed at the highest address supported by that architecture.
The argv+env data is then copied from the old mm into the new mm (which is inactive at that time - this introduces some cache coherency issues).
Then we run the binfmt code, which will compute the final stack address. The existing stack will be moved downwards (or upwards on PA-RISC) to the desired place.
This 'trick' heavily relies on the MMU, so for no-MMU archs we stay with the old approach.
---
Plenty of changes all around, changes listed in the individual patches. We hope to have addressed all issues raised.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/3 arch: personality independent stack top
New arch macro STACK_TOP_MAX it gives the larges valid stack address for the architecture in question.
It differs from STACK_TOP in that it will not distinguish between personalities but will always return the largest possible address.
This is used to create the initial stack on execve, which we will move down to the proper location once the binfmt code has figured out where that is.
---
Changes
- small fix to UML
include/asm-alpha/a.out.h | 2 ++ include/asm-arm/a.out.h | 1 + include/asm-arm26/a.out.h | 1 + include/asm-avr32/a.out.h | 1 + include/asm-cris/a.out.h | 1 + include/asm-frv/mem-layout.h | 1 + include/asm-h8300/a.out.h | 1 + include/asm-i386/a.out.h | 1 + include/asm-ia64/ustack.h | 1 + include/asm-m32r/a.out.h | 1 + include/asm-m68k/a.out.h | 1 + include/asm-mips/a.out.h | 1 + include/asm-parisc/a.out.h | 1 + include/asm-powerpc/a.out.h | 3 +++ include/asm-s390/a.out.h | 1 + include/asm-sh/a.out.h | 1 + include/asm-sh64/a.out.h | 1 + include/asm-sparc/a.out.h | 1 + include/asm-sparc64/a.out.h | 2 ++ include/asm-um/a.out.h | 3 +++ include/asm-x86_64/a.out.h | 3 ++- include/asm-xtensa/a.out.h | 1 + 22 files changed, 29 insertions(+), 1 deletion(-)
include/asm-alpha/a.out.h +2 -0
@@ -101,6 +101,8 @@ struct exec#define STACK_TOP \ (current->personality & ADDR_LIMIT_32BIT ? 0x80000000 : 0x00120000000UL) +#define STACK_TOP_MAX 0x00120000000UL +#endif #endif /* __A_OUT_GNU_H__ */
include/asm-arm/a.out.h +1 -0
@@ -30,6 +30,7 @@ struct exec#ifdef __KERNEL__#define STACK_TOP ((current->personality == PER_LINUX_32BIT) ? \ TASK_SIZE : TASK_SIZE_26) +#define STACK_TOP_MAX TASK_SIZE#endif #ifndef LIBRARY_START_TEXT
include/asm-arm26/a.out.h +1 -0
@@ -29,6 +29,7 @@ struct exec#ifdef __KERNEL__#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOP#endif #ifndef LIBRARY_START_TEXT
include/asm-avr32/a.out.h +1 -0
@@ -20,6 +20,7 @@ struct exec#ifdef __KERNEL__#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOP#endif
include/asm-cris/a.out.h +1 -0
@@ -8,6 +8,7 @@/* grabbed from the intel stuff */ #define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOPstruct exec
include/asm-frv/mem-layout.h +1 -0
@@ -60,6 +60,7 @@*/ #define BRK_BASE __UL(2 * 1024 * 1024 + PAGE_SIZE)#define STACK_TOP __UL(2 * 1024 * 1024) +#define STACK_TOP_MAX STACK_TOP/* userspace process size */ #ifdef CONFIG_MMU
include/asm-h8300/a.out.h +1 -0
@@ -20,6 +20,7 @@ struct exec#ifdef __KERNEL__#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOP#endif
include/asm-i386/a.out.h +1 -0
@@ -20,6 +20,7 @@ struct exec#ifdef __KERNEL__#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOP#endif
include/asm-ia64/ustack.h +1 -0
@@ -11,6 +11,7 @@/* The absolute hard limit for stack size is 1/2 of the mappable space in the region */ #define MAX_USER_STACK_SIZE (RGN_MAP_LIMIT/2)#define STACK_TOP (0x6000000000000000UL + RGN_MAP_LIMIT) +#define STACK_TOP_MAX STACK_TOP#endif /* Make a default stack size of 2GiB */
include/asm-m32r/a.out.h +1 -0
@@ -20,6 +20,7 @@ struct exec#ifdef __KERNEL__#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOP#endif
include/asm-m68k/a.out.h +1 -0
@@ -20,6 +20,7 @@ struct exec#ifdef __KERNEL__#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOP#endif
include/asm-mips/a.out.h +1 -0
@@ -40,6 +40,7 @@ struct exec#ifdef CONFIG_64BIT #define STACK_TOP (current->thread.mflags & MF_32BIT_ADDR ? TASK_SIZE32 : TASK_SIZE)#endif +#define STACK_TOP_MAX TASK_SIZE#endif
include/asm-parisc/a.out.h +1 -0
@@ -23,6 +23,7 @@ struct exec* prumpf */ #define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX DEFAULT_TASK_SIZE#endif
include/asm-powerpc/a.out.h +3 -0
@@ -26,9 +26,12 @@ struct exec#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \ STACK_TOP_USER32 : STACK_TOP_USER64) +#define STACK_TOP_MAX STACK_TOP_USER64 +#else /* __powerpc64__ */ #define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOP#endif /* __powerpc64__ */ #endif /* __KERNEL__ */
include/asm-s390/a.out.h +1 -0
@@ -32,6 +32,7 @@ struct exec#ifdef __KERNEL__#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX DEFAULT_TASK_SIZE#endif
include/asm-sh/a.out.h +1 -0
@@ -20,6 +20,7 @@ struct exec#ifdef __KERNEL__#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOP#endif
include/asm-sh64/a.out.h +1 -0
@@ -31,6 +31,7 @@ struct exec#ifdef __KERNEL__#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOP#endif
include/asm-sparc/a.out.h +1 -0
@@ -92,6 +92,7 @@ struct relocation_info /* used when head#include <asm/page.h> #define STACK_TOP (PAGE_OFFSET - PAGE_SIZE) +#define STACK_TOP_MAX STACK_TOP#endif /* __KERNEL__ */
include/asm-sparc64/a.out.h +2 -0
@@ -101,6 +101,8 @@ struct relocation_info /* used when head#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \ STACK_TOP32 : STACK_TOP64) +#define STACK_TOP_MAX STACK_TOP64 +#endif #endif /* !(__ASSEMBLY__) */
include/asm-um/a.out.h +3 -0
@@ -5,6 +5,7 @@#include "choose-mode.h" #undef STACK_TOP +#undef STACK_TOP_MAXextern unsigned long stacksizelim;
@@ -16,4 +17,6 @@ extern int honeypot;#define STACK_TOP \ CHOOSE_MODE((honeypot ? host_task_size : task_size), task_size) +#define STACK_TOP_MAX STACK_TOP +#endif
include/asm-x86_64/a.out.h +2 -1
@@ -21,7 +21,8 @@ struct exec#ifdef __KERNEL__#include <linux/thread_info.h> -#define STACK_TOP TASK_SIZE +#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX TASK_SIZE64#endif #endif /* __A_OUT_GNU_H__ */
include/asm-xtensa/a.out.h +1 -0
@@ -17,6 +17,7 @@/* Note: the kernel needs the a.out definitions, even if only ELF is used. */ #define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOPstruct exec {
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 2/3 audit: rework execve audit
In reply to Peter ZijlstraThe purpose of audit_bprm() is to log the argv array to a userspace daemon at the end of the execve system call. Since user-space hasn't had time to run, this array is still in pristine state on the process' stack; so no need to copy it, we can just grab it from there.
In order to minimize the damage to audit_log_*() copy each string into a temporary kernel buffer first.
Currently the audit code requires that the full argument vector fits in a single packet. So currently it does clip the argv size to a (sysctl) limit, but only when execve auditing is enabled.
If the audit protocol gets extended to allow for multiple packets this check can be removed.
---
Changes:
- changed the BUG_ONs to kill current and print a warning.
- eradicate tmp
- extra check on strlen
fs/exec.c | 3 + include/linux/binfmts.h | 1 kernel/auditsc.c | 84 ++++++++++++++++++++++++++++++++++++------------ kernel/sysctl.c | 11 ++++++ 4 files changed, 78 insertions(+), 21 deletions(-)
kernel/auditsc.c +63 -21
@@ -156,7 +156,7 @@ struct audit_aux_data_execve {struct audit_aux_data d;int argc;int envc; -char mem[0 ]; +struct mm_struct *mm; };struct audit_aux_data_socketcall {
@@ -834,6 +834,55 @@ static int audit_log_pid_context(structreturn rc; } +static void audit_log_execve_info (struct audit_buffer *ab, +struct audit_aux_data_execve *axi) +{ +int i; +long len, ret; +const char __user *p = (const char __user *)axi->mm->arg_start; +char *buf; + +if (axi->mm != current->mm) +return ;/* execve failed, no additional info */ + +for (i =0 ; i < axi->argc; i++, p += len) { + len =strnlen_user (p,MAX_ARG_PAGES *PAGE_SIZE ); +/* +* We just created this mm, if we can't find the strings +* we just copied into it something is _very_ wrong. Similar +* for strings that are too long, we should not have created +* any. +*/ +if (!len || len >MAX_ARG_STRLEN ) { +WARN_ON (1 ); +send_sig (SIGKILL , current,0 ); + } + + buf =kmalloc (len,GFP_KERNEL ); +if (!buf) { +audit_panic ("out of memory for argv string\n" ); +break ; + } + + ret =copy_from_user (buf, p, len); +/* +* There is no reason for this copy to be short. We just +* copied them here, and the mm hasn't been exposed to user- +* space yet. +*/ +if (!ret) { +WARN_ON (1 ); +send_sig (SIGKILL , current,0 ); + } + +audit_log_format (ab,"a%d=" , i); +audit_log_untrustedstring (ab, buf); +audit_log_format (ab,"\n" ); + +kfree (buf); + } +} +static void audit_log_exit (struct audit_context *context,struct task_struct *tsk) {int i, call_panic =0 ;
@@ -974,13 +1023,7 @@ static void audit_log_exit(struct audit_case AUDIT_EXECVE : {struct audit_aux_data_execve *axi = (void *)aux; -int i; -const char *p; -for (i =0 , p = axi->mem; i < axi->argc; i++) { -audit_log_format (ab,"a%d=" , i); - p =audit_log_untrustedstring (ab, p); -audit_log_format (ab,"\n" ); - } +audit_log_execve_info (ab, axi);break ; }case AUDIT_SOCKETCALL : {
@@ -1824,32 +1867,31 @@ int __audit_ipc_set_perm(unsigned long qreturn 0 ; } +int audit_argv_kb =32 ; +int audit_bprm (struct linux_binprm *bprm) {struct audit_aux_data_execve *ax;struct audit_context *context = current->audit_context; -unsigned long p, next; -void *to;if (likely (!audit_enabled || !context || context->dummy))return 0 ; - ax =kmalloc (sizeof (*ax) +PAGE_SIZE *MAX_ARG_PAGES - bprm->p, -GFP_KERNEL ); +/* +* Even though the stack code doesn't limit the arg+env size any more, +* the audit code requires that _all_ arguments be logged in a single +* netlink skb. Hence cap it :-( +*/ +if (bprm->argv_len > (audit_argv_kb <<10 )) +return -E2BIG ; + + ax =kmalloc (sizeof (*ax),GFP_KERNEL );if (!ax)return -ENOMEM ; ax->argc = bprm->argc; ax->envc = bprm->envc; -for (p = bprm->p, to = ax->mem; p <MAX_ARG_PAGES *PAGE_SIZE ; p = next) { -struct page *page = bprm->page[p /PAGE_SIZE ]; -void *kaddr =kmap (page); - next = (p +PAGE_SIZE ) & ~(PAGE_SIZE -1 ); -memcpy (to, kaddr + (p & (PAGE_SIZE -1 )), next - p); - to += next - p; -kunmap (page); - } - + ax->mm = bprm->mm; ax->d.type =AUDIT_EXECVE ; ax->d.next = context->aux; context->aux = (void *)ax;
fs/exec.c +3 -0
@@ -1154,6 +1154,7 @@ int do_execve(char * filename, {struct linux_binprm *bprm;struct file *file; +unsigned long env_p;int retval;int i;
@@ -1208,9 +1209,11 @@ int do_execve(char * filename,if (retval <0 ) goto out; + env_p = bprm->p; retval =copy_strings (bprm->argc, argv, bprm);if (retval <0 ) goto out; + bprm->argv_len = env_p - bprm->p; retval =search_binary_handler (bprm,regs);if (retval >=0 ) {
include/linux/binfmts.h +1 -0
@@ -40,6 +40,7 @@ struct linux_binprm{unsigned interp_flags;unsigned interp_data;unsigned long loader, exec; +unsigned long argv_len; };#define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
kernel/sysctl.c +11 -0
@@ -81,6 +81,7 @@ extern int percpu_pagelist_fraction;extern int compat_log;extern int maps_protect;extern int sysctl_stat_interval; +extern int audit_argv_kb;/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ static int maxolduid =65535 ;
@@ -711,6 +712,16 @@ static ctl_table kern_table[] = { .proc_handler = &proc_dointvec, },#endif +#ifdef CONFIG_AUDITSYSCALL + { + .ctl_name = CTL_UNNUMBERED, + .procname = "audit_argv_kb", + .data = &audit_argv_kb, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif { .ctl_name = 0 } };
Andrew Morton
maintainerRe: [patch 2/3] audit: rework execve audit
kernel/sysctl.c static ctl_table kern_table[] = { · line 724
Quoted 10 lines · On Wed, 13 Jun 2007 12:03:36 +0200 Peter Zijlstra <[email protected]>…
kernel/sysctl.c +10
-0+#ifdef CONFIG_AUDITSYSCALL + { + .ctl_name = CTL_UNNUMBERED, + .procname = "audit_argv_kb", + .data = &audit_argv_kb, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif
Please document /proc entries in Documentation/filesystems/proc.txt
Re: [patch 2/3] audit: rework execve audit
Quoted 15 lines · Andrew Morton
Review
Quoted 10 lines · On Wed, 13 Jun 2007 12:03:36 +0200 Peter Zijlstra <[email protected]>…
(quoted diff) +10
-0+#ifdef CONFIG_AUDITSYSCALL + { + .ctl_name = CTL_UNNUMBERED, + .procname = "audit_argv_kb", + .data = &audit_argv_kb, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endifPlease document /proc entries in
Documentation/filesystems/proc.txt
--- Documentation/filesystems/proc.txt | 7 +++++++ 1 file changed, 7 insertions(+)
Documentation/filesystems/proc.txt +7 -0
@@ -1075,6 +1075,13 @@ check the amount of free space (value is resume it if we have a value of 3 or more percent; consider information about the amount of free space valid for 30 seconds +audit_argv_kb +------------- + +The file contains a single value denoting the limit on the argv array size +for execve (in KiB). This limit is only applied when system call auditing for +execve is enabled, otherwise the value is ignored. + ctrl-alt-del ------------
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
[parisc-linux] Re: [patch 2/3] audit: rework execve audit
In reply to Andrew MortonQuoted 15 lines · Andrew Morton
Review
Quoted 10 lines · On Wed, 13 Jun 2007 12:03:36 +0200 Peter Zijlstra <[email protected]>…
(quoted diff) +10
-0+#ifdef CONFIG_AUDITSYSCALL + { + .ctl_name = CTL_UNNUMBERED, + .procname = "audit_argv_kb", + .data = &audit_argv_kb, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endifPlease document /proc entries in
Documentation/filesystems/proc.txt
--- Documentation/filesystems/proc.txt | 7 +++++++ 1 file changed, 7 insertions(+)
Documentation/filesystems/proc.txt +7 -0
@@ -1075,6 +1075,13 @@ check the amount of free space (value is resume it if we have a value of 3 or more percent; consider information about the amount of free space valid for 30 seconds +audit_argv_kb +------------- + +The file contains a single value denoting the limit on the argv array size +for execve (in KiB). This limit is only applied when system call auditing for +execve is enabled, otherwise the value is ignored. + ctrl-alt-del ------------
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
PATCH 3/3 mm: variable length argument support
In reply to Peter ZijlstraRemove the arg+env limit of MAX_ARG_PAGES by copying the strings directly from the old mm into the new mm.
We create the new mm before the binfmt code runs, and place the new stack at the very top of the address space. Once the binfmt code runs and figures out where the stack should be, we move it downwards.
It is a bit peculiar in that we have one task with two mm's, one of which is inactive.
---
Changes:
- reverted the UML changes, those were no longer needed
- reworked the no-MMU stuff to reduce #ifdef clutter and enhance compilability
- removed move_page_tables_up() since it turned out to be unused
- sprinkled comments
arch/ia64/ia32/binfmt_elf32.c | 65 +--- arch/x86_64/ia32/ia32_aout.c | 2 arch/x86_64/ia32/ia32_binfmt.c | 58 --- fs/binfmt_elf.c | 28 + fs/binfmt_elf_fdpic.c | 8 fs/binfmt_misc.c | 4 fs/binfmt_script.c | 4 fs/compat.c | 128 +++----- fs/exec.c | 606 +++++++++++++++++++++++++---------------- include/linux/binfmts.h | 18 - include/linux/mm.h | 9 kernel/auditsc.c | 2 mm/mmap.c | 61 ++-- mm/mprotect.c | 2 mm/mremap.c | 2 15 files changed, 541 insertions(+), 456 deletions(-)
arch/x86_64/ia32/ia32_binfmt.c +0 -58
@@ -233,9 +233,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 { \
@@ -287,61 +284,6 @@ static void elf32_init(struct pt_regs *r me->thread.es = __USER_DS; } -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_zalloc (vm_area_cachep,GFP_KERNEL ); -if (!mpnt) -return -ENOMEM ; - -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 ; -} -EXPORT_SYMBOL (ia32_setup_arg_pages); -#ifdef CONFIG_SYSCTL /* Register vsyscall32 into the ABI table */ #include <linux/sysctl.h>
fs/binfmt_elf.c +19 -9
@@ -148,6 +148,7 @@ create_elf_tables(struct linux_binprm *belf_addr_t *elf_info;int ei_index =0 ;struct task_struct *tsk = current; +struct vm_area_struct *vma;/* * If this architecture has a platform capability string, copy it
@@ -234,6 +235,15 @@ create_elf_tables(struct linux_binprm *b sp = (elf_addr_t __user *)bprm->p;#endif + +/* +* Grow the stack manually; some architectures have a limit on how +* far ahead a user-space access may be in order to grow the stack. +*/ + vma =find_extend_vma (current->mm, bprm->p); +if (!vma) +return -EFAULT ; +/* Now, let's put argc (and argv, envp if appropriate) on the stack */ if (__put_user (argc, sp++))return -EFAULT ;
@@ -254,8 +264,8 @@ create_elf_tables(struct linux_binprm *bsize_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; }
@@ -266,8 +276,8 @@ create_elf_tables(struct linux_binprm *bsize_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; }
@@ -826,10 +836,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;
@@ -1051,9 +1057,13 @@ static int load_elf_binary(struct linux_compute_creds (bprm); current->flags &= ~PF_FORKNOEXEC ; -create_elf_tables (bprm, &loc->elf_ex, + retval =create_elf_tables (bprm, &loc->elf_ex, (interpreter_type ==INTERPRETER_AOUT ), load_addr, interp_load_addr); +if (retval <0 ) { +send_sig (SIGKILL , current,0 ); + goto out; + }/* N.B. passed_fileno might not be initialized? */ if (interpreter_type ==INTERPRETER_AOUT ) current->mm->arg_start +=strlen (passed_fileno) +1 ;
fs/binfmt_elf_fdpic.c +4 -4
@@ -621,8 +621,8 @@ static int create_elf_fdpic_tables(struc p = (char __user *) current->mm->arg_start;for (loop = bprm->argc; loop >0 ; loop--) {__put_user ((elf_caddr_t ) p, argv++); - len =strnlen_user (p,PAGE_SIZE *MAX_ARG_PAGES ); -if (!len || len >PAGE_SIZE *MAX_ARG_PAGES ) + len =strnlen_user (p,MAX_ARG_STRLEN ); +if (!len || len >MAX_ARG_STRLEN )return -EINVAL ; p += len; }
@@ -633,8 +633,8 @@ static int create_elf_fdpic_tables(struc current->mm->env_start = (unsigned long ) p;for (loop = bprm->envc; loop >0 ; loop--) {__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_ARG_STRLEN ); +if (!len || len >MAX_ARG_STRLEN )return -EINVAL ; p += len; }
fs/binfmt_misc.c +3 -1
@@ -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 ) {
fs/binfmt_script.c +3 -1
@@ -67,7 +67,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++;
fs/compat.c +53 -75
209 lines not on this page · raw message
fs/exec.c +384 -222
778 lines not on this page · raw message
include/linux/binfmts.h +13 -5
@@ -6,11 +6,13 @@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! +* These are the maximum length and maximum number of strings passed to the +* execve() system call. MAX_ARG_STRLEN is essentially random but serves to +* prevent the kernel from being unduly impacted by misaddressed pointers. +* MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer. */ -#define MAX_ARG_PAGES 32 +#define MAX_ARG_STRLEN (PAGE_SIZE * 32) +#define MAX_ARG_STRINGS 0x7FFFFFFF/* sizeof(linux_binprm->buf) */ #define BINPRM_BUF_SIZE 128
@@ -24,7 +26,12 @@ struct pt_regs;*/ struct linux_binprm {char buf[BINPRM_BUF_SIZE ]; +#ifdef CONFIG_MMU +struct vm_area_struct *vma; +#else +# define MAX_ARG_PAGES 32struct page *page[MAX_ARG_PAGES ]; +#endif struct mm_struct *mm;unsigned long p;/* current top of mem */ int sh_bang;
@@ -69,7 +76,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);
@@ -86,6 +93,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);
include/linux/mm.h +8 -1
@@ -815,7 +815,6 @@ static inline int handle_mm_fault(structextern 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);
@@ -832,9 +831,15 @@ int FASTCALL(set_page_dirty(struct pageint set_page_dirty_lock (struct page *page);int clear_page_dirty_for_io (struct page *page); +extern unsigned long move_page_tables (struct vm_area_struct *vma, +unsigned long old_addr,struct vm_area_struct *new_vma, +unsigned long new_addr,unsigned long len);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);/* * A callback you can register to apply pressure to ageable caches.
@@ -1159,6 +1164,8 @@ extern int expand_stack(struct vm_area_s#ifdef CONFIG_IA64 extern int expand_upwards (struct vm_area_struct *vma,unsigned long address);#endif +extern int expand_stack_downwards (struct vm_area_struct *vma, +unsigned long address);/* Look up the first VMA which satisfies addr < vm_end, NULL if none. */ extern struct vm_area_struct *find_vma (struct mm_struct * mm,unsigned long addr);
mm/mmap.c +35 -26
83 lines not on this page · raw message
mm/mprotect.c +1 -1
@@ -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) {
arch/ia64/ia32/binfmt_elf32.c +15 -50
77 lines not on this page · raw message
arch/x86_64/ia32/ia32_aout.c +1 -1
@@ -404,7 +404,7 @@ beyond_if:set_brk (current->mm->start_brk, current->mm->brk); - retval =ia32_setup_arg_pages (bprm,IA32_STACK_TOP ,EXSTACK_DEFAULT ); + retval =setup_arg_pages (bprm,IA32_STACK_TOP ,EXSTACK_DEFAULT );if (retval <0 ) {/* Someone check-me: is this error path enough? */ send_sig (SIGKILL , current,0 );
kernel/auditsc.c +1 -1
@@ -846,7 +846,7 @@ static void audit_log_execve_info(structreturn ;/* execve failed, no additional info */ for (i =0 ; i < axi->argc; i++, p += len) { - len =strnlen_user (p,MAX_ARG_PAGES *PAGE_SIZE ); + len =strnlen_user (p,MAX_ARG_STRLEN );/* * We just created this mm, if we can't find the strings * we just copied into it something is _very_ wrong. Similar
mm/mremap.c +1 -1
@@ -120,7 +120,7 @@ static void move_ptes(struct vm_area_str#define LATENCY_LIMIT (64 * PAGE_SIZE) -static unsigned long move_page_tables (struct vm_area_struct *vma, +unsigned long move_page_tables (struct vm_area_struct *vma,unsigned long old_addr,struct vm_area_struct *new_vma,unsigned long new_addr,unsigned long len) {
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 3/3] mm: variable length argument support
Quoted 11 lines · Peter Zijlstra
From: Ollie Wild <[email protected]>
Remove the arg+env limit of
MAX_ARG_PAGESby copying the strings directly from the old mm into the new mm.+++
linux-2.6-2/include/linux/binfmts.h2007-06-13 11:52:46.000000000 +0200include/linux/binfmts.h +0
-1@@ -6,11 +6,13 @@struct pt_regs ;/* -* MAX_ARG_PAGES defines the number of pages allocated for arguments
include/linux/binfmts.h line 15
Quoted 10 lines
include/linux/binfmts.h +6
-3-* and envelope for the new program. 32 should suffice, this gives -* a maximum env+arg of 128kB w/4KB pages! +* These are the maximum length and maximum number of strings passed to the +* execve() system call. MAX_ARG_STRLEN is essentially random but serves to +* prevent the kernel from being unduly impacted by misaddressed pointers. +* MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer. */ -#define MAX_ARG_PAGES 32 +#define MAX_ARG_STRLEN (PAGE_SIZE * 32) +#define MAX_ARG_STRINGS 0x7FFFFFFF
This adds a new usage of PAGE_SIZE to an exported header. How can this be fixed for 2.6.23?
Andrew Morton
maintainerRe: [patch 3/3] mm: variable length argument support
Quoted 11 lines · On Tue, 7 Aug 2007 21:03:57 +0200 Olaf Hering <[email protected]> wrote:
Quoted 9 lines · Peter Zijlstra
From: Ollie Wild <[email protected]>
Remove the arg+env limit of
MAX_ARG_PAGESby copying the strings directly from the old mm into the new mm.+++
linux-2.6-2/include/linux/binfmts.h2007-06-13 11:52:46.000000000 +0200include/linux/binfmts.h +0
-0@@ -6,11 +6,13 @@struct pt_regs ;
Quoted 15 lines
include/linux/binfmts.h line 15
Quoted 12 lines
include/linux/binfmts.h +6
-4/* -* 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! +* These are the maximum length and maximum number of strings passed to the +* execve() system call. MAX_ARG_STRLEN is essentially random but serves to +* prevent the kernel from being unduly impacted by misaddressed pointers. +* MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer. */ -#define MAX_ARG_PAGES 32 +#define MAX_ARG_STRLEN (PAGE_SIZE * 32) +#define MAX_ARG_STRINGS 0x7FFFFFFFThis adds a new usage of
PAGE_SIZEto an exported header. How can this be fixed for 2.6.23?
Put #ifdef __KERNEL__ around it?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 3/3] mm: variable length argument support
Quoted 30 lines · Andrew Morton
Quoted 11 lines · On Tue, 7 Aug 2007 21:03:57 +0200 Olaf Hering <[email protected]> wrote:
Quoted 9 lines · Peter Zijlstra
From: Ollie Wild <[email protected]>
Remove the arg+env limit of
MAX_ARG_PAGESby copying the strings directly from the old mm into the new mm.+++
linux-2.6-2/include/linux/binfmts.h2007-06-13 11:52:46.000000000 +0200include/linux/binfmts.h +0
-0@@ -6,11 +6,13 @@struct pt_regs ;Quoted 15 lines
include/linux/binfmts.h line 15
Quoted 12 lines
include/linux/binfmts.h +6
-4/* -* 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! +* These are the maximum length and maximum number of strings passed to the +* execve() system call. MAX_ARG_STRLEN is essentially random but serves to +* prevent the kernel from being unduly impacted by misaddressed pointers. +* MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer. */ -#define MAX_ARG_PAGES 32 +#define MAX_ARG_STRLEN (PAGE_SIZE * 32) +#define MAX_ARG_STRINGS 0x7FFFFFFFThis adds a new usage of
PAGE_SIZEto an exported header. How can this be fixed for 2.6.23?
Quoted 1 line
Put #ifdef
__KERNEL__around it?
Sounds like a good idea, since its new there should not yet be anybody using it.
If anything, someone used to use MAX_ARG_PAGES in userspace, which we just now broke. Olaf said he'd grep a distro source base to find out :-)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 3/3] mm: variable length argument support
In reply to Andrew MortonQuoted 10 lines · Andrew Morton
Quoted 8 lines
include/linux/binfmts.h line 15
Quoted 5 lines
+++
linux-2.6-2/include/linux/binfmts.h2007-06-13 11:52:46.000000000 +0200include/linux/binfmts.h +2
-1-#define MAX_ARG_PAGES 32 +#define MAX_ARG_STRLEN (PAGE_SIZE * 32) +#define MAX_ARG_STRINGS 0x7FFFFFFFThis adds a new usage of
PAGE_SIZEto an exported header. How can this be fixed for 2.6.23?Put #ifdef
__KERNEL__around it?
No package uses linux/binfmts.h, will send a Kbuild patch to unexport it.
Re: [patch 3/3] mm: variable length argument support
In reply to Peter ZijlstraQuoted 5 lines · Peter Zijlstra
From: Ollie Wild <[email protected]>
Remove the arg+env limit of
MAX_ARG_PAGESby copying the strings directly from the old mm into the new mm.
[...]
Quoted 2 lines
(quoted diff) +2
-0+static int __bprm_mm_init(struct linux_binprm *bprm) +{
[...]
Review
Quoted 8 lines
(quoted diff) +8
-0+ vma->vm_flags = VM_STACK_FLAGS; + vma->vm_page_prot = protection_map[vma->vm_flags & 0x7]; + err = insert_vm_struct(mm, vma); + if (err) { + up_write(&mm->mmap_sem); + goto err; + } +
That change causes a crash in khelper when overcommit_memory = 2 under 2.6.23-rc3.
When a khelper execs, at __bprm_mm_init() current->mm is still NULL. insert_vm_struct() calls security_vm_enough_memory(), which calls __vm_enough_memory(), and that's where current->mm->total_vm gets dereferenced.
mm/mmap.c +6 -4
@@ -163,10 +163,12 @@ int __vm_enough_memory(long pages, int cap_sys_admin)if (!cap_sys_admin) allowed -= allowed /32 ; allowed += total_swap_pages; - -/* Don't let a single process grow too big: -leave 3% of the size of this process for other processes */ - allowed -= current->mm->total_vm /32 ; + +if (current->mm) { +/* Don't let a single process grow too big: +leave 3% of the size of this process for other processes */ + allowed -= current->mm->total_vm /32 ; + }/* * cast `allowed' as a signed long because vm_committed_space
Signature · 9 lines
Dan Aloni XIV LTD, http://www.xivstorage.com da-x (at) monatomic.org, dan (at) xiv.co.il -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 3/3] mm: variable length argument support
Quoted 22 lines · Dan Aloni
Quoted 5 lines · Peter Zijlstra
From: Ollie Wild <[email protected]>
Remove the arg+env limit of
MAX_ARG_PAGESby copying the strings directly from the old mm into the new mm.[...]
Quoted 2 lines
(quoted diff) +2
-0+static int __bprm_mm_init(struct linux_binprm *bprm) +{[...]
Review
Quoted 8 lines
(quoted diff) +8
-0+ vma->vm_flags = VM_STACK_FLAGS; + vma->vm_page_prot = protection_map[vma->vm_flags & 0x7]; + err = insert_vm_struct(mm, vma); + if (err) { + up_write(&mm->mmap_sem); + goto err; + } +That change causes a crash in khelper when
overcommit_memory= 2 under 2.6.23-rc3.
Quoted 4 lines
When a khelper execs, at
__bprm_mm_init()current->mmis still NULL.insert_vm_struct()callssecurity_vm_enough_memory(), which calls__vm_enough_memory(), and that's wherecurrent->mm->total_vmgets dereferenced.
Alan proposed this patch:
Andrew Morton
maintainerRe: [patch 3/3] mm: variable length argument support
Quoted 1 line · On Wed, 22 Aug 2007 10:54:02 +0200 Peter Zijlstra <[email protected]>…
Alan proposed this patch:
yeah, I have a great pile of stuff queued for Linus. I'm bad. Tomorrow.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 3/3] mm: variable length argument support
In reply to Dan AloniQuoted 42 lines · Dan Aloni
Quoted 5 lines · Peter Zijlstra
From: Ollie Wild <[email protected]>
Remove the arg+env limit of
MAX_ARG_PAGESby copying the strings directly from the old mm into the new mm.[...]
Quoted 2 lines
(quoted diff) +2
-0+static int __bprm_mm_init(struct linux_binprm *bprm) +{[...]
Review
Quoted 8 lines
(quoted diff) +8
-0+ vma->vm_flags = VM_STACK_FLAGS; + vma->vm_page_prot = protection_map[vma->vm_flags & 0x7]; + err = insert_vm_struct(mm, vma); + if (err) { + up_write(&mm->mmap_sem); + goto err; + } +That change causes a crash in khelper when
overcommit_memory= 2 under 2.6.23-rc3.When a khelper execs, at
__bprm_mm_init()current->mmis still NULL.insert_vm_struct()callssecurity_vm_enough_memory(), which calls__vm_enough_memory(), and that's wherecurrent->mm->total_vmgets dereferenced.Signed-off-by Dan Aloni <[email protected]>mm/mmap.c +0
-3@@ -163,10 +163,12 @@ int __vm_enough_memory(long pages, int cap_sys_admin)if (!cap_sys_admin) allowed -= allowed /32 ; allowed += total_swap_pages; - -/* Don't let a single process grow too big: -leave 3% of the size of this process for other processes */
mm/mmap.c int __vm_enough_memory(long pages, int cap_sys_admin) · line 174
Quoted 10 lines
mm/mmap.c +6
-1- allowed -= current->mm->total_vm /32 ; + +if (current->mm) { +/* Don't let a single process grow too big: +leave 3% of the size of this process for other processes */ + allowed -= current->mm->total_vm /32 ; + }/* * cast `allowed' as a signed long because vm_committed_space
FYI: This bug has been fixed by Alan Cox: http://lkml.org/lkml/2007/8/13/782.
But thanks anyway~
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 3/3] mm: variable length argument support
In reply to Dan AloniQuoted 42 lines · Dan Aloni
Quoted 5 lines · Peter Zijlstra
From: Ollie Wild <[email protected]>
Remove the arg+env limit of
MAX_ARG_PAGESby copying the strings directly from the old mm into the new mm.[...]
Quoted 2 lines
(quoted diff) +2
-0+static int __bprm_mm_init(struct linux_binprm *bprm) +{[...]
Review
Quoted 8 lines
(quoted diff) +8
-0+ vma->vm_flags = VM_STACK_FLAGS; + vma->vm_page_prot = protection_map[vma->vm_flags & 0x7]; + err = insert_vm_struct(mm, vma); + if (err) { + up_write(&mm->mmap_sem); + goto err; + } +That change causes a crash in khelper when
overcommit_memory= 2 under 2.6.23-rc3.When a khelper execs, at
__bprm_mm_init()current->mmis still NULL.insert_vm_struct()callssecurity_vm_enough_memory(), which calls__vm_enough_memory(), and that's wherecurrent->mm->total_vmgets dereferenced.Signed-off-by Dan Aloni <[email protected]>mm/mmap.c +0
-3@@ -163,10 +163,12 @@ int __vm_enough_memory(long pages, int cap_sys_admin)if (!cap_sys_admin) allowed -= allowed /32 ; allowed += total_swap_pages; - -/* Don't let a single process grow too big: -leave 3% of the size of this process for other processes */
mm/mmap.c int __vm_enough_memory(long pages, int cap_sys_admin) · line 174
Quoted 10 lines
mm/mmap.c +6
-1- allowed -= current->mm->total_vm /32 ; + +if (current->mm) { +/* Don't let a single process grow too big: +leave 3% of the size of this process for other processes */ + allowed -= current->mm->total_vm /32 ; + }/* * cast `allowed' as a signed long because vm_committed_space
FYI: This bug has been fixed by Alan Cox: http://lkml.org/lkml/2007/8/13/782.
But thanks anyway~
Quoted 2 lines
This patch-set aims at removing the current limit on argv+env space aka.
MAX_ARG_PAGES.
Running with this patch shows that /bin/bash has some unpleasant O(n^2) performance issues with long argument lists. I made a 1Mbyte file full of pathnames, then timed the execution of:
$ /bin/echo `cat megabyte` | wc $ /bin/echo `cat megabyte megabyte` | wc etc. ...
System time was pretty much linear as the arglist grew (and only got up to 0.144 seconds at 5Mbytes).
But user time ~= real time (in seconds) looks like:
1 5.318
2 18.871
3 40.620
4 70.819
5 108.911
Above 5Mbytes, I started seeing problems. The line/word/char counts from "wc" started being "0 0 0". Not sure if this is a problem in "wc" dealing with a single line >5MBytes, or some other problem (possibly I was exceeding the per-process stack limit which is only 8MB on that machine).
-Tony
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 5 lines · Tony
Above 5Mbytes, I started seeing problems. The line/word/char counts from "wc" started being "0 0 0". Not sure if this is a problem in "wc" dealing with a single line >5MBytes, or some other problem (possibly I was exceeding the per-process stack limit which is only 8MB on that machine).
Interesting. If you're exceeding your stack ulimit, you should be seeing either an "argument list too long" message or getting a SIGSEGV. Have you tried bypassing wc and piping the output straight to a file?
Ollie
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 11 lines · Ollie Wild
Quoted 5 lines · Tony
Above 5Mbytes, I started seeing problems. The line/word/char counts from "wc" started being "0 0 0". Not sure if this is a problem in "wc" dealing with a single line >5MBytes, or some other problem (possibly I was exceeding the per-process stack limit which is only 8MB on that machine).
Interesting. If you're exceeding your stack ulimit, you should be seeing either an "argument list too long" message or getting a SIGSEGV. Have you tried bypassing wc and piping the output straight to a file?
I think it sends SIGKILL on failure paths.
I've been thinking of moving this large stack alloc in create_elf_tables() before the point of no return.
something like this, it should do the largest part of the alloc beforehand. Just have to see if all binfmts need this much, and if not, what the ramifications are of overgrowing the stack (perhaps we need to shrink it again to wherever bprm->p ends up?)
fs/exec.c +20 -0
@@ -272,6 +272,17 @@ static bool valid_arg_len(struct linux_breturn len <=MAX_ARG_STRLEN ; } +static int expand_arg_vma (struct linux_binprm *bprm) +{ +long size = (bprm->argc + bprm->envc +2 ) *sizeof (void *); + +#ifdef CONFIG_STACK_GROWSUP +#error I broke it +#else +return expand_stack (bprm->vma, bprm->p - size); +#endif +} +#else static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
@@ -326,6 +337,11 @@ static bool valid_arg_len(struct linux_b return len <= bprm->p; } +static int expand_arg_vma (struct linux_binprm *bprm) +{ +return 0 ; +} +#endif /* CONFIG_MMU */ /*
@@ -1385,6 +1401,10 @@ int do_execve(char * filename, goto out; bprm->argv_len = env_p - bprm->p; + retval =expand_arg_vma (bprm); +if (retval <0 ) + goto out; + retval =search_binary_handler (bprm,regs);if (retval >=0 ) {/* execve success */
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 6 lines
Quoted 4 lines
Interesting. If you're exceeding your stack ulimit, you should be seeing either an "argument list too long" message or getting a SIGSEGV. Have you tried bypassing wc and piping the output straight to a file?
I think it sends SIGKILL on failure paths.
Setting stack limit to unlimited I managed to exec with 10MB, and "wc" produced the correct output when it (finally) ran, so no odd limits being hit in there.
Setting a lower (4MB) stack limit, and then increasing the amount of args in 100K steps I saw this:
Up to an including 32 * 100K => works fine.
33:40 * 100K => no errors from the script, but wc reports "0 0 0"
Quoted 1 line
40 * 100K => "
/bin/echo: Argument list too long".
All this might be connected to ia64's confusing implementation of stack limit (since we have *two* stacks ... the regular one and the upward growing one for the h/w register stack engine).
Ah ... running the 34*100K case direct from my shell prompt, I do see a "Killed" that must get lost when I run this in the shell script loop.
-Tony
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 10 lines · Tony
Quoted 6 lines
Quoted 4 lines
Interesting. If you're exceeding your stack ulimit, you should be seeing either an "argument list too long" message or getting a SIGSEGV. Have you tried bypassing wc and piping the output straight to a file?
I think it sends SIGKILL on failure paths.
Setting stack limit to unlimited I managed to exec with 10MB, and "wc" produced the correct output when it (finally) ran, so no odd limits being hit in there.
Ah, good :-)
Quoted 3 lines
Ah ... running the 34*100K case direct from my shell prompt, I do see a "Killed" that must get lost when I run this in the shell script loop.
Yes, so it seems we just trip the stack limit after we cross the point of no return.
I started looking into growing the stack beforehand and perhaps shrinking the stack after we're done. That would get most if not all these failures before the point of no return.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
fs/exec.c int do_execve(char * filename, · line 1410
Quoted 11 lines
fs/exec.c +4
-0@@ -1385,6 +1401,10 @@ int do_execve(char * filename, goto out; bprm->argv_len = env_p - bprm->p; + retval =expand_arg_vma (bprm); +if (retval <0 ) + goto out; + retval =search_binary_handler (bprm,regs);if (retval >=0 ) {/* execve success */
At this point bprm->argc hasn't been finalized yet. For example, the script binfmt reads the script header and adds additional arguments. The flush_old_exec() function is a better place to call this.
I'm not 100% sure this is the right way to handle this, though. The problem isn't as simple as ensuring the stack doesn't overflow during argument allocation. We also need to ensure the program has sufficient stack space to run subsequently. Otherwise, the observable behavior is identical. Since we can't realistically predict acceptable stack availability requirements, some amount of uncertainty is always going to exist. A good heuristic, though, might be to limit argument size to a percentage (say 25%) of maximum stack size and validate this inside copy_strings().
Ollie
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 4 lines · Ollie Wild
Quoted 4 lines
fs/exec.c +0
-0@@ -1385,6 +1401,10 @@ int do_execve(char * filename, goto out; bprm->argv_len = env_p - bprm->p;
Quoted 11 lines
fs/exec.c int do_execve(char * filename, · line 1410
Quoted 7 lines
fs/exec.c +4
-0+ retval =expand_arg_vma (bprm); +if (retval <0 ) + goto out; + retval =search_binary_handler (bprm,regs);if (retval >=0 ) {/* execve success */ At this point
bprm->argchasn't been finalized yet. For example, the script binfmt reads the script header and adds additional arguments. Theflush_old_exec()function is a better place to call this.
Sure, but at this time most of it is there, so when there are many, this allocates the most of it.
Quoted 5 lines
I'm not 100% sure this is the right way to handle this, though. The problem isn't as simple as ensuring the stack doesn't overflow during argument allocation. We also need to ensure the program has sufficient stack space to run subsequently. Otherwise, the observable behavior is identical.
Well, not identical, but similar indeed.
Quoted 7 lines
Since we can't realistically predict
acceptable stack availability requirements, some amount of uncertainty is always going to exist.A good heuristic, though, might be to limit
argument size to a percentage (say 25%) of maximum stack size and validate this insidecopy_strings().
Right, this seems a much simpler approach. I like it.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 3 lines · Ollie Wild
A good heuristic, though, might be to limit
argument size to a percentage (say 25%) of maximum stack size and validate this insidecopy_strings().
This seems to do:
--- fs/exec.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
fs/exec.c +17 -0
@@ -199,6 +199,23 @@ static struct page *get_arg_page(structif (ret <=0 )return NULL ; +if (write) { +struct rlimit *rlim = current->signal->rlim; +unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start; + +/* +* Limit to 1/4-th the stack size for the argv+env strings. +* This ensures that: +* - the remaining binfmt code will not run out of stack space, +* - the program will have a reasonable amount of stack left +* to work from. +*/ +if (size > rlim[RLIMIT_STACK ].rlim_cur /4 ) { +put_page (page); +return NULL ; + } + } +return page; }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 7 lines · Peter Zijlstra
Quoted 3 lines · Ollie Wild
A good heuristic, though, might be to limit
argument size to a percentage (say 25%) of maximum stack size and validate this insidecopy_strings().This seems to do:
Looks good.
Ollie
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Luck, Tony
Acked-byQuoted 7 lines
Quoted 5 lines
Quoted 3 lines
A good heuristic, though, might be to limit
argument size to a percentage (say 25%) of maximum stack size and validate this insidecopy_strings().This seems to do:
Looks good.
Me too. As I increase the number of arguments, I now have a smooth cutover from "works" to "Arg list too long", without the in between zone where the process is killed.
The IA-32 compatability exec path is now working too (I didn't stress it too hard, but I did try argument lists up to a megabyte).
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Hi!
Quoted 2 lines
This patch-set aims at removing the current limit on argv+env space aka.
MAX_ARG_PAGES.
Thanks a lot for solving this properly. I have been upping current limits to some insane ammounts to work around this.
Pavel
Signature · 8 lines
(english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Ingo Molnar
Acked-byQuoted 7 lines · Pavel Machek
Hi!
Quoted 2 lines
This patch-set aims at removing the current limit on argv+env space aka.
MAX_ARG_PAGES.Thanks a lot for solving this properly. I have been upping current limits to some insane ammounts to work around this.
seconded! I have tried the patchset and it works great for me. This limitation of Linux has bothered me almost since i started using Linux more than a decade ago (i remember having run into it when running a script on an overly large directory), and it's perhaps the oldest still existing userspace-visible limitations of Linux. It was also a really hard nut to crack. Kudos Peter! I really cant wait to see this in 2.6.23 :-)
Ingo
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>