History

efi: efivars: Fix variable writes without query_variable_store()

Commit bbc6d2c6ef22 ("efi: vars: Switch to new wrapper layer") refactored the efivars layer so that the 'business logic' related to which UEFI variables affect the boot flow in which way could be moved out of it, and into the efivarfs driver. This inadvertently broke setting variables on firmware implementations that lack the QueryVariableInfo() boot service, because we no longer tolerate a EFI_UNSUPPORTED result from check_var_size() when calling efivar_entry_set_get_size(), which now ends up calling check_var_size() a second time inadvertently. If QueryVariableInfo() is missing, we support writes of up to 64k - let's move that logic into check_var_size(), and drop the redundant call.

Ard Biesheuvel committed 4 years ago

Commit 8a254d91 parent 4b017e53 files · +5 −24Browse files

Unified · Split

3 files
  1. drivers/firmware/efi/vars.c +5 −5
  2. fs/efivarfs/vars.c +0 −16
  3. include/linux/efi.h +0 −3
drivers/firmware/efi/vars.c+5−5
@@ -7,6 +7,7 @@ · 6 unmodified lines
77 */
88
99 #include <linux/types.h>
10+#include <linux/sizes.h>
1011 #include <linux/errno.h>
1112 #include <linux/init.h>
1213 #include <linux/module.h>
@@ -20,19 +21,19 @@ static struct efivars *__efivars; · 7 unmodified lines
2021
2122 static DEFINE_SEMAPHORE(efivars_lock);
2223
23−efi_status_t check_var_size(u32 attributes, unsigned long size)
24+static efi_status_t check_var_size(u32 attributes, unsigned long size)
2425 {
2526 const struct efivar_operations *fops;
2627
2728 fops = __efivars->ops;
2829
2930 if (!fops->query_variable_store)
30− return EFI_UNSUPPORTED;
31+ return (size <= SZ_64K) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
3132
3233 return fops->query_variable_store(attributes, size, false);
3334 }
34−EXPORT_SYMBOL_NS_GPL(check_var_size, EFIVAR);
3535
36+static
3637 efi_status_t check_var_size_nonblocking(u32 attributes, unsigned long size)
3738 {
3839 const struct efivar_operations *fops;
@@ -40,11 +41,10 @@ efi_status_t check_var_size_nonblocking(u32 attributes, unsigned long size) · 1 unmodified line
4041 fops = __efivars->ops;
4142
4243 if (!fops->query_variable_store)
43− return EFI_UNSUPPORTED;
44+ return (size <= SZ_64K) ? EFI_SUCCESS : EFI_OUT_OF_RESOURCES;
4445
4546 return fops->query_variable_store(attributes, size, true);
4647 }
47−EXPORT_SYMBOL_NS_GPL(check_var_size_nonblocking, EFIVAR);
4848
4949 /**
5050 * efivars_kobject - get the kobject for the registered efivars
fs/efivarfs/vars.c+0−16
@@ -651,22 +651,6 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, · 650 unmodified lines
651651 if (err)
652652 return err;
653653
654− /*
655− * Ensure that the available space hasn't shrunk below the safe level
656− */
657− status = check_var_size(attributes, *size + ucs2_strsize(name, 1024));
658− if (status != EFI_SUCCESS) {
659− if (status != EFI_UNSUPPORTED) {
660− err = efi_status_to_err(status);
661− goto out;
662− }
663−
664− if (*size > 65536) {
665− err = -ENOSPC;
666− goto out;
667− }
668− }
669−
670654 status = efivar_set_variable_locked(name, vendor, attributes, *size,
671655 data, false);
672656 if (status != EFI_SUCCESS) {
include/linux/efi.h+0−3
@@ -1085,9 +1085,6 @@ efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor, · 1084 unmodified lines
10851085 efi_status_t efivar_set_variable(efi_char16_t *name, efi_guid_t *vendor,
10861086 u32 attr, unsigned long data_size, void *data);
10871087
1088−efi_status_t check_var_size(u32 attributes, unsigned long size);
1089−efi_status_t check_var_size_nonblocking(u32 attributes, unsigned long size);
1090−
10911088 #if IS_ENABLED(CONFIG_EFI_CAPSULE_LOADER)
10921089 extern bool efi_capsule_pending(int *reset_type);
10931090