[PATCH 07] rework prepare_ptrace_attach/finish_ptrace_attach
Oleg Nesterov
oleg at redhat.com
Mon Aug 17 15:22:58 UTC 2009
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;
}
/**
More information about the utrace-devel
mailing list