diff options
author | Jeremy Compostella <[email protected]> | 2016-05-06 22:39:28 +0100 |
---|---|---|
committer | Ingo Molnar <[email protected]> | 2016-05-07 07:06:13 +0200 |
commit | 2e121d711a51f91e792595a05cf9ef6963cb8464 (patch) | |
tree | 510005d33d6a005fc980a78134a116e55c11c23c | |
parent | 62075e581802ea1842d5d3c490a7e46330bdb9e1 (diff) |
efibc: Fix excessive stack footprint warning
GCC complains about a newly added file for the EFI Bootloader Control:
drivers/firmware/efi/efibc.c: In function 'efibc_set_variable':
drivers/firmware/efi/efibc.c:53:1: error: the frame size of 2272 bytes is larger than 1024 bytes [-Werror=frame-larger-than=]
The problem is the declaration of a local variable of type struct
efivar_entry, which is by itself larger than the warning limit of 1024
bytes.
Use dynamic memory allocation instead of stack memory for the entry
object.
This patch also fixes a potential buffer overflow.
Reported-by: Ingo Molnar <[email protected]>
Reported-by: Arnd Bergmann <[email protected]>
Signed-off-by: Jeremy Compostella <[email protected]>
[ Updated changelog to include GCC error ]
Signed-off-by: Matt Fleming <[email protected]>
Cc: Andy Lutomirski <[email protected]>
Cc: Ard Biesheuvel <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Brian Gerst <[email protected]>
Cc: Denys Vlasenko <[email protected]>
Cc: H. Peter Anvin <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
-rw-r--r-- | drivers/firmware/efi/efibc.c | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/drivers/firmware/efi/efibc.c b/drivers/firmware/efi/efibc.c index 2e0c7ccd9d9e..8dd0c7085e59 100644 --- a/drivers/firmware/efi/efibc.c +++ b/drivers/firmware/efi/efibc.c @@ -17,6 +17,7 @@ #include <linux/efi.h> #include <linux/module.h> #include <linux/reboot.h> +#include <linux/slab.h> static void efibc_str_to_str16(const char *str, efi_char16_t *str16) { @@ -28,41 +29,52 @@ static void efibc_str_to_str16(const char *str, efi_char16_t *str16) str16[i] = '\0'; } -static void efibc_set_variable(const char *name, const char *value) +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; + struct efivar_entry *entry; size_t size = (strlen(value) + 1) * sizeof(efi_char16_t); - if (size > sizeof(entry.var.Data)) + if (size > sizeof(entry->var.Data)) { pr_err("value is too large"); + return -EINVAL; + } - 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)); + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) { + pr_err("failed to allocate efivar entry"); + return -ENOMEM; + } - ret = efivar_entry_set(&entry, + 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(entry, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, - size, entry.var.Data, NULL); + size, entry->var.Data, NULL); if (ret) pr_err("failed to set %s EFI variable: 0x%x\n", name, ret); + + kfree(entry); + return ret; } static int efibc_reboot_notifier_call(struct notifier_block *notifier, unsigned long event, void *data) { const char *reason = "shutdown"; + int ret; if (event == SYS_RESTART) reason = "reboot"; - efibc_set_variable("LoaderEntryRebootReason", reason); - - if (!data) + ret = efibc_set_variable("LoaderEntryRebootReason", reason); + if (ret || !data) return NOTIFY_DONE; efibc_set_variable("LoaderEntryOneShot", (char *)data); |