Skip to content

Commit 8a254d9

Browse files
committed
efi: efivars: Fix variable writes without query_variable_store()
Commit bbc6d2c ("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. Cc: <stable@vger.kernel.org> # v6.0 Fixes: bbc6d2c ("efi: vars: Switch to new wrapper layer") Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
1 parent 4b017e5 commit 8a254d9

File tree

3 files changed

+5
-24
lines changed

3 files changed

+5
-24
lines changed

drivers/firmware/efi/vars.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
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,31 +21,30 @@ static struct efivars *__efivars;
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;
3940

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

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -651,22 +651,6 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,9 +1085,6 @@ efi_status_t efivar_set_variable_locked(efi_char16_t *name, efi_guid_t *vendor,
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

0 commit comments

Comments
 (0)