[patch] thread-exec-fix-2.5.35-A5, BK-curr

From: Ingo Molnar (mingo@elte.hu)
Date: Mon Sep 16 2002 - 06:03:22 EST


the attached patch (against BK-curr) fixes a number of sys_execve()
problems:

 - ptrace of thread groups over exec works again.

 - if the exec() is done in a non-leader thread then we must inherit the
   parent links properly - otherwise the shell will see an early
   child-exit notification.

 - if the exec()-ing thread is detached then make it use SIGCHLD like the
   leader thread.

 - wait for the leader thread to become TASK_ZOMBIE properly -
   wait_task_inactive() alone was not enough. This should be a rare
   codepath.

now sys_execve() from thread groups works as expected in every combination
i could test: standalone, from the leader thread, from one of the child
threads, ptraced, non-ptraced, SMP and UP.

        Ingo

--- linux/fs/exec.c.orig Mon Sep 16 11:11:34 2002
+++ linux/fs/exec.c Mon Sep 16 12:53:00 2002
@@ -41,6 +41,7 @@
 #include <linux/module.h>
 #include <linux/namei.h>
 #include <linux/proc_fs.h>
+#include <linux/ptrace.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
@@ -577,11 +578,17 @@
          * and to assume its PID:
          */
         if (current->pid != current->tgid) {
- struct task_struct *leader = current->group_leader;
+ struct task_struct *leader = current->group_leader, *parent;
                 struct dentry *proc_dentry1, *proc_dentry2;
- unsigned long state;
+ unsigned long state, ptrace;
 
- wait_task_inactive(leader);
+ /*
+ * Wait for the thread group leader to be a zombie.
+ * It should already be zombie at this point, most
+ * of the time.
+ */
+ while (leader->state != TASK_ZOMBIE)
+ yield();
 
                 write_lock_irq(&tasklist_lock);
                 proc_dentry1 = clean_proc_dentry(current);
@@ -597,10 +604,33 @@
                  * two threads with a switched PID, and release
                  * the former thread group leader:
                  */
+ ptrace = leader->ptrace;
+ parent = leader->parent;
+
+ ptrace_unlink(leader);
+ ptrace_unlink(current);
                 unhash_pid(current);
                 unhash_pid(leader);
+ remove_parent(current);
+ remove_parent(leader);
+ /*
+ * Split up the last two remaining members of the
+ * thread group:
+ */
+ list_del_init(&leader->thread_group);
+
                 leader->pid = leader->tgid = current->pid;
                 current->pid = current->tgid;
+ current->parent = current->real_parent = leader->real_parent;
+ leader->parent = leader->real_parent = child_reaper;
+ current->exit_signal = SIGCHLD;
+
+ add_parent(current, current->parent);
+ add_parent(leader, leader->parent);
+ if (ptrace) {
+ current->ptrace = ptrace;
+ __ptrace_link(current, parent);
+ }
                 hash_pid(current);
                 hash_pid(leader);
                 
@@ -608,8 +638,9 @@
                 state = leader->state;
                 write_unlock_irq(&tasklist_lock);
 
- if (state == TASK_ZOMBIE)
- release_task(leader);
+ if (state != TASK_ZOMBIE)
+ BUG();
+ release_task(leader);
 
                 put_proc_dentry(proc_dentry1);
                 put_proc_dentry(proc_dentry2);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Mon Sep 23 2002 - 22:00:16 EST