ptrace: do_wait(traced_leader_killed_by_mt_exec) can block forever
[pandora-kernel.git] / fs / exec.c
index c3d517b..d219541 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -967,6 +967,14 @@ static int de_thread(struct task_struct *tsk)
 
                BUG_ON(leader->exit_state != EXIT_ZOMBIE);
                leader->exit_state = EXIT_DEAD;
+
+               /*
+                * We are going to release_task()->ptrace_unlink() silently,
+                * the tracer can sleep in do_wait(). EXIT_DEAD guarantees
+                * the tracer wont't block again waiting for this thread.
+                */
+               if (unlikely(leader->ptrace))
+                       __wake_up_parent(leader, leader->parent);
                write_unlock_irq(&tasklist_lock);
 
                release_task(leader);
@@ -1358,6 +1366,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
        unsigned int depth = bprm->recursion_depth;
        int try,retval;
        struct linux_binfmt *fmt;
+       pid_t old_pid;
 
        retval = security_bprm_check(bprm);
        if (retval)
@@ -1371,6 +1380,11 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
        if (retval)
                return retval;
 
+       /* Need to fetch pid before load_binary changes it */
+       rcu_read_lock();
+       old_pid = task_pid_nr_ns(current, task_active_pid_ns(current->parent));
+       rcu_read_unlock();
+
        retval = -ENOENT;
        for (try=0; try<2; try++) {
                read_lock(&binfmt_lock);
@@ -1390,7 +1404,8 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
                        bprm->recursion_depth = depth;
                        if (retval >= 0) {
                                if (depth == 0)
-                                       ptrace_event(PTRACE_EVENT_EXEC, 0);
+                                       ptrace_event(PTRACE_EVENT_EXEC,
+                                                       old_pid);
                                put_binfmt(fmt);
                                allow_write_access(bprm->file);
                                if (bprm->file)