This is a note to let you know that I've just added the patch titled
x86, efivars: firmware bug workarounds should be in platform code
to the 3.4-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
x86-efivars-firmware-bug-workarounds-should-be-in-platform-code.patch
and it can be found in the queue-3.4 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree,
please let <[email protected]> know about it.
>From a6e4d5a03e9e3587e88aba687d8f225f4f04c792 Mon Sep 17 00:00:00 2001
From: Matt Fleming <[email protected]>
Date: Mon, 25 Mar 2013 09:14:30 +0000
Subject: x86, efivars: firmware bug workarounds should be in platform code
From: Matt Fleming <[email protected]>
commit a6e4d5a03e9e3587e88aba687d8f225f4f04c792 upstream.
Let's not burden ia64 with checks in the common efivars code that we're not
writing too much data to the variable store. That kind of thing is an x86
firmware bug, plain and simple.
efi_query_variable_store() provides platforms with a wrapper in which they can
perform checks and workarounds for EFI variable storage bugs.
Cc: H. Peter Anvin <[email protected]>
Cc: Matthew Garrett <[email protected]>
Signed-off-by: Matt Fleming <[email protected]>
[xr: Backported to 3.4: adjust context]
Signed-off-by: Rui Xiang <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
arch/x86/platform/efi/efi.c | 25 +++++++++++++++++++++++++
drivers/firmware/efivars.c | 18 +++---------------
include/linux/efi.h | 9 ++++++++-
3 files changed, 36 insertions(+), 16 deletions(-)
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -960,3 +960,28 @@ u64 efi_mem_attributes(unsigned long phy
}
return 0;
}
+
+/*
+ * Some firmware has serious problems when using more than 50% of the EFI
+ * variable store, i.e. it triggers bugs that can brick machines. Ensure that
+ * we never use more than this safe limit.
+ *
+ * Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
+ * store.
+ */
+efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
+{
+ efi_status_t status;
+ u64 storage_size, remaining_size, max_size;
+
+ status = efi.query_variable_info(attributes, &storage_size,
+ &remaining_size, &max_size);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ if (!storage_size || size > remaining_size || size > max_size ||
+ (remaining_size - size) < (storage_size / 2))
+ return EFI_OUT_OF_RESOURCES;
+
+ return EFI_SUCCESS;
+}
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -425,24 +425,12 @@ static efi_status_t
check_var_size_locked(struct efivars *efivars, u32 attributes,
unsigned long size)
{
- u64 storage_size, remaining_size, max_size;
- efi_status_t status;
const struct efivar_operations *fops = efivars->ops;
- if (!efivars->ops->query_variable_info)
+ if (!efivars->ops->query_variable_store)
return EFI_UNSUPPORTED;
- status = fops->query_variable_info(attributes, &storage_size,
- &remaining_size, &max_size);
-
- if (status != EFI_SUCCESS)
- return status;
-
- if (!storage_size || size > remaining_size || size > max_size ||
- (remaining_size - size) < (storage_size / 2))
- return EFI_OUT_OF_RESOURCES;
-
- return status;
+ return fops->query_variable_store(attributes, size);
}
static ssize_t
@@ -1445,7 +1433,7 @@ efivars_init(void)
ops.get_variable = efi.get_variable;
ops.set_variable = efi.set_variable;
ops.get_next_variable = efi.get_next_variable;
- ops.query_variable_info = efi.query_variable_info;
+ ops.query_variable_store = efi_query_variable_store;
error = register_efivars(&__efivars, &ops, efi_kobj);
if (error)
goto err_put;
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -262,6 +262,7 @@ typedef efi_status_t efi_query_capsule_c
unsigned long count,
u64 *max_size,
int *reset_type);
+typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long
size);
/*
* EFI Configuration Table and GUID definitions
@@ -503,8 +504,14 @@ extern void efi_gettimeofday (struct tim
extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode,
if possible */
#ifdef CONFIG_X86
extern void efi_free_boot_services(void);
+extern efi_status_t efi_query_variable_store(u32 attributes, unsigned long
size);
#else
static inline void efi_free_boot_services(void) {}
+
+static inline efi_status_t efi_query_variable_store(u32 attributes, unsigned
long size)
+{
+ return EFI_SUCCESS;
+}
#endif
extern u64 efi_get_iobase (void);
extern u32 efi_mem_type (unsigned long phys_addr);
@@ -657,7 +664,7 @@ struct efivar_operations {
efi_get_variable_t *get_variable;
efi_get_next_variable_t *get_next_variable;
efi_set_variable_t *set_variable;
- efi_query_variable_info_t *query_variable_info;
+ efi_query_variable_store_t *query_variable_store;
};
struct efivars {
Patches currently in stable-queue which might be from [email protected] are
queue-3.4/efi-be-more-paranoid-about-available-space-when-creating-variables.patch
queue-3.4/x86-efi-fix-dummy-variable-buffer-allocation.patch
queue-3.4/x86-efivars-firmware-bug-workarounds-should-be-in-platform-code.patch
queue-3.4/efivars-fix-check-for-config_efi_vars_pstore_default_disable.patch
queue-3.4/efi_pstore-introducing-workqueue-updating-sysfs.patch
queue-3.4/efivars-disable-external-interrupt-while-holding-efivars-lock.patch
queue-3.4/x86-efi-implement-efi_no_storage_paranoia-parameter.patch
queue-3.4/efivars-add-module-parameter-to-disable-use-as-a-pstore-backend.patch
queue-3.4/efivars-allow-disabling-use-as-a-pstore-backend.patch
queue-3.4/x86-efi-check-max_size-only-if-it-is-non-zero.patch
queue-3.4/modify-uefi-anti-bricking-code.patch
queue-3.4/efi-export-efi_query_variable_store-for-efivars.ko.patch
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html