exec: replace call_usermodehelper_pipe with use of umh init function and resolve...
[safe/jmp/linux-2.6] / fs / exec.c
index da2b31d..63f459c 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -242,9 +242,10 @@ static int __bprm_mm_init(struct linux_binprm *bprm)
         * use STACK_TOP because that can depend on attributes which aren't
         * configured yet.
         */
+       BUG_ON(VM_STACK_FLAGS & VM_STACK_INCOMPLETE_SETUP);
        vma->vm_end = STACK_TOP_MAX;
        vma->vm_start = vma->vm_end - PAGE_SIZE;
-       vma->vm_flags = VM_STACK_FLAGS;
+       vma->vm_flags = VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP;
        vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
        INIT_LIST_HEAD(&vma->anon_vma_chain);
        err = insert_vm_struct(mm, vma);
@@ -616,6 +617,7 @@ int setup_arg_pages(struct linux_binprm *bprm,
        else if (executable_stack == EXSTACK_DISABLE_X)
                vm_flags &= ~VM_EXEC;
        vm_flags |= mm->def_flags;
+       vm_flags |= VM_STACK_INCOMPLETE_SETUP;
 
        ret = mprotect_fixup(vma, &prev, vma->vm_start, vma->vm_end,
                        vm_flags);
@@ -630,6 +632,9 @@ int setup_arg_pages(struct linux_binprm *bprm,
                        goto out_unlock;
        }
 
+       /* mprotect_fixup is overkill to remove the temporary stack flags */
+       vma->vm_flags &= ~VM_STACK_INCOMPLETE_SETUP;
+
        stack_expand = 131072UL; /* randomly 32*4k (or 2*64k) pages */
        stack_size = vma->vm_end - vma->vm_start;
        /*
@@ -1387,8 +1392,6 @@ int do_execve(char * filename,
        if (retval < 0)
                goto out;
 
-       current->stack_start = current->mm->start_stack;
-
        /* execve succeeded */
        current->fs->in_exec = 0;
        current->in_execve = 0;
@@ -1561,12 +1564,13 @@ out:
        return ispipe;
 }
 
-static int zap_process(struct task_struct *start)
+static int zap_process(struct task_struct *start, int exit_code)
 {
        struct task_struct *t;
        int nr = 0;
 
        start->signal->flags = SIGNAL_GROUP_EXIT;
+       start->signal->group_exit_code = exit_code;
        start->signal->group_stop_count = 0;
 
        t = start;
@@ -1591,8 +1595,7 @@ static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
        spin_lock_irq(&tsk->sighand->siglock);
        if (!signal_group_exit(tsk->signal)) {
                mm->core_state = core_state;
-               tsk->signal->group_exit_code = exit_code;
-               nr = zap_process(tsk);
+               nr = zap_process(tsk, exit_code);
        }
        spin_unlock_irq(&tsk->sighand->siglock);
        if (unlikely(nr < 0))
@@ -1641,7 +1644,7 @@ static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
                        if (p->mm) {
                                if (unlikely(p->mm == mm)) {
                                        lock_task_sighand(p, &flags);
-                                       nr += zap_process(p);
+                                       nr += zap_process(p, exit_code);
                                        unlock_task_sighand(p, &flags);
                                }
                                break;
@@ -1748,14 +1751,19 @@ void set_dumpable(struct mm_struct *mm, int value)
        }
 }
 
-int get_dumpable(struct mm_struct *mm)
+static int __get_dumpable(unsigned long mm_flags)
 {
        int ret;
 
-       ret = mm->flags & 0x3;
+       ret = mm_flags & MMF_DUMPABLE_MASK;
        return (ret >= 2) ? 2 : ret;
 }
 
+int get_dumpable(struct mm_struct *mm)
+{
+       return __get_dumpable(mm->flags);
+}
+
 static void wait_for_dump_helpers(struct file *file)
 {
        struct pipe_inode_info *pipe;
@@ -1779,6 +1787,50 @@ static void wait_for_dump_helpers(struct file *file)
 }
 
 
