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: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
Родитель
3881ee0b1e
Коммит
416581e486
|
@ -145,6 +145,7 @@ config EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER
|
|||
|
||||
config EFI_BOOTLOADER_CONTROL
|
||||
tristate "EFI Bootloader Control"
|
||||
select UCS2_STRING
|
||||
default n
|
||||
help
|
||||
This module installs a reboot hook, such that if reboot() is
|
||||
|
|
|
@ -10,69 +10,51 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/reboot.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
|
||||
|
||||
static int efibc_set_variable(efi_char16_t *name, efi_char16_t *value,
|
||||
unsigned long len)
|
||||
{
|
||||
size_t i;
|
||||
efi_status_t status;
|
||||
|
||||
for (i = 0; i < strlen(str); i++)
|
||||
str16[i] = str[i];
|
||||
status = efi.set_variable(name, &LINUX_EFI_LOADER_ENTRY_GUID,
|
||||
EFI_VARIABLE_NON_VOLATILE
|
||||
| EFI_VARIABLE_BOOTSERVICE_ACCESS
|
||||
| EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
len * sizeof(efi_char16_t), value);
|
||||
|
||||
str16[i] = '\0';
|
||||
}
|
||||
|
||||
static int efibc_set_variable(const char *name, const char *value)
|
||||
{
|
||||
int ret;
|
||||
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;
|
||||
if (status != EFI_SUCCESS) {
|
||||
pr_err("failed to set EFI variable: 0x%lx\n", status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
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,
|
||||
entry->var.VendorGuid,
|
||||
EFI_VARIABLE_NON_VOLATILE
|
||||
| EFI_VARIABLE_BOOTSERVICE_ACCESS
|
||||
| EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
false, size, entry->var.Data);
|
||||
|
||||
if (ret)
|
||||
pr_err("failed to set %s EFI variable: 0x%x\n",
|
||||
name, ret);
|
||||
|
||||
kfree(entry);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efibc_reboot_notifier_call(struct notifier_block *notifier,
|
||||
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;
|
||||
|
||||
if (event == SYS_RESTART)
|
||||
reason = "reboot";
|
||||
|
||||
ret = efibc_set_variable("LoaderEntryRebootReason", reason);
|
||||
ret = efibc_set_variable(L"LoaderEntryRebootReason", reason,
|
||||
ucs2_strlen(reason));
|
||||
if (ret || !data)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -84,7 +66,7 @@ static int __init efibc_init(void)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (!efivars_kobject() || !efivar_supports_writes())
|
||||
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_SET_VARIABLE))
|
||||
return -ENODEV;
|
||||
|
||||
ret = register_reboot_notifier(&efibc_reboot_notifier);
|
||||
|
|
Загрузка…
Ссылка в новой задаче