| From 6c72e3501d0d62fc064d3680e5234f3463ec5a86 Mon Sep 17 00:00:00 2001 |
| From: Peter Zijlstra <peterz@infradead.org> |
| Date: Thu, 2 Oct 2014 16:17:02 -0700 |
| Subject: perf: fix perf bug in fork() |
| |
| From: Peter Zijlstra <peterz@infradead.org> |
| |
| commit 6c72e3501d0d62fc064d3680e5234f3463ec5a86 upstream. |
| |
| Oleg noticed that a cleanup by Sylvain actually uncovered a bug; by |
| calling perf_event_free_task() when failing sched_fork() we will not yet |
| have done the memset() on ->perf_event_ctxp[] and will therefore try and |
| 'free' the inherited contexts, which are still in use by the parent |
| process. This is bad.. |
| |
| Suggested-by: Oleg Nesterov <oleg@redhat.com> |
| Reported-by: Oleg Nesterov <oleg@redhat.com> |
| Reported-by: Sylvain 'ythier' Hitier <sylvain.hitier@gmail.com> |
| Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> |
| Cc: Ingo Molnar <mingo@kernel.org> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| kernel/events/core.c | 4 +++- |
| kernel/fork.c | 5 +++-- |
| 2 files changed, 6 insertions(+), 3 deletions(-) |
| |
| --- a/kernel/events/core.c |
| +++ b/kernel/events/core.c |
| @@ -7921,8 +7921,10 @@ int perf_event_init_task(struct task_str |
| |
| for_each_task_context_nr(ctxn) { |
| ret = perf_event_init_context(child, ctxn); |
| - if (ret) |
| + if (ret) { |
| + perf_event_free_task(child); |
| return ret; |
| + } |
| } |
| |
| return 0; |
| --- a/kernel/fork.c |
| +++ b/kernel/fork.c |
| @@ -1326,7 +1326,7 @@ static struct task_struct *copy_process( |
| goto bad_fork_cleanup_policy; |
| retval = audit_alloc(p); |
| if (retval) |
| - goto bad_fork_cleanup_policy; |
| + goto bad_fork_cleanup_perf; |
| /* copy all the process information */ |
| retval = copy_semundo(clone_flags, p); |
| if (retval) |
| @@ -1525,8 +1525,9 @@ bad_fork_cleanup_semundo: |
| exit_sem(p); |
| bad_fork_cleanup_audit: |
| audit_free(p); |
| -bad_fork_cleanup_policy: |
| +bad_fork_cleanup_perf: |
| perf_event_free_task(p); |
| +bad_fork_cleanup_policy: |
| #ifdef CONFIG_NUMA |
| mpol_put(p->mempolicy); |
| bad_fork_cleanup_threadgroup_lock: |