Commit 25f0da24 authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

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

This 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.
parent 3568bea5
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/ptrace.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
...@@ -577,11 +578,17 @@ static inline int de_thread(struct signal_struct *oldsig) ...@@ -577,11 +578,17 @@ static inline int de_thread(struct signal_struct *oldsig)
* and to assume its PID: * and to assume its PID:
*/ */
if (current->pid != current->tgid) { 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; 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); write_lock_irq(&tasklist_lock);
proc_dentry1 = clean_proc_dentry(current); proc_dentry1 = clean_proc_dentry(current);
...@@ -597,10 +604,33 @@ static inline int de_thread(struct signal_struct *oldsig) ...@@ -597,10 +604,33 @@ static inline int de_thread(struct signal_struct *oldsig)
* two threads with a switched PID, and release * two threads with a switched PID, and release
* the former thread group leader: * the former thread group leader:
*/ */
ptrace = leader->ptrace;
parent = leader->parent;
ptrace_unlink(leader);
ptrace_unlink(current);
unhash_pid(current); unhash_pid(current);
unhash_pid(leader); 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; leader->pid = leader->tgid = current->pid;
current->pid = current->tgid; 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(current);
hash_pid(leader); hash_pid(leader);
...@@ -608,8 +638,9 @@ static inline int de_thread(struct signal_struct *oldsig) ...@@ -608,8 +638,9 @@ static inline int de_thread(struct signal_struct *oldsig)
state = leader->state; state = leader->state;
write_unlock_irq(&tasklist_lock); write_unlock_irq(&tasklist_lock);
if (state == TASK_ZOMBIE) if (state != TASK_ZOMBIE)
release_task(leader); BUG();
release_task(leader);
put_proc_dentry(proc_dentry1); put_proc_dentry(proc_dentry1);
put_proc_dentry(proc_dentry2); put_proc_dentry(proc_dentry2);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment