lkml.org 
[lkml]   [2012]   [Sep]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH] edac_mc: edac_mc_free() cannot assume mem_ctl_info is registered in sysfs.
Fix potential NULL pointer dereference in edac_unregister_sysfs() on
system boot introduced in 3.6-rc1. This patch is dependent on
Fengguang's "edac_mc: fix messy kfree calls in the error path".

Since commit 7a623c039 ("edac: rewrite the sysfs code to use struct
device") edac_mc_alloc() no longer initializes embedded kobjects in
struct mem_ctl_info. Therefore edac_mc_free() can no longer simply
decrement a kobject reference count to free the allocated memory
unless the memory controller driver module had also called
edac_mc_add_mc().

Now edac_mc_free() will check if the newly embedded struct device
has been registered with sysfs before using either the standard
device release functions or freeing the data structures itself with
logic pulled out of the error path of edac_mc_alloc().

The BUG this patch resolves for me:

BUG: unable to handle kernel NULL pointer dereference at (null)
IP: [<c045e195>] __wake_up_common+0x1a/0x6a
*pde = 7f0c6067
Oops: 0000 [#1] SMP
Modules linked in: parport_pc parport floppy e7xxx_edac(+) ide_cd_mod edac_core intel_rng cdrom microcode(+) dm_snapshot dm_zero dm_mirror dm_region_hash d
Pid: 933, comm: modprobe Tainted: G W 3.6.0-rc2-00111-gc1999ee #12 Dell Computer Corporation PowerEdge 2600 /0F0364
EIP: 0060:[<c045e195>] EFLAGS: 00010093 CPU: 3
EIP is at __wake_up_common+0x1a/0x6a
EAX: f47b0984 EBX: fffffff4 ECX: 00000000 EDX: 00000003
ESI: f47b0984 EDI: 00000282 EBP: f3dc7d38 ESP: f3dc7d1c
DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
CR0: 8005003b CR2: 00000000 CR3: 347d4000 CR4: 000007d0
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: ffff0ff0 DR7: 00000400
Process modprobe (pid: 933, ti=f3dc6000 task=f3db9520 task.ti=f3dc6000)
Stack:
00000000 00000000 00000003 c046701a f47b0980 f47b0984 00000282 f3dc7d54
c046703f 00000000 00000000 f47b08b0 f47b08b0 00000000 f3dc7d74 c06961ce
f3dc7d74 f3dc7d80 c05e2837 c094c4cc f47b08b0 f47b08b0 f3dc7d88 c068d56d
Call Trace:
[<c046701a>] ? complete_all+0x1a/0x50
[<c046703f>] complete_all+0x3f/0x50
[<c06961ce>] device_pm_remove+0x23/0xa2
[<c05e2837>] ? kobject_put+0x5b/0x5d
[<c068d56d>] device_del+0x34/0x142
[<f8547884>] edac_unregister_sysfs+0x3b/0x5c [edac_core]
[<f8545041>] edac_mc_free+0x29/0x2f [edac_core]
[<f860163f>] e7xxx_probe1+0x268/0x311 [e7xxx_edac]
[<c0603d00>] ? __pci_enable_device_flags+0x8f/0xd3
[<f8601b0b>] e7xxx_init_one+0x56/0x61 [e7xxx_edac]
[<c0604f85>] local_pci_probe+0x13/0x15
...
Cc: Mauro Carvalho Chehab <mchehab@redhat.com>
Cc: Shaohui Xie <Shaohui.Xie@freescale.com>
Signed-off-by: Shaun Ruffell <sruffell@digium.com>
---
Hi Linus, I did not bother to resend the third patch [1] since it's
not really *necessary* to boot my system. Fengguang's and this is
sufficient.

[1] http://marc.info/?l=linux-kernel&m=134764597921761&w=2

drivers/edac/edac_mc.c | 59 +++++++++++++++++++++++++++++++++-----------------
1 file changed, 39 insertions(+), 20 deletions(-)
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 9037ffa..d5dc9da 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -199,6 +199,36 @@ void *edac_align_ptr(void **p, unsigned size, int n_elems)
return (void *)(((unsigned long)ptr) + align - r);
}

+static void _edac_mc_free(struct mem_ctl_info *mci)
+{
+ int i, chn, row;
+ struct csrow_info *csr;
+ const unsigned int tot_dimms = mci->tot_dimms;
+ const unsigned int tot_channels = mci->num_cschannel;
+ const unsigned int tot_csrows = mci->nr_csrows;
+
+ if (mci->dimms) {
+ for (i = 0; i < tot_dimms; i++)
+ kfree(mci->dimms[i]);
+ kfree(mci->dimms);
+ }
+ if (mci->csrows) {
+ for (row = 0; row < tot_csrows; row++) {
+ csr = mci->csrows[row];
+ if (csr) {
+ if (csr->channels) {
+ for (chn = 0; chn < tot_channels; chn++)
+ kfree(csr->channels[chn]);
+ kfree(csr->channels);
+ }
+ kfree(csr);
+ }
+ }
+ kfree(mci->csrows);
+ }
+ kfree(mci);
+}
+
/**
* edac_mc_alloc: Allocate and partially fill a struct mem_ctl_info structure
* @mc_num: Memory controller number
@@ -413,26 +443,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
return mci;

error:
- if (mci->dimms) {
- for (i = 0; i < tot_dimms; i++)
- kfree(mci->dimms[i]);
- kfree(mci->dimms);
- }
- if (mci->csrows) {
- for (row = 0; row < tot_csrows; row++) {
- csr = mci->csrows[row];
- if (csr) {
- if (csr->channels) {
- for (chn = 0; chn < tot_channels; chn++)
- kfree(csr->channels[chn]);
- kfree(csr->channels);
- }
- kfree(csr);
- }
- }
- kfree(mci->csrows);
- }
- kfree(mci);
+ _edac_mc_free(mci);

return NULL;
}
@@ -447,6 +458,14 @@ void edac_mc_free(struct mem_ctl_info *mci)
{
edac_dbg(1, "\n");

+ /* If we're not yet registered with sysfs free only what was allocated
+ * in edac_mc_alloc().
+ */
+ if (!device_is_registered(&mci->dev)) {
+ _edac_mc_free(mci);
+ return;
+ }
+
/* the mci instance is freed here, when the sysfs object is dropped */
edac_unregister_sysfs(mci);
}
--
1.7.11.6

\
 
 \ /
  Last update: 2012-09-23 04:21    [W:0.054 / U:0.132 seconds]
©2003-2014 Jasper Spaans. Advertise on this site