Introduce ptrace_attach_task() and ptrace_abort_attach(). There are simplified versions of prepare_ptrace_attach/finish_ptrace_attach and should be used instead. Change ptrace_attach() accordingly.
This patch doesn't kill the old helpers and doesn't change ptrace_traceme() because I noticed it has another bug. Note the "XXX" comment in ptrace_abort_attach(). I am not sure a simple UTRACE_DETACH is always correct. We already did utrace_set_events(), we must not, say, lose a signal if it comes in between. --- kernel/ptrace.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 8 deletions(-) --- PU/kernel/ptrace.c~07_ATTACH 2009-08-13 18:41:46.000000000 +0200 +++ PU/kernel/ptrace.c 2009-08-17 15:31:07.000000000 +0200 @@ -509,6 +509,46 @@ static struct utrace_engine *prepare_ptr return engine; } +/* + * Attach a utrace engine for ptrace and set up its event mask. + * Returns error code or 0 on success. + */ +static int ptrace_attach_task(struct task_struct *tracee) +{ + struct utrace_engine *engine; + unsigned long events; + + engine = utrace_attach_task(tracee, UTRACE_ATTACH_CREATE | + UTRACE_ATTACH_EXCLUSIVE | + UTRACE_ATTACH_MATCH_OPS, + &ptrace_utrace_ops, NULL); + if (unlikely(IS_ERR(engine))) { + int err = PTR_ERR(engine); + if (err != -ESRCH && err != -ERESTARTNOINTR) + err = -EPERM ; + return err; + } + /* + * We need QUIESCE for resume handling, CLONE to check + * for CLONE_PTRACE, other events are always reported. + */ + events = UTRACE_EVENT(QUIESCE) | UTRACE_EVENT(CLONE) | + UTRACE_EVENT(EXEC) | UTRACE_EVENT_SIGNAL_ALL; + /* + * It can fail only if the tracee is dead, the caller + * must notice this before setting PT_PTRACED. + */ + utrace_set_events(tracee, engine, events); + utrace_engine_put(engine); + return 0; +} + +static void ptrace_abort_attach(struct task_struct *tracee) +{ + /* XXX we raced with detach. Double check UTRACE_DETACH is enough */ + ptrace_detach_task(tracee, 0); +} + int ptrace_check_attach(struct task_struct *child, int kill) { struct utrace_engine *engine; @@ -587,19 +627,14 @@ bool ptrace_may_access(struct task_struc int ptrace_attach(struct task_struct *task) { int retval; - struct utrace_engine *engine; audit_ptrace(task); retval = -EPERM; if (unlikely(task->flags & PF_KTHREAD)) - return retval; + goto out; if (same_thread_group(task, current)) - return retval; - - engine = prepare_ptrace_attach(task, current); - if (unlikely(IS_ERR(engine))) - return PTR_ERR(engine); + goto out; /* * Protect exec's credential calculations against our interference; @@ -616,6 +651,10 @@ int ptrace_attach(struct task_struct *ta if (retval) goto unlock_creds; + retval = ptrace_attach_task(task); + if (unlikely(retval)) + goto unlock_creds; + write_lock_irq(&tasklist_lock); retval = -EPERM; if (unlikely(task->exit_state)) @@ -633,10 +672,12 @@ int ptrace_attach(struct task_struct *ta retval = 0; unlock_tasklist: write_unlock_irq(&tasklist_lock); + if (retval) + ptrace_abort_attach(task); unlock_creds: mutex_unlock(&task->cred_guard_mutex); out: - return finish_ptrace_attach(task, engine, retval); + return retval; } /**