From: Matt Fleming
Git-commit: ec50bd32f1672d38ddce10fb1841cbfda89cfe9a
Patch-mainline: v3.9-rc4
References: bnc#808680
Target: openSUSE 12.3
Some buggy firmware implementations return a string length from
GetNextVariableName() that is actually larger than the string in
'variable_name', as Michael Schroeder writes,
On HP z220 system (firmware version 1.54), some EFI variables are
incorrectly named :
ls -d /sys/firmware/efi/vars/*8be4d* | grep -v -- -8be returns
/sys/firmware/efi/vars/dbxDefault-pport8be4df61-93ca-11d2-aa0d-00e098032b8c
/sys/firmware/efi/vars/KEKDefault-pport8be4df61-93ca-11d2-aa0d-00e098032b8c
/sys/firmware/efi/vars/SecureBoot-pport8be4df61-93ca-11d2-aa0d-00e098032b8c
/sys/firmware/efi/vars/SetupMode-Information8be4df61-93ca-11d2-aa0d-00e098032b8c
Since 'variable_name' is a string, we can validate its size by
searching for the terminating NULL character.
Reported-by: Frederic Crozat
Cc: Matthew Garrett
Cc: Josh Boyer
Cc: Michael Schroeder
Cc: Lee, Chun-Yi
Cc: Lingzhu Xiang
Signed-off-by: Matt Fleming
Acked-by: Lee, Chun-Yi
---
drivers/firmware/efivars.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -1911,6 +1911,33 @@ void unregister_efivars(struct efivars *
}
EXPORT_SYMBOL_GPL(unregister_efivars);
+/*
+ * Sanity check size of a variable name.
+ */
+static unsigned long sanity_check_size(efi_char16_t *variable_name,
+ unsigned long variable_name_size)
+{
+ unsigned long len;
+ efi_char16_t c;
+
+ /*
+ * The variable name is, by definition, a NULL-terminated
+ * string, so make absolutely sure that variable_name_size is
+ * the value we expect it to be. If not, return the real size.
+ */
+ for (len = 2; len <= variable_name_size; len += sizeof(c)) {
+ c = variable_name[(len / sizeof(c)) - 1];
+ if (!c)
+ break;
+ }
+
+
+ if (len != variable_name_size)
+ printk(KERN_WARNING "efivars: bogus variable_name_size: %lu %lu\n", len, variable_name_size);
+
+ return min(len, variable_name_size);
+}
+
int register_efivars(struct efivars *efivars,
const struct efivar_operations *ops,
struct kobject *parent_kobj)
@@ -1957,8 +1984,11 @@ int register_efivars(struct efivars *efi
status = ops->get_next_variable(&variable_name_size,
variable_name,
&vendor_guid);
+
switch (status) {
case EFI_SUCCESS:
+ variable_name_size = sanity_check_size(variable_name,
+ variable_name_size);
efivar_create_sysfs_entry(efivars,
variable_name_size,
variable_name,
--
To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org
To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org