mirror of https://gitee.com/openkylin/linux.git
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 <mcermak@redhat.com> Reported-by: David Smith <dsmith@redhat.com> Signed-off-by: Oleg Nesterov <oleg@redhat.com>
This commit is contained in:
parent
aa59c53fd4
commit
3ab6796617
|
@ -117,7 +117,7 @@ extern void uprobe_start_dup_mmap(void);
|
|||
extern void uprobe_end_dup_mmap(void);
|
||||
extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm);
|
||||
extern void uprobe_free_utask(struct task_struct *t);
|
||||
extern void uprobe_copy_process(struct task_struct *t);
|
||||
extern void uprobe_copy_process(struct task_struct *t, unsigned long flags);
|
||||
extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs);
|
||||
extern int uprobe_post_sstep_notifier(struct pt_regs *regs);
|
||||
extern int uprobe_pre_sstep_notifier(struct pt_regs *regs);
|
||||
|
@ -174,7 +174,7 @@ static inline unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
|
|||
static inline void uprobe_free_utask(struct task_struct *t)
|
||||
{
|
||||
}
|
||||
static inline void uprobe_copy_process(struct task_struct *t)
|
||||
static inline void uprobe_copy_process(struct task_struct *t, unsigned long flags)
|
||||
{
|
||||
}
|
||||
static inline void uprobe_clear_state(struct mm_struct *mm)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1489,7 +1489,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
|||
perf_event_fork(p);
|
||||
|
||||
trace_task_newtask(p, clone_flags);
|
||||
uprobe_copy_process(p);
|
||||
uprobe_copy_process(p, clone_flags);
|
||||
|
||||
return p;
|
||||
|
||||
|
|
Loading…
Reference in New Issue