Messages in this thread Patch in this message | | | Date | Sun, 8 Feb 2009 19:47:24 +0100 | From | Oleg Nesterov <> | Subject | [PATCH 1/3] ptrace_detach: the wrong wakeup breaks the ERESTARTxxx logic |
| |
Another ancient bug. Consider this trivial test-case,
int main(void) { int pid = fork();
if (pid) { ptrace(PTRACE_ATTACH, pid, NULL, NULL); wait(NULL); ptrace(PTRACE_DETACH, pid, NULL, NULL); } else { pause(); printf("WE HAVE A KERNEL BUG!!!\n"); }
return 0; }
the child must not "escape" for sys_pause(), but it can and this was seen in practice.
This is because ptrace_detach does:
if (!child->exit_state) wake_up_process(child);
this wakeup can happen after this child has already restarted sys_pause(), because it gets another wakeup from ptrace_untrace().
It is not clear to me what was the rationale, but this is obviously wrong. Remove this wakeup. The caller saw this task in TASK_TRACED state, and unless it was SIGKILL'ed in between __ptrace_unlink()->ptrace_untrace() should handle this case correctly. If it was SIGKILL'ed, we don't need to wakup the dying tracee too.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
--- 6.29-rc3/kernel/ptrace.c~1_KILL_WAKE 2009-02-08 04:26:57.000000000 +0100 +++ 6.29-rc3/kernel/ptrace.c 2009-02-08 05:11:52.000000000 +0100 @@ -250,11 +250,7 @@ int ptrace_detach(struct task_struct *ch /* protect against de_thread()->release_task() */ if (child->ptrace) { child->exit_code = data; - dead = __ptrace_detach(current, child); - - if (!child->exit_state) - wake_up_process(child); } write_unlock_irq(&tasklist_lock);
| |