forked from Minki/linux
ftrace: fix race in function graph during fork
Impact: graph tracer race/crash fix There is a nasy race in startup of a new process running the function graph tracer. In fork.c: total_forks++; spin_unlock(¤t->sighand->siglock); write_unlock_irq(&tasklist_lock); ftrace_graph_init_task(p); proc_fork_connector(p); cgroup_post_fork(p); return p; The new task is free to run as soon as the tasklist_lock is released. This is before the ftrace_graph_init_task. If the task does run it will be using the same ret_stack and curr_ret_stack as the parent. This will cause crashes that are difficult to debug. This patch moves the ftrace_graph_init_task to just after the alloc_pid code. This fixes the above race. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
0a37119d96
commit
e8e1abe92f
@ -1137,6 +1137,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ftrace_graph_init_task(p);
|
||||||
|
|
||||||
p->pid = pid_nr(pid);
|
p->pid = pid_nr(pid);
|
||||||
p->tgid = p->pid;
|
p->tgid = p->pid;
|
||||||
if (clone_flags & CLONE_THREAD)
|
if (clone_flags & CLONE_THREAD)
|
||||||
@ -1145,7 +1147,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
|||||||
if (current->nsproxy != p->nsproxy) {
|
if (current->nsproxy != p->nsproxy) {
|
||||||
retval = ns_cgroup_clone(p, pid);
|
retval = ns_cgroup_clone(p, pid);
|
||||||
if (retval)
|
if (retval)
|
||||||
goto bad_fork_free_pid;
|
goto bad_fork_free_graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
|
p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
|
||||||
@ -1238,7 +1240,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
|||||||
spin_unlock(¤t->sighand->siglock);
|
spin_unlock(¤t->sighand->siglock);
|
||||||
write_unlock_irq(&tasklist_lock);
|
write_unlock_irq(&tasklist_lock);
|
||||||
retval = -ERESTARTNOINTR;
|
retval = -ERESTARTNOINTR;
|
||||||
goto bad_fork_free_pid;
|
goto bad_fork_free_graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clone_flags & CLONE_THREAD) {
|
if (clone_flags & CLONE_THREAD) {
|
||||||
@ -1271,11 +1273,12 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
|||||||
total_forks++;
|
total_forks++;
|
||||||
spin_unlock(¤t->sighand->siglock);
|
spin_unlock(¤t->sighand->siglock);
|
||||||
write_unlock_irq(&tasklist_lock);
|
write_unlock_irq(&tasklist_lock);
|
||||||
ftrace_graph_init_task(p);
|
|
||||||
proc_fork_connector(p);
|
proc_fork_connector(p);
|
||||||
cgroup_post_fork(p);
|
cgroup_post_fork(p);
|
||||||
return p;
|
return p;
|
||||||
|
|
||||||
|
bad_fork_free_graph:
|
||||||
|
ftrace_graph_exit_task(p);
|
||||||
bad_fork_free_pid:
|
bad_fork_free_pid:
|
||||||
if (pid != &init_struct_pid)
|
if (pid != &init_struct_pid)
|
||||||
free_pid(pid);
|
free_pid(pid);
|
||||||
|
Loading…
Reference in New Issue
Block a user