+/*
+ * uhm_pipe_setup
+ * helper function to customize the process used
+ * to collect the core in userspace.  Specifically
+ * it sets up a pipe and installs it as fd 0 (stdin)
+ * for the process.  Returns 0 on success, or
+ * PTR_ERR on failure.
+ * Note that it also sets the core limit to 1.  This
+ * is a special value that we use to trap recursive
+ * core dumps
+ */
+static int umh_pipe_setup(struct subprocess_info *info)
+{
+       struct file *rp, *wp;
+       struct fdtable *fdt;
+       struct coredump_params *cp = (struct coredump_params *)info->data;
+       struct files_struct *cf = current->files;
+
+       wp = create_write_pipe(0);
+       if (IS_ERR(wp))
+               return PTR_ERR(wp);
+
+       rp = create_read_pipe(wp, 0);
+       if (IS_ERR(rp)) {
+               free_write_pipe(wp);
+               return PTR_ERR(rp);
+       }
+
+       cp->file = wp;
+
+       sys_close(0);
+       fd_install(0, rp);
+       spin_lock(&cf->file_lock);
+       fdt = files_fdtable(cf);
+       FD_SET(0, fdt->open_fds);
+       FD_CLR(0, fdt->close_on_exec);
+       spin_unlock(&cf->file_lock);
+
+       /* and disallow core files too */
+       current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1};
+
+       return 0;
+}
+
 void do_coredump(long signr, int exit_code, struct pt_regs *regs)
 {
        struct core_state core_state;
@@ -1799,6 +1851,12 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
                .signr = signr,
                .regs = regs,
                .limit = rlimit(RLIMIT_CORE),
+               /*
+                * We must use the same mm->flags while dumping core to avoid
+                * inconsistency of bit flags, since this flag is not protected
+                * by any locks.
+                */
+               .mm_flags = mm->flags,
        };
 
        audit_core_dumps(signr);
@@ -1817,7 +1875,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
        /*
         * If another thread got here first, or we are not dumpable, bail out.
         */
-       if (mm->core_state || !get_dumpable(mm)) {
+       if (mm->core_state || !__get_dumpable(cprm.mm_flags)) {
                up_write(&mm->mmap_sem);
                put_cred(cred);
                goto fail;
@@ -1828,7 +1886,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
         *      process nor do we know its entire history. We only know it
         *      was tainted so we dump it as root in mode 2.
         */
-       if (get_dumpable(mm) == 2) {    /* Setuid core dump mode */
+       if (__get_dumpable(cprm.mm_flags) == 2) {
+               /* Setuid core dump mode */
                flag = O_EXCL;          /* Stop rewrite attacks */
                cred->fsuid = 0;        /* Dump root private */
        }
@@ -1859,15 +1918,15 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
                goto fail_unlock;
 
        if (ispipe) {
-               if (cprm.limit == 0) {
+               if (cprm.limit == 1) {
                        /*
                         * Normally core limits are irrelevant to pipes, since
                         * we're not writing to the file system, but we use
-                        * cprm.limit of 0 here as a speacial value. Any
-                        * non-zero limit gets set to RLIM_INFINITY below, but
+                        * cprm.limit of 1 here as a speacial value. Any
+                        * non-1 limit gets set to RLIM_INFINITY below, but
                         * a limit of 0 skips the dump.  This is a consistent
                         * way to catch recursive crashes.  We can still crash
-                        * if the core_pattern binary sets RLIM_CORE =  !0
+                        * if the core_pattern binary sets RLIM_CORE =  !1
                         * but it runs as root, and can do lots of stupid things
                         * Note that we use task_tgid_vnr here to grab the pid
                         * of the process group leader.  That way we get the
@@ -1875,7 +1934,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
                         * core_pattern process dies.
                         */
                        printk(KERN_WARNING
-                               "Process %d(%s) has RLIMIT_CORE set to 0\n",
+                               "Process %d(%s) has RLIMIT_CORE set to 1\n",
                                task_tgid_vnr(current), current->comm);
                        printk(KERN_WARNING "Aborting core\n");
                        goto fail_unlock;
@@ -1899,8 +1958,13 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
                cprm.limit = RLIM_INFINITY;
 
                /* SIGPIPE can happen, but it's just never processed */
-               if (call_usermodehelper_pipe(helper_argv[0], helper_argv, NULL,
-                               &cprm.file)) {
+               cprm.file = NULL;
+               if (call_usermodehelper_fns(helper_argv[0], helper_argv, NULL,
+                                           UMH_WAIT_EXEC, umh_pipe_setup,
+                                           NULL, &cprm)) {
+                       if (cprm.file)
+                               filp_close(cprm.file, NULL);
+
                        printk(KERN_INFO "Core dump to %s pipe failed\n",
                               corename);
                        goto fail_dropcount;
@@ -1924,8 +1988,9 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
        /*
         * Dont allow local users get cute and trick others to coredump
         * into their pre-created files:
+        * Note, this is not relevant for pipes
         */
-       if (inode->i_uid != current_fsuid())
+       if (!ispipe && (inode->i_uid != current_fsuid()))
                goto close_fail;
        if (!cprm.file->f_op)
                goto close_fail;