[PATCH 08] change ptrace_traceme() to use the new helpers, kill prepare/finish attach
Oleg Nesterov
oleg at redhat.com
Mon Aug 17 15:23:00 UTC 2009
Change ptrace_traceme() to use the new helpers. Kill the now unused
prepare_ptrace_attach/finish_ptrace_attach.
finish_ptrace_attach(ret) logic was wrong. If ->parent has PF_EXITING
we must UTRACE_DETACH but ret == 0. Fix this.
Note: we attach the new engine unconditionally, before security check.
Not good, another task can do ptrace_attach() and get EPERM. Hopefully
we can live with this race, or somehow fix it later.
But security_ptrace_traceme() is strange anyway, I never understood it.
It is called under tasklist_lock, but I can't see how this lock can
help. ->parent can change its creds right after the check.
Somehow with the last 2 patches the kernel survives after make xcheck.
A lot of warning from ptrace_resumed()->WARN_ON(task->last_siginfo != info)
but forget_original_parent()->BUG_ON(task_ptrace(p)) has gone away.
I don't understand how this was "fixed", this means I missed something :/
I am ignoring ptrace_report_clone() for now. I think it should not
rely on tracehook_finish_clone/tracehook_report_clone(). Instead it
should do all work itself, we have PF_STARTING. In that case it can
share the code with ptrace_traceme().
---
kernel/ptrace.c | 53 +++++------------------------------------------------
1 file changed, 5 insertions(+), 48 deletions(-)
--- PU/kernel/ptrace.c~08_TRACEME 2009-08-17 15:31:07.000000000 +0200
+++ PU/kernel/ptrace.c 2009-08-17 16:05:21.000000000 +0200
@@ -464,52 +464,6 @@ static const struct utrace_engine_ops pt
};
/*
- * Detach the utrace engine on error. On success, set @engine->data to
- * the ptracer's task_struct pointer. This distinguishes an engine for
- * attached ptrace from an engine left behind after a PTRACE_DETACH call
- * that left a parting signal to deliver.
- */
-static int finish_ptrace_attach(struct task_struct *task,
- struct utrace_engine *engine,
- int retval)
-{
- if (retval) {
- int error = utrace_control(task, engine, UTRACE_DETACH);
- WARN_ON(error && error != -ESRCH && error != -EALREADY);
- }
-
- utrace_engine_put(engine);
- return retval;
-}
-
-/*
- * Attach a utrace engine for ptrace and set up its event mask.
- * Returns the engine pointer or an IS_ERR() pointer.
- */
-static struct utrace_engine *prepare_ptrace_attach(
- struct task_struct *child, struct task_struct *parent)
-{
- struct utrace_engine *engine;
-
- engine = utrace_attach_task(child, UTRACE_ATTACH_CREATE |
- UTRACE_ATTACH_EXCLUSIVE |
- UTRACE_ATTACH_MATCH_OPS,
- &ptrace_utrace_ops, NULL);
-
- if (IS_ERR(engine)) {
- if (engine != ERR_PTR(-ESRCH) &&
- engine != ERR_PTR(-ERESTARTNOINTR))
- engine = ERR_PTR(-EPERM);
- } else {
- int ret = ptrace_update_utrace(child, engine);
- if (ret)
- engine = ERR_PTR(finish_ptrace_attach(child, engine,
- -ESRCH));
- }
- return engine;
-}
-
-/*
* Attach a utrace engine for ptrace and set up its event mask.
* Returns error code or 0 on success.
*/
@@ -688,13 +642,13 @@ out:
*/
int ptrace_traceme(void)
{
- int ret = -EPERM;
- struct utrace_engine *engine;
+ bool detach = true;
+ int ret = ptrace_attach_task(current);
- engine = prepare_ptrace_attach(current, current->parent);
- if (unlikely(IS_ERR(engine)))
- return PTR_ERR(engine);
+ if (unlikely(ret))
+ return ret;
+ ret = -EPERM;
write_lock_irq(&tasklist_lock);
/* Are we already being traced? */
if (!current->ptrace) {
@@ -707,11 +661,14 @@ int ptrace_traceme(void)
if (!ret && !(current->real_parent->flags & PF_EXITING)) {
current->ptrace = PT_PTRACED;
__ptrace_link(current, current->real_parent);
+ detach = false;
}
}
write_unlock_irq(&tasklist_lock);
- return finish_ptrace_attach(current, engine, ret);
+ if (detach)
+ ptrace_abort_attach(current);
+ return ret;
}
/*
More information about the utrace-devel
mailing list