Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

efivars: Handle duplicate names from get_next_variable()

Some firmware exhibits a bug where the same VariableName and
VendorGuid values are returned on multiple invocations of
GetNextVariableName(). See,

https://bugzilla.kernel.org/show_bug.cgi?id=47631

As a consequence of such a bug, Andre reports hitting the following
WARN_ON() in the sysfs code after updating the BIOS on his, "Gigabyte
Technology Co., Ltd. To be filled by O.E.M./Z77X-UD3H, BIOS F19e
11/21/2012)" machine,

[ 0.581554] EFI Variables Facility v0.08 2004-May-17
[ 0.584914] ------------[ cut here ]------------
[ 0.585639] WARNING: at /home/andre/linux/fs/sysfs/dir.c:536 sysfs_add_one+0xd4/0x100()
[ 0.586381] Hardware name: To be filled by O.E.M.
[ 0.587123] sysfs: cannot create duplicate filename '/firmware/efi/vars/SbAslBufferPtrVar-01f33c25-764d-43ea-aeea-6b5a41f3f3e8'
[ 0.588694] Modules linked in:
[ 0.589484] Pid: 1, comm: swapper/0 Not tainted 3.8.0+ #7
[ 0.590280] Call Trace:
[ 0.591066] [<ffffffff81208954>] ? sysfs_add_one+0xd4/0x100
[ 0.591861] [<ffffffff810587bf>] warn_slowpath_common+0x7f/0xc0
[ 0.592650] [<ffffffff810588bc>] warn_slowpath_fmt+0x4c/0x50
[ 0.593429] [<ffffffff8134dd85>] ? strlcat+0x65/0x80
[ 0.594203] [<ffffffff81208954>] sysfs_add_one+0xd4/0x100
[ 0.594979] [<ffffffff81208b78>] create_dir+0x78/0xd0
[ 0.595753] [<ffffffff81208ec6>] sysfs_create_dir+0x86/0xe0
[ 0.596532] [<ffffffff81347e4c>] kobject_add_internal+0x9c/0x220
[ 0.597310] [<ffffffff81348307>] kobject_init_and_add+0x67/0x90
[ 0.598083] [<ffffffff81584a71>] ? efivar_create_sysfs_entry+0x61/0x1c0
[ 0.598859] [<ffffffff81584b2b>] efivar_create_sysfs_entry+0x11b/0x1c0
[ 0.599631] [<ffffffff8158517e>] register_efivars+0xde/0x420
[ 0.600395] [<ffffffff81d430a7>] ? edd_init+0x2f5/0x2f5
[ 0.601150] [<ffffffff81d4315f>] efivars_init+0xb8/0x104
[ 0.601903] [<ffffffff8100215a>] do_one_initcall+0x12a/0x180
[ 0.602659] [<ffffffff81d05d80>] kernel_init_freeable+0x13e/0x1c6
[ 0.603418] [<ffffffff81d05586>] ? loglevel+0x31/0x31
[ 0.604183] [<ffffffff816a6530>] ? rest_init+0x80/0x80
[ 0.604936] [<ffffffff816a653e>] kernel_init+0xe/0xf0
[ 0.605681] [<ffffffff816ce7ec>] ret_from_fork+0x7c/0xb0
[ 0.606414] [<ffffffff816a6530>] ? rest_init+0x80/0x80
[ 0.607143] ---[ end trace 1609741ab737eb29 ]---

There's not much we can do to work around and keep traversing the
variable list once we hit this firmware bug. Our only solution is to
terminate the loop because, as Lingzhu reports, some machines get
stuck when they encounter duplicate names,

> I had an IBM System x3100 M4 and x3850 X5 on which kernel would
> get stuck in infinite loop creating duplicate sysfs files because,
> for some reason, there are several duplicate boot entries in nvram
> getting GetNextVariableName into a circle of iteration (with
> period > 2).

Also disable the workqueue, as efivar_update_sysfs_entries() uses
GetNextVariableName() to figure out which variables have been created
since the last iteration. That algorithm isn't going to work if
GetNextVariableName() returns duplicates. Note that we don't disable
EFI variable creation completely on the affected machines, it's just
that any pstore dump-* files won't appear in sysfs until the next
boot.

Reported-by: Andre Heider <a.heider@gmail.com>
Reported-by: Lingzhu Xiang <lxiang@redhat.com>
Tested-by: Lingzhu Xiang <lxiang@redhat.com>
Cc: Seiji Aguchi <seiji.aguchi@hds.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>

+47 -1
+47 -1
drivers/firmware/efivars.c
··· 170 170 171 171 static void efivar_update_sysfs_entries(struct work_struct *); 172 172 static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries); 173 + static bool efivar_wq_enabled = true; 173 174 174 175 /* Return the number of unicode characters in data */ 175 176 static unsigned long ··· 1445 1444 1446 1445 spin_unlock_irqrestore(&efivars->lock, flags); 1447 1446 1448 - if (reason == KMSG_DUMP_OOPS) 1447 + if (reason == KMSG_DUMP_OOPS && efivar_wq_enabled) 1449 1448 schedule_work(&efivar_work); 1450 1449 1451 1450 *id = part; ··· 1976 1975 } 1977 1976 EXPORT_SYMBOL_GPL(unregister_efivars); 1978 1977 1978 + /* 1979 + * Print a warning when duplicate EFI variables are encountered and 1980 + * disable the sysfs workqueue since the firmware is buggy. 1981 + */ 1982 + static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid, 1983 + unsigned long len16) 1984 + { 1985 + size_t i, len8 = len16 / sizeof(efi_char16_t); 1986 + char *s8; 1987 + 1988 + /* 1989 + * Disable the workqueue since the algorithm it uses for 1990 + * detecting new variables won't work with this buggy 1991 + * implementation of GetNextVariableName(). 1992 + */ 1993 + efivar_wq_enabled = false; 1994 + 1995 + s8 = kzalloc(len8, GFP_KERNEL); 1996 + if (!s8) 1997 + return; 1998 + 1999 + for (i = 0; i < len8; i++) 2000 + s8[i] = s16[i]; 2001 + 2002 + printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n", 2003 + s8, vendor_guid); 2004 + kfree(s8); 2005 + } 2006 + 1979 2007 int register_efivars(struct efivars *efivars, 1980 2008 const struct efivar_operations *ops, 1981 2009 struct kobject *parent_kobj) ··· 2055 2025 case EFI_SUCCESS: 2056 2026 variable_name_size = var_name_strnsize(variable_name, 2057 2027 variable_name_size); 2028 + 2029 + /* 2030 + * Some firmware implementations return the 2031 + * same variable name on multiple calls to 2032 + * get_next_variable(). Terminate the loop 2033 + * immediately as there is no guarantee that 2034 + * we'll ever see a different variable name, 2035 + * and may end up looping here forever. 2036 + */ 2037 + if (variable_is_present(variable_name, &vendor_guid)) { 2038 + dup_variable_bug(variable_name, &vendor_guid, 2039 + variable_name_size); 2040 + status = EFI_NOT_FOUND; 2041 + break; 2042 + } 2043 + 2058 2044 efivar_create_sysfs_entry(efivars, 2059 2045 variable_name_size, 2060 2046 variable_name,