Skip to content

Commit

Permalink
efi/efivars: Expose RT service availability via efivars abstraction
Browse files Browse the repository at this point in the history
Commit

  bf67fad ("efi: Use more granular check for availability for variable services")

introduced a check into the efivarfs, efi-pstore and other drivers that
aborts loading of the module if not all three variable runtime services
(GetVariable, SetVariable and GetNextVariable) are supported. However, this
results in efivarfs being unavailable entirely if only SetVariable support
is missing, which is only needed if you want to make any modifications.
Also, efi-pstore and the sysfs EFI variable interface could be backed by
another implementation of the 'efivars' abstraction, in which case it is
completely irrelevant which services are supported by the EFI firmware.

So make the generic 'efivars' abstraction dependent on the availibility of
the GetVariable and GetNextVariable EFI runtime services, and add a helper
'efivar_supports_writes()' to find out whether the currently active efivars
abstraction supports writes (and wire it up to the availability of
SetVariable for the generic one).

Then, use the efivar_supports_writes() helper to decide whether to permit
efivarfs to be mounted read-write, and whether to enable efi-pstore or the
sysfs EFI variable interface altogether.

Fixes: bf67fad ("efi: Use more granular check for availability for variable services")
Reported-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Acked-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Tested-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
  • Loading branch information
Ard Biesheuvel committed Jul 9, 2020
1 parent 3230d95 commit f88814c
Show file tree
Hide file tree
Showing 6 changed files with 20 additions and 15 deletions.
5 changes: 1 addition & 4 deletions drivers/firmware/efi/efi-pstore.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,10 +356,7 @@ static struct pstore_info efi_pstore_info = {

static __init int efivars_pstore_init(void)
{
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
return 0;

if (!efivars_kobject())
if (!efivars_kobject() || !efivar_supports_writes())
return 0;

if (efivars_pstore_disable)
Expand Down
12 changes: 8 additions & 4 deletions drivers/firmware/efi/efi.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,13 @@ static struct efivar_operations generic_ops;
static int generic_ops_register(void)
{
generic_ops.get_variable = efi.get_variable;
generic_ops.set_variable = efi.set_variable;
generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking;
generic_ops.get_next_variable = efi.get_next_variable;
generic_ops.query_variable_store = efi_query_variable_store;

if (efi_rt_services_supported(EFI_RT_SUPPORTED_SET_VARIABLE)) {
generic_ops.set_variable = efi.set_variable;
generic_ops.set_variable_nonblocking = efi.set_variable_nonblocking;
}
return efivars_register(&generic_efivars, &generic_ops, efi_kobj);
}

Expand Down Expand Up @@ -382,7 +384,8 @@ static int __init efisubsys_init(void)
return -ENOMEM;
}

if (efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES)) {
if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE |
EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME)) {
efivar_ssdt_load();
error = generic_ops_register();
if (error)
Expand Down Expand Up @@ -416,7 +419,8 @@ static int __init efisubsys_init(void)
err_remove_group:
sysfs_remove_group(efi_kobj, &efi_subsys_attr_group);
err_unregister:
if (efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
if (efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE |
EFI_RT_SUPPORTED_GET_NEXT_VARIABLE_NAME))
generic_ops_unregister();
err_put:
kobject_put(efi_kobj);
Expand Down
5 changes: 1 addition & 4 deletions drivers/firmware/efi/efivars.c
Original file line number Diff line number Diff line change
Expand Up @@ -680,11 +680,8 @@ int efivars_sysfs_init(void)
struct kobject *parent_kobj = efivars_kobject();
int error = 0;

if (!efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
return -ENODEV;

/* No efivars has been registered yet */
if (!parent_kobj)
if (!parent_kobj || !efivar_supports_writes())
return 0;

printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION,
Expand Down
6 changes: 6 additions & 0 deletions drivers/firmware/efi/vars.c
Original file line number Diff line number Diff line change
Expand Up @@ -1229,3 +1229,9 @@ int efivars_unregister(struct efivars *efivars)
return rv;
}
EXPORT_SYMBOL_GPL(efivars_unregister);

int efivar_supports_writes(void)
{
return __efivars && __efivars->ops->set_variable;
}
EXPORT_SYMBOL_GPL(efivar_supports_writes);
6 changes: 3 additions & 3 deletions fs/efivarfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
sb->s_d_op = &efivarfs_d_ops;
sb->s_time_gran = 1;

if (!efivar_supports_writes())
sb->s_flags |= SB_RDONLY;

inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0, true);
if (!inode)
return -ENOMEM;
Expand Down Expand Up @@ -252,9 +255,6 @@ static struct file_system_type efivarfs_type = {

static __init int efivarfs_init(void)
{
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_VARIABLE_SERVICES))
return -ENODEV;

if (!efivars_kobject())
return -ENODEV;

Expand Down
1 change: 1 addition & 0 deletions include/linux/efi.h
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,7 @@ int efivars_register(struct efivars *efivars,
int efivars_unregister(struct efivars *efivars);
struct kobject *efivars_kobject(void);

int efivar_supports_writes(void);
int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
void *data, bool duplicates, struct list_head *head);

Expand Down

0 comments on commit f88814c

Please sign in to comment.