ptracee data structures cleanup

Oleg Nesterov oleg at redhat.com
Mon Apr 20 18:37:18 UTC 2009


On 04/16, Roland McGrath wrote:
>
> But even that is a lot of hair for the incremental patches in the first
> several stages, I think.  So just never deallocate it, and:
>
> 	static inline int task_ptrace(struct task_struct *task)
> 	{
> 		return unlikely(task->ptrace_child) ? task->ptrace_child->flags : 0;
> 	}

OK, agreed.

Except... personally I dislike ->flags, it is not greppable.

> > even ptracer can't safely access
> > child->ptrace_child->ptrace_flags. Once sys_ptrace() drops tasklist,
> > child's sub-thread can do exec, and de_thread() can untrace the child
> > and free ->ptrace_child.
>
> This kind of trouble is why going to dynamic allocation should start
> with never-deallocate (i.e. until release_task or something).

Yes, except release_task() doesn't work. I think it should be freed
by __put_task_struct(). Proc can read ->ptrace_child and race with
release_task().

> > 		// was task_struct->parent
> > 		struct task_struct *ptrace_parent;
>
> struct ptrace_task.tracer, please. :-)

OK. I'll send the first patch (or 2 patches) which introduces ptrace_task
and moves ->ptrace into it tomorrow. The patch is simple, but intrusive.


Now the questions. First of all, what does task_lock() currently mean
from the ptrace pov ?

Afaics ptrace_attach() needs this lock only to pin ->mm, no other other
reasons. ptrace_traceme() doesn't need it at all.

The comment above tracehook_unsafe_exec() says "Called with task_lock()",
this is wrong, check_unsafe_exec() doesn't take task_lock().

The only place which believes task_lock() can help is sys_execve() on
some arches, the code clears PT_DTRACE under task_lock(). Why, and what
PT_DTRACE actually means?

I don't understand PT_DTRACE, but looking at the code I assume it can
only be set when the task is ptraced. Right?

arch/m68k/kernel/traps.c:trap_c() does current->ptrace |= PT_DTRACE.
Again, can I assume this can only happen when the task is already
traced? Otherwise, we have a problem with allocationg of ->ptrace_task
(and this is racy with ptrace_attach of course).

Perhaps it makes sense to do a little cleanup first, introduce

	ptrace_clear_dtrace(void)
	{
		if (unlikely(current->ptrace & PT_DTRACE))
			current->ptrace &= ~PT_DTRACE;
	}

This can't race with the tracer, it never changes ->ptrace flags until
the tracee is TASK_TRACED.

The last question. ptrace_attach() does

	task->ptrace |= PT_PTRACED;

Why can't we use the plain "=" instead of "|=" ? This looks as if ->ptrace
can be nonzero even if the task is not traced. But I assume this is not
possible? And any code which does "if (p->ptrace & PT_TRACED)" could just
do "if (p->ptrace)", right?

Oleg.




More information about the utrace-devel mailing list