First of all, I believe ptrace_check_attach() is buggy. It lacks
"child->parent == current" or "engine->data == current" check.
The bug is serious, sys_ptrace() does not do security checks unless
request == PTRACE_ATTACH. But this is trivial to fix.


Also. Without utrace, ptrace_check_attach() requires the child
is STOPPED or TRACED. With utrace, ptrace_check_attach() does
utrace_control(UTRACE_STOP) first. If the child is not stopped
we return -ESRCH correctly, but utrace_control() sets ENGINE_STOP
and utrace->report, and this can actually stop the child.

Yes, if ptracer does utrace_control(UTRACE_STOP), this doesn't
necessarily mean the child will stop. But, for example, suppose
that ptracer does sys_ptrace(WHATEVER) in a loop. In that case
it is possible that utrace_control(UTRACE_STOP) races with the
child doing utrace_resume()->start_callback(), and we can set
ENGINE_STOP right before start_callback() re-reads engine->flags
under "if (want & UTRACE_EVENT(QUIESCE))".

This is minor, but not good anyway. Unless I missed something.



And. From another thread,

        utrace_prepare_examine verifies that the target is blocked already,
        ...
        Note it does not in particular
        require the target be stopped, though does require the caller's engine
        used UTRACE_STOP.

Yes, but I am a bit worried about ptrace_check_attach() case...

For example, utrace_control(UTRACE_STOP)->utrace_do_stop() finds
the child inside utrace_report_jctl() path in TASK_STOPPED state,
sets utrace->stopped and returns true. After that utrace_report_jctl()
clears ->stopped and another engine's ->report_jctl does mutex_lock()
and sets ->state == TASK_INTERRUPTIBLE.

This means that ptrace_check_attach() can succeed while the child
can be waked up soon and do a lot more before it actually stops.

I don't see really bad implications though, just worried.

Oleg.

Reply via email to