]> www.infradead.org Git - linux-platform-drivers-x86.git/commitdiff
efi/efivars: Expose RT service availability via efivars abstraction
authorArd Biesheuvel <ardb@kernel.org>
Wed, 8 Jul 2020 10:01:57 +0000 (13:01 +0300)
committerArd Biesheuvel <ardb@kernel.org>
Thu, 9 Jul 2020 07:14:29 +0000 (10:14 +0300)
Commit

  bf67fad19e493b ("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: bf67fad19e493b ("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>
drivers/firmware/efi/efi-pstore.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/efivars.c
drivers/firmware/efi/vars.c
fs/efivarfs/super.c
include/linux/efi.h

index c2f1d4e6630b10351a1cc428671d04ccc46a6b02..feb7fe6f2da76d7244c13d6ea5251f896c91fb8a 100644 (file)
@@ -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)
index 5114cae4ec9735dad8c0d809176957ce2ba676b2..fdd1db025dbfda2c0a4e5f63b9d3e24fa95cfeb9 100644 (file)
@@ -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);
 }
 
@@ -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)
@@ -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);
index 26528a46d99e9e9f0db8c3f55dc3e4706bc774f4..dcea137142b3ceb3913024f6aafa363f4747dd3c 100644 (file)
@@ -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,
index 5f2a4d162795c2ddfbcf122b9ad82963f3185db5..973eef234b365e530576fe09cc407cbb6e0d1366 100644 (file)
@@ -1229,3 +1229,9 @@ out:
        return rv;
 }
 EXPORT_SYMBOL_GPL(efivars_unregister);
+
+int efivar_supports_writes(void)
+{
+       return __efivars && __efivars->ops->set_variable;
+}
+EXPORT_SYMBOL_GPL(efivar_supports_writes);
index 12c66f5d92dd2e5e1de7fc4d733bed11871adfa0..28bb5689333a59a69fa46bc6beba8e8d1f81acd2 100644 (file)
@@ -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;
@@ -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;
 
index bb35f3305e5506f1721cac2f88854c6f38f97b21..05c47f857383ebf215898cb39c956b7a29d9f86c 100644 (file)
@@ -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);