]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.0-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 3 May 2012 20:36:32 +0000 (13:36 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 3 May 2012 20:36:32 +0000 (13:36 -0700)
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

queue-3.0/efi-add-new-variable-attributes.patch [new file with mode: 0644]
queue-3.0/efi-validate-uefi-boot-variables.patch [new file with mode: 0644]
queue-3.0/efivars-fix-warnings-when-config_pstore-n.patch [new file with mode: 0644]
queue-3.0/efivars-string-functions.patch [new file with mode: 0644]
queue-3.0/series

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 (file)
index 0000000..0631860
--- /dev/null
@@ -0,0 +1,41 @@
+From 41b3254c93acc56adc3c4477fef7c9512d47659e Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg@redhat.com>
+Date: Mon, 30 Apr 2012 16:11:29 -0400
+Subject: efi: Add new variable attributes
+
+From: Matthew Garrett <mjg@redhat.com>
+
+commit 41b3254c93acc56adc3c4477fef7c9512d47659e upstream.
+
+More recent versions of the UEFI spec have added new attributes for
+variables. Add them.
+
+Signed-off-by: Matthew Garrett <mjg@redhat.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..c3d8bb6
--- /dev/null
@@ -0,0 +1,229 @@
+From fec6c20b570bcf541e581fc97f2e0cbdb9725b98 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg@redhat.com>
+Date: Mon, 30 Apr 2012 16:11:30 -0400
+Subject: efi: Validate UEFI boot variables
+
+From: Matthew Garrett <mjg@redhat.com>
+
+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 <mjg@redhat.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..1d58d49
--- /dev/null
@@ -0,0 +1,42 @@
+From b728a5c806fb36f9adebf2a862bbd015e074afca Mon Sep 17 00:00:00 2001
+From: Tony Luck <tony.luck@intel.com>
+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 <tony.luck@intel.com>
+
+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 <mjg@redhat.com>
+Acked-by: Mike Waychison <mikew@google.com>
+Signed-off-by: Tony Luck <tony.luck@intel.com>
+[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 <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..55ac21e
--- /dev/null
@@ -0,0 +1,94 @@
+From a2940908391f3cee72e38769b30e829b22742b5b Mon Sep 17 00:00:00 2001
+From: Mike Waychison <mikew@google.com>
+Date: Thu, 21 Jul 2011 16:57:57 -0400
+Subject: efivars: String functions
+
+From: Mike Waychison <mikew@google.com>
+
+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 <mikew@google.com>
+Signed-off-by: Tony Luck <tony.luck@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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) &&
index f74721f77173d3060fdca3450140d1cc4246d69a..210e4b2bf8a53ab2e00a3363f03086d06ce58ad7 100644 (file)
@@ -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