--- /dev/null
+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
+ */
--- /dev/null
+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);
+
+ /*
--- /dev/null
+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);
--- /dev/null
+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) &&
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