| From 8282f5d9c17fe15a9e658c06e3f343efae1a2a2f Mon Sep 17 00:00:00 2001 |
| From: Peter Jones <pjones@redhat.com> |
| Date: Mon, 8 Feb 2016 14:48:14 -0500 |
| Subject: efi: Make our variable validation list include the guid |
| |
| From: Peter Jones <pjones@redhat.com> |
| |
| commit 8282f5d9c17fe15a9e658c06e3f343efae1a2a2f upstream. |
| |
| All the variables in this list so far are defined to be in the global |
| namespace in the UEFI spec, so this just further ensures we're |
| validating the variables we think we are. |
| |
| Including the guid for entries will become more important in future |
| patches when we decide whether or not to allow deletion of variables |
| based on presence in this list. |
| |
| Signed-off-by: Peter Jones <pjones@redhat.com> |
| Tested-by: Lee, Chun-Yi <jlee@suse.com> |
| Acked-by: Matthew Garrett <mjg59@coreos.com> |
| Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/firmware/efi/efivars.c | 6 +++- |
| drivers/firmware/efi/vars.c | 52 ++++++++++++++++++++++++++--------------- |
| include/linux/efi.h | 3 +- |
| 3 files changed, 39 insertions(+), 22 deletions(-) |
| |
| --- a/drivers/firmware/efi/efivars.c |
| +++ b/drivers/firmware/efi/efivars.c |
| @@ -219,7 +219,8 @@ efivar_store_raw(struct efivar_entry *en |
| } |
| |
| if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || |
| - efivar_validate(new_var->VariableName, new_var->Data, new_var->DataSize) == false) { |
| + efivar_validate(new_var->VendorGuid, new_var->VariableName, |
| + new_var->Data, new_var->DataSize) == false) { |
| printk(KERN_ERR "efivars: Malformed variable content\n"); |
| return -EINVAL; |
| } |
| @@ -334,7 +335,8 @@ static ssize_t efivar_create(struct file |
| return -EACCES; |
| |
| if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || |
| - efivar_validate(new_var->VariableName, new_var->Data, new_var->DataSize) == false) { |
| + efivar_validate(new_var->VendorGuid, new_var->VariableName, |
| + new_var->Data, new_var->DataSize) == false) { |
| printk(KERN_ERR "efivars: Malformed variable content\n"); |
| return -EINVAL; |
| } |
| --- a/drivers/firmware/efi/vars.c |
| +++ b/drivers/firmware/efi/vars.c |
| @@ -165,31 +165,42 @@ validate_ascii_string(efi_char16_t *var_ |
| } |
| |
| struct variable_validate { |
| + efi_guid_t vendor; |
| char *name; |
| bool (*validate)(efi_char16_t *var_name, int match, u8 *data, |
| unsigned long len); |
| }; |
| |
| +/* |
| + * This is the list of variables we need to validate. |
| + * |
| + * If it has a validate() method that's not NULL, it'll go into the |
| + * validation routine. If not, it is assumed valid. |
| + * |
| + * Note that it's sorted by {vendor,name}, but globbed names must come after |
| + * any other name with the same prefix. |
| + */ |
| static const struct variable_validate variable_validate[] = { |
| - { "BootNext", validate_uint16 }, |
| - { "BootOrder", validate_boot_order }, |
| - { "DriverOrder", validate_boot_order }, |
| - { "Boot*", validate_load_option }, |
| - { "Driver*", validate_load_option }, |
| - { "ConIn", validate_device_path }, |
| - { "ConInDev", validate_device_path }, |
| - { "ConOut", validate_device_path }, |
| - { "ConOutDev", validate_device_path }, |
| - { "ErrOut", validate_device_path }, |
| - { "ErrOutDev", validate_device_path }, |
| - { "Timeout", validate_uint16 }, |
| - { "Lang", validate_ascii_string }, |
| - { "PlatformLang", validate_ascii_string }, |
| - { "", NULL }, |
| + { EFI_GLOBAL_VARIABLE_GUID, "BootNext", validate_uint16 }, |
| + { EFI_GLOBAL_VARIABLE_GUID, "BootOrder", validate_boot_order }, |
| + { EFI_GLOBAL_VARIABLE_GUID, "Boot*", validate_load_option }, |
| + { EFI_GLOBAL_VARIABLE_GUID, "DriverOrder", validate_boot_order }, |
| + { EFI_GLOBAL_VARIABLE_GUID, "Driver*", validate_load_option }, |
| + { EFI_GLOBAL_VARIABLE_GUID, "ConIn", validate_device_path }, |
| + { EFI_GLOBAL_VARIABLE_GUID, "ConInDev", validate_device_path }, |
| + { EFI_GLOBAL_VARIABLE_GUID, "ConOut", validate_device_path }, |
| + { EFI_GLOBAL_VARIABLE_GUID, "ConOutDev", validate_device_path }, |
| + { EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path }, |
| + { EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path }, |
| + { EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string }, |
| + { EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string }, |
| + { EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 }, |
| + { NULL_GUID, "", NULL }, |
| }; |
| |
| bool |
| -efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long data_size) |
| +efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, |
| + unsigned long data_size) |
| { |
| int i; |
| unsigned long utf8_size; |
| @@ -203,9 +214,12 @@ efivar_validate(efi_char16_t *var_name, |
| ucs2_as_utf8(utf8_name, var_name, utf8_size); |
| utf8_name[utf8_size] = '\0'; |
| |
| - for (i = 0; variable_validate[i].validate != NULL; i++) { |
| + for (i = 0; variable_validate[i].name[0] != '\0'; i++) { |
| const char *name = variable_validate[i].name; |
| - int match; |
| + int match = 0; |
| + |
| + if (efi_guidcmp(vendor, variable_validate[i].vendor)) |
| + continue; |
| |
| for (match = 0; ; match++) { |
| char c = name[match]; |
| @@ -807,7 +821,7 @@ int efivar_entry_set_get_size(struct efi |
| |
| *set = false; |
| |
| - if (efivar_validate(name, data, *size) == false) |
| + if (efivar_validate(*vendor, name, data, *size) == false) |
| return -EINVAL; |
| |
| /* |
| --- a/include/linux/efi.h |
| +++ b/include/linux/efi.h |
| @@ -834,7 +834,8 @@ int efivar_entry_iter(int (*func)(struct |
| struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, |
| struct list_head *head, bool remove); |
| |
| -bool efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len); |
| +bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, |
| + unsigned long data_size); |
| |
| extern struct work_struct efivar_work; |
| void efivar_run_worker(void); |