aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2013-04-26 05:10:55 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-04-26 11:02:03 -0400
commitf464246d85d5a5c0fdbf5838b8c58ef59bd82fcc (patch)
treee0788b40695dcaa64ef2baa2367639dcdb3f4fc5
parent37b7f3c76595e23257f61bd80b223de8658617ee (diff)
efivars: only check for duplicates on the registered list
variable_is_present() accesses '__efivars' directly, but when called via gsmi_init() Michel reports observing the following crash, BUG: unable to handle kernel NULL pointer dereference at (null) IP: variable_is_present+0x55/0x170 Call Trace: register_efivars+0x106/0x370 gsmi_init+0x2ad/0x3da do_one_initcall+0x3f/0x170 The reason for the crash is that '__efivars' hasn't been initialised nor has it been registered with register_efivars() by the time the google EFI SMI driver runs. The gsmi code uses its own struct efivars, and therefore, a different variable list. Fix the above crash by passing the registered struct efivars to variable_is_present(), so that we traverse the correct list. Reported-by: Michel Lespinasse <walken@google.com> Tested-by: Michel Lespinasse <walken@google.com> Cc: Mike Waychison <mikew@google.com> Cc: Matthew Garrett <matthew.garrett@nebula.com> Cc: Seiji Aguchi <seiji.aguchi@hds.com> Signed-off-by: Matt Fleming <matt.fleming@intel.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/firmware/efivars.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 182ce9471175..f4baa11d3644 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -1628,10 +1628,11 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
1628 return count; 1628 return count;
1629} 1629}
1630 1630
1631static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor) 1631static bool variable_is_present(struct efivars *efivars,
1632 efi_char16_t *variable_name,
1633 efi_guid_t *vendor)
1632{ 1634{
1633 struct efivar_entry *entry, *n; 1635 struct efivar_entry *entry, *n;
1634 struct efivars *efivars = &__efivars;
1635 unsigned long strsize1, strsize2; 1636 unsigned long strsize1, strsize2;
1636 bool found = false; 1637 bool found = false;
1637 1638
@@ -1703,8 +1704,8 @@ static void efivar_update_sysfs_entries(struct work_struct *work)
1703 if (status != EFI_SUCCESS) { 1704 if (status != EFI_SUCCESS) {
1704 break; 1705 break;
1705 } else { 1706 } else {
1706 if (!variable_is_present(variable_name, 1707 if (!variable_is_present(efivars,
1707 &vendor)) { 1708 variable_name, &vendor)) {
1708 found = true; 1709 found = true;
1709 break; 1710 break;
1710 } 1711 }
@@ -2008,7 +2009,8 @@ int register_efivars(struct efivars *efivars,
2008 * we'll ever see a different variable name, 2009 * we'll ever see a different variable name,
2009 * and may end up looping here forever. 2010 * and may end up looping here forever.
2010 */ 2011 */
2011 if (variable_is_present(variable_name, &vendor_guid)) { 2012 if (variable_is_present(efivars, variable_name,
2013 &vendor_guid)) {
2012 dup_variable_bug(variable_name, &vendor_guid, 2014 dup_variable_bug(variable_name, &vendor_guid,
2013 variable_name_size); 2015 variable_name_size);
2014 status = EFI_NOT_FOUND; 2016 status = EFI_NOT_FOUND;