From: Linus Torvalds Date: Mon, 23 May 2011 15:28:34 +0000 (-0700) Subject: Merge branch 'exec_rm_compat' of git://git.kernel.org/pub/scm/linux/kernel/git/oleg... X-Git-Tag: firefly_0821_release~7613^2~1342 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=4d9dec4db2efbd7edb549bd02373995b67496983;hp=-c;p=firefly-linux-kernel-4.4.55.git Merge branch 'exec_rm_compat' of git://git./linux/kernel/git/oleg/misc * 'exec_rm_compat' of git://git.kernel.org/pub/scm/linux/kernel/git/oleg/misc: exec: document acct_arg_size() exec: unify do_execve/compat_do_execve code exec: introduce struct user_arg_ptr exec: introduce get_user_arg_ptr() helper --- 4d9dec4db2efbd7edb549bd02373995b67496983 diff --combined fs/exec.c index 8328beb9016f,5cb53f0232b1..c016896dcbb2 --- a/fs/exec.c +++ b/fs/exec.c @@@ -55,6 -55,7 +55,7 @@@ #include #include #include + #include #include #include @@@ -166,8 -167,13 +167,13 @@@ out } #ifdef CONFIG_MMU - - void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) + /* + * The nascent bprm->mm is not visible until exec_mmap() but it can + * use a lot of memory, account these pages in current->mm temporary + * for oom_badness()->get_mm_rss(). Once exec succeeds or fails, we + * change the counter back via acct_arg_size(0). + */ + static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) { struct mm_struct *mm = current->mm; long diff = (long)(pages - bprm->vma_pages); @@@ -186,7 -192,7 +192,7 @@@ #endif } - struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, + static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, int write) { struct page *page; @@@ -305,11 -311,11 +311,11 @@@ static bool valid_arg_len(struct linux_ #else - void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) + static inline void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) { } - struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, + static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, int write) { struct page *page; @@@ -398,22 -404,56 +404,56 @@@ err return err; } + struct user_arg_ptr { + #ifdef CONFIG_COMPAT + bool is_compat; + #endif + union { + const char __user *const __user *native; + #ifdef CONFIG_COMPAT + compat_uptr_t __user *compat; + #endif + } ptr; + }; + + static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr) + { + const char __user *native; + + #ifdef CONFIG_COMPAT + if (unlikely(argv.is_compat)) { + compat_uptr_t compat; + + if (get_user(compat, argv.ptr.compat + nr)) + return ERR_PTR(-EFAULT); + + return compat_ptr(compat); + } + #endif + + if (get_user(native, argv.ptr.native + nr)) + return ERR_PTR(-EFAULT); + + return native; + } + /* * count() counts the number of strings in array ARGV. */ - static int count(const char __user * const __user * argv, int max) + static int count(struct user_arg_ptr argv, int max) { int i = 0; - if (argv != NULL) { + if (argv.ptr.native != NULL) { for (;;) { - const char __user * p; + const char __user *p = get_user_arg_ptr(argv, i); - if (get_user(p, argv)) - return -EFAULT; if (!p) break; - argv++; + + if (IS_ERR(p)) + return -EFAULT; + if (i++ >= max) return -E2BIG; @@@ -430,7 -470,7 +470,7 @@@ * 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, const char __user *const __user *argv, + static int copy_strings(int argc, struct user_arg_ptr argv, struct linux_binprm *bprm) { struct page *kmapped_page = NULL; @@@ -443,16 -483,18 +483,18 @@@ int len; unsigned long pos; - if (get_user(str, argv+argc) || - !(len = strnlen_user(str, MAX_ARG_STRLEN))) { - ret = -EFAULT; + ret = -EFAULT; + str = get_user_arg_ptr(argv, argc); + if (IS_ERR(str)) goto out; - } - if (!valid_arg_len(bprm, len)) { - ret = -E2BIG; + len = strnlen_user(str, MAX_ARG_STRLEN); + if (!len) + goto out; + + ret = -E2BIG; + if (!valid_arg_len(bprm, len)) goto out; - } /* We're going to work our way backwords. */ pos = bprm->p; @@@ -519,14 -561,19 +561,19 @@@ out /* * Like copy_strings, but get argv and its values from kernel memory. */ - int copy_strings_kernel(int argc, const char *const *argv, + int copy_strings_kernel(int argc, const char *const *__argv, struct linux_binprm *bprm) { int r; mm_segment_t oldfs = get_fs(); + struct user_arg_ptr argv = { + .ptr.native = (const char __user *const __user *)__argv, + }; + set_fs(KERNEL_DS); - r = copy_strings(argc, (const char __user *const __user *)argv, bprm); + r = copy_strings(argc, argv, bprm); set_fs(oldfs); + return r; } EXPORT_SYMBOL(copy_strings_kernel); @@@ -1379,10 -1426,10 +1426,10 @@@ EXPORT_SYMBOL(search_binary_handler) /* * sys_execve() executes a new program. */ - int do_execve(const char * filename, - const char __user *const __user *argv, - const char __user *const __user *envp, - struct pt_regs * regs) + static int do_execve_common(const char *filename, + struct user_arg_ptr argv, + struct user_arg_ptr envp, + struct pt_regs *regs) { struct linux_binprm *bprm; struct file *file; @@@ -1489,6 -1536,34 +1536,34 @@@ out_ret return retval; } + int do_execve(const char *filename, + const char __user *const __user *__argv, + const char __user *const __user *__envp, + struct pt_regs *regs) + { + struct user_arg_ptr argv = { .ptr.native = __argv }; + struct user_arg_ptr envp = { .ptr.native = __envp }; + return do_execve_common(filename, argv, envp, regs); + } + + #ifdef CONFIG_COMPAT + int compat_do_execve(char *filename, + compat_uptr_t __user *__argv, + compat_uptr_t __user *__envp, + struct pt_regs *regs) + { + struct user_arg_ptr argv = { + .is_compat = true, + .ptr.compat = __argv, + }; + struct user_arg_ptr envp = { + .is_compat = true, + .ptr.compat = __envp, + }; + return do_execve_common(filename, argv, envp, regs); + } + #endif + void set_binfmt(struct linux_binfmt *new) { struct mm_struct *mm = current->mm; @@@ -1659,7 -1734,6 +1734,7 @@@ static int zap_process(struct task_stru t = start; do { + task_clear_group_stop_pending(t); if (t != current && t->mm) { sigaddset(&t->pending.signal, SIGKILL); signal_wake_up(t, 1);