EDAC/ghes: Fix NULL pointer dereference in ghes_edac_register()

After

  b9cae27728 ("EDAC/ghes: Scan the system once on driver init")

and with CONFIG_DEBUG_TEST_DRIVER_REMOVE enabled, ghes_hw.dimms becomes
a NULL pointer after the second ->probe() (aka ghes_edac_register())
which the config option causes to be called.

This happens because the static variable which holds down whether
the system has been scanned already, doesn't get reset in
ghes_edac_unregister(). Then, on the second probe, ghes_scan_system()
doesn't get to enumerate the DIMMs, leading to ghes_hw.dimms remaining
NULL.

Clear the variable and rename it to something more descriptive so that a
second probe succeeds.

 [ bp: Rewrite commit message. ]

Fixes: b9cae27728 ("EDAC/ghes: Scan the system once on driver init")
Suggested-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Shiju Jose <shiju.jose@huawei.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/20200827140450.1620-1-shiju.jose@huawei.com
This commit is contained in:
Shiju Jose 2020-08-27 15:04:50 +01:00 committed by Borislav Petkov
parent d012a7190f
commit b972fdba86

View File

@ -55,6 +55,8 @@ static DEFINE_SPINLOCK(ghes_lock);
static bool __read_mostly force_load; static bool __read_mostly force_load;
module_param(force_load, bool, 0); module_param(force_load, bool, 0);
static bool system_scanned;
/* Memory Device - Type 17 of SMBIOS spec */ /* Memory Device - Type 17 of SMBIOS spec */
struct memdev_dmi_entry { struct memdev_dmi_entry {
u8 type; u8 type;
@ -225,14 +227,12 @@ static void enumerate_dimms(const struct dmi_header *dh, void *arg)
static void ghes_scan_system(void) static void ghes_scan_system(void)
{ {
static bool scanned; if (system_scanned)
if (scanned)
return; return;
dmi_walk(enumerate_dimms, &ghes_hw); dmi_walk(enumerate_dimms, &ghes_hw);
scanned = true; system_scanned = true;
} }
void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err) void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
@ -631,6 +631,8 @@ void ghes_edac_unregister(struct ghes *ghes)
mutex_lock(&ghes_reg_mutex); mutex_lock(&ghes_reg_mutex);
system_scanned = false;
if (!refcount_dec_and_test(&ghes_refcount)) if (!refcount_dec_and_test(&ghes_refcount))
goto unlock; goto unlock;