Commit 416581e4 authored by Ard Biesheuvel's avatar Ard Biesheuvel

efi: efibc: avoid efivar API for setting variables

Avoid abusing the efivar API by passing locally instantiated
efivar_entry structs into efivar_set_entry_safe(), rather than using the
API as intended. Instead, just call efi.set_variable() directly.
Signed-off-by: default avatarArd Biesheuvel <ardb@kernel.org>
parent 3881ee0b
...@@ -145,6 +145,7 @@ config EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER ...@@ -145,6 +145,7 @@ config EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER
config EFI_BOOTLOADER_CONTROL config EFI_BOOTLOADER_CONTROL
tristate "EFI Bootloader Control" tristate "EFI Bootloader Control"
select UCS2_STRING
default n default n
help help
This module installs a reboot hook, such that if reboot() is This module installs a reboot hook, such that if reboot() is
......
...@@ -10,69 +10,51 @@ ...@@ -10,69 +10,51 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ucs2_string.h>
static void efibc_str_to_str16(const char *str, efi_char16_t *str16) #define MAX_DATA_LEN 512
{
size_t i;
for (i = 0; i < strlen(str); i++)
str16[i] = str[i];
str16[i] = '\0';
}
static int efibc_set_variable(const char *name, const char *value) static int efibc_set_variable(efi_char16_t *name, efi_char16_t *value,
unsigned long len)
{ {
int ret; efi_status_t status;
efi_guid_t guid = LINUX_EFI_LOADER_ENTRY_GUID;
struct efivar_entry *entry;
size_t size = (strlen(value) + 1) * sizeof(efi_char16_t);
if (size > sizeof(entry->var.Data)) {
pr_err("value is too large (%zu bytes) for '%s' EFI variable\n", size, name);
return -EINVAL;
}
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
pr_err("failed to allocate efivar entry for '%s' EFI variable\n", name);
return -ENOMEM;
}
efibc_str_to_str16(name, entry->var.VariableName);
efibc_str_to_str16(value, (efi_char16_t *)entry->var.Data);
memcpy(&entry->var.VendorGuid, &guid, sizeof(guid));
ret = efivar_entry_set_safe(entry->var.VariableName, status = efi.set_variable(name, &LINUX_EFI_LOADER_ENTRY_GUID,
entry->var.VendorGuid,
EFI_VARIABLE_NON_VOLATILE EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS, | EFI_VARIABLE_RUNTIME_ACCESS,
false, size, entry->var.Data); len * sizeof(efi_char16_t), value);
if (ret)
pr_err("failed to set %s EFI variable: 0x%x\n",
name, ret);
kfree(entry); if (status != EFI_SUCCESS) {
return ret; pr_err("failed to set EFI variable: 0x%lx\n", status);
return -EIO;
}
return 0;
} }
static int efibc_reboot_notifier_call(struct notifier_block *notifier, static int efibc_reboot_notifier_call(struct notifier_block *notifier,
unsigned long event, void *data) unsigned long event, void *data)
{ {
const char *reason = "shutdown"; efi_char16_t *reason = event == SYS_RESTART ? L"reboot"
: L"shutdown";
const u8 *str = data;
efi_char16_t *wdata;
unsigned long l;
int ret; int ret;
if (event == SYS_RESTART) ret = efibc_set_variable(L"LoaderEntryRebootReason", reason,
reason = "reboot"; ucs2_strlen(reason));
ret = efibc_set_variable("LoaderEntryRebootReason", reason);
if (ret || !data) if (ret || !data)
return NOTIFY_DONE; return NOTIFY_DONE;
efibc_set_variable("LoaderEntryOneShot", (char *)data); wdata = kmalloc(MAX_DATA_LEN * sizeof(efi_char16_t), GFP_KERNEL);
for (l = 0; l < MAX_DATA_LEN - 1 && str[l] != '\0'; l++)
wdata[l] = str[l];
wdata[l] = L'\0';
efibc_set_variable(L"LoaderEntryOneShot", wdata, l);
kfree(wdata);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -84,7 +66,7 @@ static int __init efibc_init(void) ...@@ -84,7 +66,7 @@ static int __init efibc_init(void)
{ {
int ret; int ret;
if (!efivars_kobject() || !efivar_supports_writes()) if (!efi_rt_services_supported(EFI_RT_SUPPORTED_SET_VARIABLE))
return -ENODEV; return -ENODEV;
ret = register_reboot_notifier(&efibc_reboot_notifier); ret = register_reboot_notifier(&efibc_reboot_notifier);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment