aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/include/linux/ptrace.h
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2011-06-24 17:34:06 +0200
committerOleg Nesterov <oleg@redhat.com>2011-06-27 20:30:10 +0200
commit0347e17739095c58c0194fed6a61aced3536d258 (patch)
tree9eaed0f012a7ee6890ccda9beddda2a1246c3111 /include/linux/ptrace.h
parentredefine thread_group_leader() as exit_signal >= 0 (diff)
downloadwireguard-linux-0347e17739095c58c0194fed6a61aced3536d258.tar.xz
wireguard-linux-0347e17739095c58c0194fed6a61aced3536d258.zip
ptrace: ptrace_reparented() should check same_thread_group()
ptrace_reparented() naively does parent != real_parent, this means it returns true even if the tracer _is_ the real parent. This is per process thing, not per-thread. The only reason ->real_parent can point to the non-leader thread is that we have __WNOTHREAD. Change it to check !same_thread_group(parent, real_parent). It has two callers, and in both cases the current check does not look right. exit_notify: we should respect ->exit_signal if the exiting leader is traced by any thread from the parent thread group. It is the child of the whole group, and we are going to send the signal to the whole group. wait_task_zombie: without __WNOTHREAD do_wait() should do the same for any thread, only sys_ptrace() is "bound" to the single thread. However do_wait(WEXITED) succeeds but does not release a traced natural child unless the caller is the tracer. Test-case: void *tfunc(void *arg) { assert(ptrace(PTRACE_ATTACH, (long)arg, 0,0) == 0); pause(); return NULL; } int main(void) { pthread_t thr; pid_t pid, stat, ret; pid = fork(); if (!pid) { pause(); assert(0); } assert(pthread_create(&thr, NULL, tfunc, (void*)(long)pid) == 0); assert(waitpid(-1, &stat, 0) == pid); assert(WIFSTOPPED(stat)); kill(pid, SIGKILL); assert(waitpid(-1, &stat, 0) == pid); assert(WIFSIGNALED(stat) && WTERMSIG(stat) == SIGKILL); ret = waitpid(pid, &stat, 0); if (ret < 0) return 0; printf("WTF? %d is dead, but: wait=%d stat=%x\n", pid, ret, stat); return 1; } Note that the main thread simply does pid = fork(); kill(pid, SIGKILL); and then without the patch wait4(WEXITED) succeeds twice and reports WTERMSIG(stat) == SIGKILL. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'include/linux/ptrace.h')
-rw-r--r--include/linux/ptrace.h2
1 files changed, 1 insertions, 1 deletions
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index bb157bdd0c55..eae381d584f9 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -136,7 +136,7 @@ extern bool ptrace_may_access(struct task_struct *task, unsigned int mode);
static inline int ptrace_reparented(struct task_struct *child)
{
- return child->real_parent != child->parent;
+ return !same_thread_group(child->real_parent, child->parent);
}
static inline void ptrace_unlink(struct task_struct *child)