From 20afc60f892d285fde179ead4b24e6a7938c2f1b Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Tue, 30 Aug 2011 12:32:36 +0400 Subject: [PATCH] x86, perf: Check that current->mm is alive before getting user callchain An event may occur when an mm is already released. I added an event in dequeue_entity() and caught a panic with the following backtrace: [ 434.421110] BUG: unable to handle kernel NULL pointer dereference at 0000000000000050 [ 434.421258] IP: [] __get_user_pages_fast+0x9c/0x120 ... [ 434.421258] Call Trace: [ 434.421258] [] copy_from_user_nmi+0x51/0xf0 [ 434.421258] [] ? sched_clock_local+0x25/0x90 [ 434.421258] [] perf_callchain_user+0x128/0x170 [ 434.421258] [] ? __perf_event_header__init_id+0xed/0x100 [ 434.421258] [] perf_prepare_sample+0x200/0x280 [ 434.421258] [] __perf_event_overflow+0x1b8/0x290 [ 434.421258] [] ? tg_shares_up+0x0/0x670 [ 434.421258] [] ? walk_tg_tree+0x6a/0xb0 [ 434.421258] [] perf_swevent_overflow+0xc4/0xf0 [ 434.421258] [] do_perf_sw_event+0x1e0/0x250 [ 434.421258] [] perf_tp_event+0x44/0x70 [ 434.421258] [] ftrace_profile_sched_block+0xdf/0x110 [ 434.421258] [] dequeue_entity+0x2ad/0x2d0 [ 434.421258] [] dequeue_task_fair+0x1c/0x60 [ 434.421258] [] dequeue_task+0x9a/0xb0 [ 434.421258] [] deactivate_task+0x42/0xe0 [ 434.421258] [] thread_return+0x191/0x808 [ 434.421258] [] ? switch_task_namespaces+0x24/0x60 [ 434.421258] [] do_exit+0x464/0x910 [ 434.421258] [] do_group_exit+0x58/0xd0 [ 434.421258] [] sys_exit_group+0x17/0x20 [ 434.421258] [] system_call_fastpath+0x16/0x1b Signed-off-by: Andrey Vagin Signed-off-by: Peter Zijlstra Cc: stable@kernel.org Link: http://lkml.kernel.org/r/1314693156-24131-1-git-send-email-avagin@openvz.org Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 4ee3abf20ed6..cfa62ec090ec 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1900,6 +1900,9 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) perf_callchain_store(entry, regs->ip); + if (!current->mm) + return; + if (perf_callchain_user32(regs, entry)) return;