uprobes: Teach uprobe_copy_process() to handle CLONE_VFORK

uprobe_copy_process() does nothing if the child shares ->mm with
the forking process, but there is a special case: CLONE_VFORK.
In this case it would be more correct to do dup_utask() but avoid
dup_xol(). This is not that important, the child should not unwind
its stack too much, this can corrupt the parent's stack, but at
least we need this to allow to ret-probe __vfork() itself.

Note: in theory, it would be better to check task_pt_regs(p)->sp
instead of CLONE_VFORK, we need to dup_utask() if and only if the
child can return from the function called by the parent. But this
needs the arch-dependant helper, and I think that nobody actually
does clone(same_stack, CLONE_VM).

Reported-by: Martin Cermak <[email protected]>
Reported-by: David Smith <[email protected]>
Signed-off-by: Oleg Nesterov <[email protected]>
This commit is contained in:
Oleg Nesterov 2013-10-16 19:39:37 +02:00
commit 3ab6796617
3 changed files with 11 additions and 5 deletions

View file

@ -1415,7 +1415,7 @@ static void dup_xol_work(struct callback_head *work)
/*
* Called in context of a new clone/fork from copy_process.
*/
void uprobe_copy_process(struct task_struct *t)
void uprobe_copy_process(struct task_struct *t, unsigned long flags)
{
struct uprobe_task *utask = current->utask;
struct mm_struct *mm = current->mm;
@ -1424,7 +1424,10 @@ void uprobe_copy_process(struct task_struct *t)
t->utask = NULL;
if (mm == t->mm || !utask || !utask->return_instances)
if (!utask || !utask->return_instances)
return;
if (mm == t->mm && !(flags & CLONE_VFORK))
return;
if (dup_utask(t, utask))
@ -1435,6 +1438,9 @@ void uprobe_copy_process(struct task_struct *t)
if (!area)
return uprobe_warn(t, "dup xol area");
if (mm == t->mm)
return;
/* TODO: move it into the union in uprobe_task */
work = kmalloc(sizeof(*work), GFP_KERNEL);
if (!work)