Commit 83d936cb authored by Daniel Jacobowitz's avatar Daniel Jacobowitz Committed by Linus Torvalds

[PATCH] More ptrace fixes for 2.5.33

Here are the changes I have

  - Fix some bugs I introduced in zap_thread
  - Improve the check for traced children in sys_wait4
  - Fix parent links when using CLONE_PTRACE

My thanks to OGAWA Hirofumi for pointing out the first bit.

The only other issue I know of is something else Hirofumi pointed out
earlier; there are problems when a tracing process dies unexpectedly.  I'll
come back to that later.
parent e3d280b3
...@@ -449,15 +449,19 @@ static inline void forget_original_parent(struct task_struct * father) ...@@ -449,15 +449,19 @@ static inline void forget_original_parent(struct task_struct * father)
static inline void zap_thread(task_t *p, task_t *father, int traced) static inline void zap_thread(task_t *p, task_t *father, int traced)
{ {
/* If we were tracing the thread, release it; otherwise preserve the /* If someone else is tracing this thread, preserve the ptrace links. */
ptrace links. */
if (unlikely(traced)) { if (unlikely(traced)) {
task_t *trace_task = p->parent; task_t *trace_task = p->parent;
int ptrace_flag = p->ptrace;
BUG_ON (ptrace_flag == 0);
__ptrace_unlink(p); __ptrace_unlink(p);
p->ptrace = 1; p->ptrace = ptrace_flag;
__ptrace_link(p, trace_task); __ptrace_link(p, trace_task);
} else { } else {
p->ptrace = 0; /* Otherwise, if we were tracing this thread, untrace it. */
ptrace_unlink (p);
list_del_init(&p->sibling); list_del_init(&p->sibling);
p->parent = p->real_parent; p->parent = p->real_parent;
list_add_tail(&p->sibling, &p->parent->children); list_add_tail(&p->sibling, &p->parent->children);
...@@ -646,42 +650,26 @@ asmlinkage long sys_exit(int error_code) ...@@ -646,42 +650,26 @@ asmlinkage long sys_exit(int error_code)
do_exit((error_code&0xff)<<8); do_exit((error_code&0xff)<<8);
} }
asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru) static inline int eligible_child(pid_t pid, int options, task_t *p)
{ {
int flag, retval;
DECLARE_WAITQUEUE(wait, current);
struct task_struct *tsk;
if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL))
return -EINVAL;
add_wait_queue(&current->wait_chldexit,&wait);
repeat:
flag = 0;
current->state = TASK_INTERRUPTIBLE;
read_lock(&tasklist_lock);
tsk = current;
do {
struct task_struct *p;
struct list_head *_p;
list_for_each(_p,&tsk->children) {
p = list_entry(_p,struct task_struct,sibling);
if (pid>0) { if (pid>0) {
if (p->pid != pid) if (p->pid != pid)
continue; return 0;
} else if (!pid) { } else if (!pid) {
if (p->pgrp != current->pgrp) if (p->pgrp != current->pgrp)
continue; return 0;
} else if (pid != -1) { } else if (pid != -1) {
if (p->pgrp != -pid) if (p->pgrp != -pid)
continue; return 0;
} }
/* /*
* Do not consider detached threads that are * Do not consider detached threads that are
* not ptraced: * not ptraced:
*/ */
if (p->exit_signal == -1 && !p->ptrace) if (p->exit_signal == -1 && !p->ptrace)
continue; return 0;
/* Wait for all children (clone and not) if __WALL is set; /* Wait for all children (clone and not) if __WALL is set;
* otherwise, wait for clone children *only* if __WCLONE is * otherwise, wait for clone children *only* if __WCLONE is
* set; otherwise, wait for non-clone children *only*. (Note: * set; otherwise, wait for non-clone children *only*. (Note:
...@@ -689,11 +677,36 @@ asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struc ...@@ -689,11 +677,36 @@ asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struc
* using a signal other than SIGCHLD.) */ * using a signal other than SIGCHLD.) */
if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0)) if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
&& !(options & __WALL)) && !(options & __WALL))
continue; return 0;
if (security_ops->task_wait(p)) if (security_ops->task_wait(p))
continue; return 0;
return 1;
}
asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru)
{
int flag, retval;
DECLARE_WAITQUEUE(wait, current);
struct task_struct *tsk;
if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL))
return -EINVAL;
add_wait_queue(&current->wait_chldexit,&wait);
repeat:
flag = 0;
current->state = TASK_INTERRUPTIBLE;
read_lock(&tasklist_lock);
tsk = current;
do {
struct task_struct *p;
struct list_head *_p;
list_for_each(_p,&tsk->children) {
p = list_entry(_p,struct task_struct,sibling);
if (!eligible_child(pid, options, p))
continue;
flag = 1; flag = 1;
switch (p->state) { switch (p->state) {
case TASK_STOPPED: case TASK_STOPPED:
...@@ -738,12 +751,21 @@ asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struc ...@@ -738,12 +751,21 @@ asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struc
continue; continue;
} }
} }
if (!flag) {
list_for_each (_p,&tsk->ptrace_children) {
p = list_entry(_p,struct task_struct,ptrace_list);
if (!eligible_child(pid, options, p))
continue;
flag = 1;
break;
}
}
if (options & __WNOTHREAD) if (options & __WNOTHREAD)
break; break;
tsk = next_thread(tsk); tsk = next_thread(tsk);
} while (tsk != current); } while (tsk != current);
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
if (flag || !list_empty(&current->ptrace_children)) { if (flag) {
retval = 0; retval = 0;
if (options & WNOHANG) if (options & WNOHANG)
goto end_wait4; goto end_wait4;
......
...@@ -836,13 +836,11 @@ static struct task_struct *copy_process(unsigned long clone_flags, ...@@ -836,13 +836,11 @@ static struct task_struct *copy_process(unsigned long clone_flags,
write_lock_irq(&tasklist_lock); write_lock_irq(&tasklist_lock);
/* CLONE_PARENT re-uses the old parent */ /* CLONE_PARENT re-uses the old parent */
if (clone_flags & CLONE_PARENT)
p->real_parent = current->real_parent; p->real_parent = current->real_parent;
p->parent = current->parent; else
if (!(clone_flags & CLONE_PARENT)) {
p->real_parent = current; p->real_parent = current;
if (!(p->ptrace & PT_PTRACED)) p->parent = p->real_parent;
p->parent = current;
}
if (clone_flags & CLONE_THREAD) { if (clone_flags & CLONE_THREAD) {
p->tgid = current->tgid; p->tgid = current->tgid;
...@@ -850,7 +848,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, ...@@ -850,7 +848,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
} }
SET_LINKS(p); SET_LINKS(p);
ptrace_link(p, p->parent); if (p->ptrace & PT_PTRACED)
__ptrace_link(p, current->parent);
hash_pid(p); hash_pid(p);
nr_threads++; nr_threads++;
write_unlock_irq(&tasklist_lock); write_unlock_irq(&tasklist_lock);
......
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