From aab76f96c092ae8b4fe5b06458065ffa4b4f360c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 3 May 2012 13:36:32 -0700 Subject: [PATCH] 3.0-stable patches added patches: efi-add-new-variable-attributes.patch efi-validate-uefi-boot-variables.patch efivars-fix-warnings-when-config_pstore-n.patch efivars-string-functions.patch --- .../efi-add-new-variable-attributes.patch | 41 ++++ .../efi-validate-uefi-boot-variables.patch | 229 ++++++++++++++++++ ...rs-fix-warnings-when-config_pstore-n.patch | 42 ++++ queue-3.0/efivars-string-functions.patch | 94 +++++++ queue-3.0/series | 4 + 5 files changed, 410 insertions(+) create mode 100644 queue-3.0/efi-add-new-variable-attributes.patch create mode 100644 queue-3.0/efi-validate-uefi-boot-variables.patch create mode 100644 queue-3.0/efivars-fix-warnings-when-config_pstore-n.patch create mode 100644 queue-3.0/efivars-string-functions.patch diff --git a/queue-3.0/efi-add-new-variable-attributes.patch b/queue-3.0/efi-add-new-variable-attributes.patch new file mode 100644 index 00000000000..06318608f07 --- /dev/null +++ b/queue-3.0/efi-add-new-variable-attributes.patch @@ -0,0 +1,41 @@ +From 41b3254c93acc56adc3c4477fef7c9512d47659e Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Mon, 30 Apr 2012 16:11:29 -0400 +Subject: efi: Add new variable attributes + +From: Matthew Garrett + +commit 41b3254c93acc56adc3c4477fef7c9512d47659e upstream. + +More recent versions of the UEFI spec have added new attributes for +variables. Add them. + +Signed-off-by: Matthew Garrett +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/efi.h | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/include/linux/efi.h ++++ b/include/linux/efi.h +@@ -347,7 +347,18 @@ extern int __init efi_setup_pcdp_console + #define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 + #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 + #define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 ++#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x0000000000000008 ++#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x0000000000000010 ++#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x0000000000000020 ++#define EFI_VARIABLE_APPEND_WRITE 0x0000000000000040 + ++#define EFI_VARIABLE_MASK (EFI_VARIABLE_NON_VOLATILE | \ ++ EFI_VARIABLE_BOOTSERVICE_ACCESS | \ ++ EFI_VARIABLE_RUNTIME_ACCESS | \ ++ EFI_VARIABLE_HARDWARE_ERROR_RECORD | \ ++ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | \ ++ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \ ++ EFI_VARIABLE_APPEND_WRITE) + /* + * EFI Device Path information + */ diff --git a/queue-3.0/efi-validate-uefi-boot-variables.patch b/queue-3.0/efi-validate-uefi-boot-variables.patch new file mode 100644 index 00000000000..c3d8bb6581c --- /dev/null +++ b/queue-3.0/efi-validate-uefi-boot-variables.patch @@ -0,0 +1,229 @@ +From fec6c20b570bcf541e581fc97f2e0cbdb9725b98 Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Mon, 30 Apr 2012 16:11:30 -0400 +Subject: efi: Validate UEFI boot variables + +From: Matthew Garrett + +commit fec6c20b570bcf541e581fc97f2e0cbdb9725b98 upstream. + +A common flaw in UEFI systems is a refusal to POST triggered by a malformed +boot variable. Once in this state, machines may only be restored by +reflashing their firmware with an external hardware device. While this is +obviously a firmware bug, the serious nature of the outcome suggests that +operating systems should filter their variable writes in order to prevent +a malicious user from rendering the machine unusable. + +Signed-off-by: Matthew Garrett +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/firmware/efivars.c | 182 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 182 insertions(+) + +--- a/drivers/firmware/efivars.c ++++ b/drivers/firmware/efivars.c +@@ -166,6 +166,176 @@ utf16_strsize(efi_char16_t *data, unsign + return utf16_strnlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t); + } + ++static bool ++validate_device_path(struct efi_variable *var, int match, u8 *buffer, int len) ++{ ++ struct efi_generic_dev_path *node; ++ int offset = 0; ++ ++ node = (struct efi_generic_dev_path *)buffer; ++ ++ while (offset < len) { ++ offset += node->length; ++ ++ if (offset > len) ++ return false; ++ ++ if ((node->type == EFI_DEV_END_PATH || ++ node->type == EFI_DEV_END_PATH2) && ++ node->sub_type == EFI_DEV_END_ENTIRE) ++ return true; ++ ++ node = (struct efi_generic_dev_path *)(buffer + offset); ++ } ++ ++ /* ++ * If we're here then either node->length pointed past the end ++ * of the buffer or we reached the end of the buffer without ++ * finding a device path end node. ++ */ ++ return false; ++} ++ ++static bool ++validate_boot_order(struct efi_variable *var, int match, u8 *buffer, int len) ++{ ++ /* An array of 16-bit integers */ ++ if ((len % 2) != 0) ++ return false; ++ ++ return true; ++} ++ ++static bool ++validate_load_option(struct efi_variable *var, int match, u8 *buffer, int len) ++{ ++ u16 filepathlength; ++ int i, desclength = 0; ++ ++ /* Either "Boot" or "Driver" followed by four digits of hex */ ++ for (i = match; i < match+4; i++) { ++ if (hex_to_bin(var->VariableName[i] & 0xff) < 0) ++ return true; ++ } ++ ++ /* A valid entry must be at least 6 bytes */ ++ if (len < 6) ++ return false; ++ ++ filepathlength = buffer[4] | buffer[5] << 8; ++ ++ /* ++ * There's no stored length for the description, so it has to be ++ * found by hand ++ */ ++ desclength = utf16_strsize((efi_char16_t *)(buffer + 6), len) + 2; ++ ++ /* Each boot entry must have a descriptor */ ++ if (!desclength) ++ return false; ++ ++ /* ++ * If the sum of the length of the description, the claimed filepath ++ * length and the original header are greater than the length of the ++ * variable, it's malformed ++ */ ++ if ((desclength + filepathlength + 6) > len) ++ return false; ++ ++ /* ++ * And, finally, check the filepath ++ */ ++ return validate_device_path(var, match, buffer + desclength + 6, ++ filepathlength); ++} ++ ++static bool ++validate_uint16(struct efi_variable *var, int match, u8 *buffer, int len) ++{ ++ /* A single 16-bit integer */ ++ if (len != 2) ++ return false; ++ ++ return true; ++} ++ ++static bool ++validate_ascii_string(struct efi_variable *var, int match, u8 *buffer, int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) { ++ if (buffer[i] > 127) ++ return false; ++ ++ if (buffer[i] == 0) ++ return true; ++ } ++ ++ return false; ++} ++ ++struct variable_validate { ++ char *name; ++ bool (*validate)(struct efi_variable *var, int match, u8 *data, ++ int len); ++}; ++ ++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 }, ++}; ++ ++static bool ++validate_var(struct efi_variable *var, u8 *data, int len) ++{ ++ int i; ++ u16 *unicode_name = var->VariableName; ++ ++ for (i = 0; variable_validate[i].validate != NULL; i++) { ++ const char *name = variable_validate[i].name; ++ int match; ++ ++ for (match = 0; ; match++) { ++ char c = name[match]; ++ u16 u = unicode_name[match]; ++ ++ /* All special variables are plain ascii */ ++ if (u > 127) ++ return true; ++ ++ /* Wildcard in the matching name means we've matched */ ++ if (c == '*') ++ return variable_validate[i].validate(var, ++ match, data, len); ++ ++ /* Case sensitive match */ ++ if (c != u) ++ break; ++ ++ /* Reached the end of the string while matching */ ++ if (!c) ++ return variable_validate[i].validate(var, ++ match, data, len); ++ } ++ } ++ ++ return true; ++} ++ + static efi_status_t + get_var_data(struct efivars *efivars, struct efi_variable *var) + { +@@ -289,6 +459,12 @@ efivar_store_raw(struct efivar_entry *en + return -EINVAL; + } + ++ if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || ++ validate_var(new_var, new_var->Data, new_var->DataSize) == false) { ++ printk(KERN_ERR "efivars: Malformed variable content\n"); ++ return -EINVAL; ++ } ++ + spin_lock(&efivars->lock); + status = efivars->ops->set_variable(new_var->VariableName, + &new_var->VendorGuid, +@@ -414,6 +590,12 @@ static ssize_t efivar_create(struct file + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + ++ if ((new_var->Attributes & ~EFI_VARIABLE_MASK) != 0 || ++ validate_var(new_var, new_var->Data, new_var->DataSize) == false) { ++ printk(KERN_ERR "efivars: Malformed variable content\n"); ++ return -EINVAL; ++ } ++ + spin_lock(&efivars->lock); + + /* diff --git a/queue-3.0/efivars-fix-warnings-when-config_pstore-n.patch b/queue-3.0/efivars-fix-warnings-when-config_pstore-n.patch new file mode 100644 index 00000000000..1d58d49576b --- /dev/null +++ b/queue-3.0/efivars-fix-warnings-when-config_pstore-n.patch @@ -0,0 +1,42 @@ +From b728a5c806fb36f9adebf2a862bbd015e074afca Mon Sep 17 00:00:00 2001 +From: Tony Luck +Date: Tue, 2 Aug 2011 15:08:30 -0700 +Subject: efivars: fix warnings when CONFIG_PSTORE=n +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tony Luck + +commit b728a5c806fb36f9adebf2a862bbd015e074afca upstream. + +drivers/firmware/efivars.c:161: warning: ‘utf16_strlen’ defined but not used +utf16_strlen() is only used inside CONFIG_PSTORE - make this "static inline" +to shut the compiler up [thanks to hpa for the suggestion]. + +drivers/firmware/efivars.c:602: warning: initialization from incompatible pointer type +Between v1 and v2 of this patch series we decided to make the "part" number +unsigned - but missed fixing the stub version of efi_pstore_write() + +Acked-by: Matthew Garrett +Acked-by: Mike Waychison +Signed-off-by: Tony Luck +[took the static part of the patch, not the pstore part, for 3.0-stable, +to fix the compiler warning we had - gregkh] +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/firmware/efivars.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/firmware/efivars.c ++++ b/drivers/firmware/efivars.c +@@ -150,7 +150,7 @@ utf16_strnlen(efi_char16_t *s, size_t ma + return length; + } + +-static unsigned long ++static inline unsigned long + utf16_strlen(efi_char16_t *s) + { + return utf16_strnlen(s, ~0UL); diff --git a/queue-3.0/efivars-string-functions.patch b/queue-3.0/efivars-string-functions.patch new file mode 100644 index 00000000000..55ac21e6466 --- /dev/null +++ b/queue-3.0/efivars-string-functions.patch @@ -0,0 +1,94 @@ +From a2940908391f3cee72e38769b30e829b22742b5b Mon Sep 17 00:00:00 2001 +From: Mike Waychison +Date: Thu, 21 Jul 2011 16:57:57 -0400 +Subject: efivars: String functions + +From: Mike Waychison + +commit a2940908391f3cee72e38769b30e829b22742b5b upstream. + +Fix the string functions in the efivars driver to be called utf16_* +instead of utf8_* as the encoding is utf16, not utf8. + +As well, rename utf16_strlen to utf16_strnlen as it takes a maxlength +argument and the name should be consistent with the standard C function +names. utf16_strlen is still provided for convenience in a subsequent +patch. + +Signed-off-by: Mike Waychison +Signed-off-by: Tony Luck +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/firmware/efivars.c | 26 ++++++++++++++++---------- + 1 file changed, 16 insertions(+), 10 deletions(-) + +--- a/drivers/firmware/efivars.c ++++ b/drivers/firmware/efivars.c +@@ -141,23 +141,29 @@ efivar_create_sysfs_entry(struct efivars + + /* Return the number of unicode characters in data */ + static unsigned long +-utf8_strlen(efi_char16_t *data, unsigned long maxlength) ++utf16_strnlen(efi_char16_t *s, size_t maxlength) + { + unsigned long length = 0; + +- while (*data++ != 0 && length < maxlength) ++ while (*s++ != 0 && length < maxlength) + length++; + return length; + } + ++static unsigned long ++utf16_strlen(efi_char16_t *s) ++{ ++ return utf16_strnlen(s, ~0UL); ++} ++ + /* + * Return the number of bytes is the length of this string + * Note: this is NOT the same as the number of unicode characters + */ + static inline unsigned long +-utf8_strsize(efi_char16_t *data, unsigned long maxlength) ++utf16_strsize(efi_char16_t *data, unsigned long maxlength) + { +- return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t); ++ return utf16_strnlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t); + } + + static efi_status_t +@@ -414,8 +420,8 @@ static ssize_t efivar_create(struct file + * Does this variable already exist? + */ + list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { +- strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024); +- strsize2 = utf8_strsize(new_var->VariableName, 1024); ++ strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024); ++ strsize2 = utf16_strsize(new_var->VariableName, 1024); + if (strsize1 == strsize2 && + !memcmp(&(search_efivar->var.VariableName), + new_var->VariableName, strsize1) && +@@ -447,8 +453,8 @@ static ssize_t efivar_create(struct file + + /* Create the entry in sysfs. Locking is not required here */ + status = efivar_create_sysfs_entry(efivars, +- utf8_strsize(new_var->VariableName, +- 1024), ++ utf16_strsize(new_var->VariableName, ++ 1024), + new_var->VariableName, + &new_var->VendorGuid); + if (status) { +@@ -477,8 +483,8 @@ static ssize_t efivar_delete(struct file + * Does this variable already exist? + */ + list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { +- strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024); +- strsize2 = utf8_strsize(del_var->VariableName, 1024); ++ strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024); ++ strsize2 = utf16_strsize(del_var->VariableName, 1024); + if (strsize1 == strsize2 && + !memcmp(&(search_efivar->var.VariableName), + del_var->VariableName, strsize1) && diff --git a/queue-3.0/series b/queue-3.0/series index f74721f7717..210e4b2bf8a 100644 --- a/queue-3.0/series +++ b/queue-3.0/series @@ -30,3 +30,7 @@ autofs-make-the-autofsv5-packet-file-descriptor-use-a-packetized-pipe.patch arm-7403-1-tls-remove-covert-channel-via-tpidrurw.patch scsi-libsas-fix-sas_find_bcast_phy-in-the-presence-of-vacant-phys.patch scsi-libsas-fix-false-positive-device-attached-conditions.patch +efi-add-new-variable-attributes.patch +efivars-string-functions.patch +efivars-fix-warnings-when-config_pstore-n.patch +efi-validate-uefi-boot-variables.patch -- 2.47.3