From mboxrd@z Thu Jan 1 00:00:00 1970 From: Andy Shevchenko Subject: [PATCHv2] idr: always do slow path when hint is uninitialized Date: Wed, 20 Feb 2013 19:23:35 +0200 Message-ID: <1361381015-446-1-git-send-email-andriy.shevchenko@linux.intel.com> Return-path: Received: from mga09.intel.com ([134.134.136.24]:62691 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753818Ab3BTRXx (ORCPT ); Wed, 20 Feb 2013 12:23:53 -0500 Sender: linux-next-owner@vger.kernel.org List-ID: To: Tejun Heo , linux-next@vger.kernel.org, "Kirill A . Shutemov" , Andrew Morton Cc: Andy Shevchenko In case of PMU-less systems we have got the following traceback. [ 7.720687] BUG: unable to handle kernel NULL pointer dereference at (null) [ 7.727743] IP: [] perf_init_event+0x5e/0x150 [ 7.732961] *pdpt = 0000000035257001 *pde = 0000000000000000 [ 7.738700] Oops: 0000 [#1] PREEMPT SMP Entering kdb (current=0xf6c58000, pid 1) on processor 1 Oops: (null) due to oops @ 0xc10ae57c dPid: 1, comm: init Not tainted 3.8.0-next-20130220-00036-gbceb0e3-dirty #57 dEIP: 0060:[] EFLAGS: 00010246 CPU: 1 EIP is at perf_init_event+0x5e/0x150 dEAX: 00000000 EBX: 00000000 ECX: c17efaa4 EDX: 00000005 dESI: f52e44b0 EDI: 00000005 EBP: f6c61df8 ESP: f6c61de4 d DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 dCR0: 8005003b CR2: 00000000 CR3: 35256000 CR4: 000007f0 dDR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 dDR6: ffff0ff0 DR7: 00000400 0Process init (pid: 1, ti=f6c60000 task=f6c58000 task.ti=f6c60000) 0Stack: 00000000 c104762b 00000001 f52e45f8 f52e4588 f6c61e24 c10ae8df f6c58405 00000006 00000007 f6c58000 f6c61e84 f52e44b0 00000000 c18aed5c 00000000 f6c61e4c c10aec35 f52e44b0 00000000 00000000 00000000 00000000 00000000 0Call Trace: 0 [] ? __mutex_init+0x3f/0x44 0 [] perf_event_alloc+0x271/0x39a 0 [] perf_event_create_kernel_counter+0x1a/0xb3 0 [] register_wide_hw_breakpoint+0x56/0xd9 0 [] kgdb_arch_late+0x7a/0x112 0 [] ? kgdb_set_hw_break+0x15e/0x15e 0 [] kgdb_register_io_module+0x9b/0x121 0 [] configure_kgdboc+0xf1/0x126 0 [] param_set_kgdboc_var+0x8a/0x8f 0 [] param_attr_store+0x2a/0x47 0 [] ? __kernel_param_lock+0x11/0x11 0 [] module_attr_store+0x17/0x26 0 [] sysfs_write_file+0xab/0xe6 0 [] ? sysfs_chmod_file+0x82/0x82 0 [] vfs_write+0x66/0xa7 0 [] sys_write+0x37/0x60 0 [] sysenter_do_call+0x12/0x32 0Code: ff ff 8b 7e 78 8b 1d 94 12 e5 c1 e8 5c 49 f9 ff 83 c4 0c 85 c0 74 0e 80 3d 28 05 84 c1 00 75 05 e8 99 9c ff ff 89 f8 89 fa 30 c0 <3b> 03 75 26 81 e2 ff 00 00 00 83 c2 08 8b 5c 93 04 e8 2b 49 f9 The guilty commit is cc5b5f6 "events: convert to idr_alloc()" together with f49318a "idr: implement lookup hint". In our case the idr_alloc is never called, but idr_find is. The hint field is never initialized and therefore should not be dereferenced. Signed-off-by: Andy Shevchenko Reported-by: Kirill A. Shutemov --- include/linux/idr.h | 2 +- lib/idr.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/idr.h b/include/linux/idr.h index aed2a0c..a6f38b5 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h @@ -113,7 +113,7 @@ static inline void *idr_find(struct idr *idr, int id) { struct idr_layer *hint = rcu_dereference_raw(idr->hint); - if ((id & ~IDR_MASK) == hint->prefix) + if (hint && (id & ~IDR_MASK) == hint->prefix) return rcu_dereference_raw(hint->ary[id & IDR_MASK]); return idr_find_slowpath(idr, id); diff --git a/lib/idr.c b/lib/idr.c index 5c772dc..1a30272 100644 --- a/lib/idr.c +++ b/lib/idr.c @@ -139,7 +139,7 @@ static void idr_layer_rcu_free(struct rcu_head *head) static inline void free_layer(struct idr *idr, struct idr_layer *p) { - if (idr->hint == p) + if (idr->hint && idr->hint == p) RCU_INIT_POINTER(idr->hint, NULL); call_rcu(&p->rcu_head, idr_layer_rcu_free); } -- 1.8.2.rc0.22.gb3600c3