]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Jun 2014 00:31:49 +0000 (17:31 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Jun 2014 00:31:49 +0000 (17:31 -0700)
added patches:
efi-export-efi_query_variable_store-for-efivars.ko.patch
efi_pstore-introducing-workqueue-updating-sysfs.patch
efivars-add-module-parameter-to-disable-use-as-a-pstore-backend.patch
efivars-fix-check-for-config_efi_vars_pstore_default_disable.patch
modify-uefi-anti-bricking-code.patch
x86-efi-check-max_size-only-if-it-is-non-zero.patch
x86-efi-fix-dummy-variable-buffer-allocation.patch
x86-efi-implement-efi_no_storage_paranoia-parameter.patch
x86-efivars-firmware-bug-workarounds-should-be-in-platform-code.patch

queue-3.4/efi-export-efi_query_variable_store-for-efivars.ko.patch [new file with mode: 0644]
queue-3.4/efi_pstore-introducing-workqueue-updating-sysfs.patch [new file with mode: 0644]
queue-3.4/efivars-add-module-parameter-to-disable-use-as-a-pstore-backend.patch [new file with mode: 0644]
queue-3.4/efivars-fix-check-for-config_efi_vars_pstore_default_disable.patch [new file with mode: 0644]
queue-3.4/modify-uefi-anti-bricking-code.patch [new file with mode: 0644]
queue-3.4/series
queue-3.4/x86-efi-check-max_size-only-if-it-is-non-zero.patch [new file with mode: 0644]
queue-3.4/x86-efi-fix-dummy-variable-buffer-allocation.patch [new file with mode: 0644]
queue-3.4/x86-efi-implement-efi_no_storage_paranoia-parameter.patch [new file with mode: 0644]
queue-3.4/x86-efivars-firmware-bug-workarounds-should-be-in-platform-code.patch [new file with mode: 0644]

diff --git a/queue-3.4/efi-export-efi_query_variable_store-for-efivars.ko.patch b/queue-3.4/efi-export-efi_query_variable_store-for-efivars.ko.patch
new file mode 100644 (file)
index 0000000..f827a94
--- /dev/null
@@ -0,0 +1,29 @@
+From c5ba30a73ebcca1b4068363ca08410fa3729ebeb Mon Sep 17 00:00:00 2001
+From: Sergey Vlasov <vsu@altlinux.ru>
+Date: Tue, 16 Apr 2013 18:31:09 +0400
+Subject: efi: Export efi_query_variable_store() for efivars.ko
+
+From: Sergey Vlasov <vsu@altlinux.ru>
+
+commit 3668011d4ad556224f7c012c1e870a6eaa0e59da upstream.
+
+Fixes build with CONFIG_EFI_VARS=m which was broken after the commit
+"x86, efivars: firmware bug workarounds should be in platform code".
+
+Signed-off-by: Sergey Vlasov <vsu@altlinux.ru>
+Signed-off-by: Matt Fleming <matt.fleming@intel.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Rui Xiang <rui.xiang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/platform/efi/efi.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/x86/platform/efi/efi.c
++++ b/arch/x86/platform/efi/efi.c
+@@ -990,3 +990,4 @@ efi_status_t efi_query_variable_store(u3
+       return EFI_SUCCESS;
+ }
++EXPORT_SYMBOL_GPL(efi_query_variable_store);
diff --git a/queue-3.4/efi_pstore-introducing-workqueue-updating-sysfs.patch b/queue-3.4/efi_pstore-introducing-workqueue-updating-sysfs.patch
new file mode 100644 (file)
index 0000000..0754cc3
--- /dev/null
@@ -0,0 +1,136 @@
+From a93bc0c6e07ed9bac44700280e65e2945d864fd4 Mon Sep 17 00:00:00 2001
+From: Seiji Aguchi <seiji.aguchi@hds.com>
+Date: Tue, 12 Feb 2013 13:04:41 -0800
+Subject: efi_pstore: Introducing workqueue updating sysfs
+
+From: Seiji Aguchi <seiji.aguchi@hds.com>
+
+commit a93bc0c6e07ed9bac44700280e65e2945d864fd4 upstream.
+
+[Problem]
+efi_pstore creates sysfs entries, which enable users to access to NVRAM,
+in a write callback. If a kernel panic happens in an interrupt context,
+it may fail because it could sleep due to dynamic memory allocations during
+creating sysfs entries.
+
+[Patch Description]
+This patch removes sysfs operations from a write callback by introducing
+a workqueue updating sysfs entries which is scheduled after the write
+callback is called.
+
+Also, the workqueue is kicked in a just oops case.
+A system will go down in other cases such as panic, clean shutdown and emergency
+restart. And we don't need to create sysfs entries because there is no chance for
+users to access to them.
+
+efi_pstore will be robust against a kernel panic in an interrupt context with this patch.
+
+Signed-off-by: Seiji Aguchi <seiji.aguchi@hds.com>
+Acked-by: Matt Fleming <matt.fleming@intel.com>
+Signed-off-by: Tony Luck <tony.luck@intel.com>
+[xr: Backported to 3.4:
+  - Adjust contest
+  - Remove repeated definition of helper function variable_is_present]
+Signed-off-by: Rui Xiang <rui.xiang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/firmware/efivars.c |   61 +++++++++++++++++++++++++++++++++++++++++----
+ include/linux/efi.h        |    3 +-
+ 2 files changed, 58 insertions(+), 6 deletions(-)
+
+--- a/drivers/firmware/efivars.c
++++ b/drivers/firmware/efivars.c
+@@ -154,6 +154,13 @@ efivar_create_sysfs_entry(struct efivars
+                         efi_char16_t *variable_name,
+                         efi_guid_t *vendor_guid);
++/*
++ * Prototype for workqueue functions updating sysfs entry
++ */
++
++static void efivar_update_sysfs_entries(struct work_struct *);
++static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries);
++
+ /* Return the number of unicode characters in data */
+ static unsigned long
+ utf16_strnlen(efi_char16_t *s, size_t maxlength)
+@@ -839,11 +846,8 @@ static int efi_pstore_write(enum pstore_
+       if (found)
+               efivar_unregister(found);
+-      if (size)
+-              ret = efivar_create_sysfs_entry(efivars,
+-                                        utf16_strsize(efi_name,
+-                                                      DUMP_NAME_LEN * 2),
+-                                        efi_name, &vendor);
++      if (reason == KMSG_DUMP_OOPS)
++              schedule_work(&efivar_work);
+       *id = part;
+       return ret;
+@@ -1044,6 +1048,53 @@ static bool variable_is_present(efi_char
+       return found;
+ }
++static void efivar_update_sysfs_entries(struct work_struct *work)
++{
++      struct efivars *efivars = &__efivars;
++      efi_guid_t vendor;
++      efi_char16_t *variable_name;
++      unsigned long variable_name_size = 1024;
++      efi_status_t status = EFI_NOT_FOUND;
++      bool found;
++
++      /* Add new sysfs entries */
++      while (1) {
++              variable_name = kzalloc(variable_name_size, GFP_KERNEL);
++              if (!variable_name) {
++                      pr_err("efivars: Memory allocation failed.\n");
++                      return;
++              }
++
++              spin_lock_irq(&efivars->lock);
++              found = false;
++              while (1) {
++                      variable_name_size = 1024;
++                      status = efivars->ops->get_next_variable(
++                                                      &variable_name_size,
++                                                      variable_name,
++                                                      &vendor);
++                      if (status != EFI_SUCCESS) {
++                              break;
++                      } else {
++                              if (!variable_is_present(variable_name,
++                                  &vendor)) {
++                                      found = true;
++                                      break;
++                              }
++                      }
++              }
++              spin_unlock_irq(&efivars->lock);
++
++              if (!found) {
++                      kfree(variable_name);
++                      break;
++              } else
++                      efivar_create_sysfs_entry(efivars,
++                                                variable_name_size,
++                                                variable_name, &vendor);
++      }
++}
++
+ /*
+  * Returns the size of variable_name, in bytes, including the
+  * terminating NULL character, or variable_name_size if no NULL
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -666,7 +666,8 @@ struct efivars {
+        * 1) ->list - adds, removals, reads, writes
+        * 2) ops.[gs]et_variable() calls.
+        * It must not be held when creating sysfs entries or calling kmalloc.
+-       * ops.get_next_variable() is only called from register_efivars(),
++       * ops.get_next_variable() is only called from register_efivars()
++       * or efivar_update_sysfs_entries(),
+        * which is protected by the BKL, so that path is safe.
+        */
+       spinlock_t lock;
diff --git a/queue-3.4/efivars-add-module-parameter-to-disable-use-as-a-pstore-backend.patch b/queue-3.4/efivars-add-module-parameter-to-disable-use-as-a-pstore-backend.patch
new file mode 100644 (file)
index 0000000..a4f8245
--- /dev/null
@@ -0,0 +1,79 @@
+From a1e16e8184d48763a7036a672e44998e4d3fe182 Mon Sep 17 00:00:00 2001
+From: Seth Forshee <seth.forshee@canonical.com>
+Date: Mon, 11 Mar 2013 16:17:50 -0500
+Subject: efivars: Add module parameter to disable use as a pstore backend
+
+From: Seth Forshee <seth.forshee@canonical.com>
+
+commit ec0971ba5372a4dfa753f232449d23a8fd98490e upstream.
+
+We know that with some firmware implementations writing too much data to
+UEFI variables can lead to bricking machines. Recent changes attempt to
+address this issue, but for some it may still be prudent to avoid
+writing large amounts of data until the solution has been proven on a
+wide variety of hardware.
+
+Crash dumps or other data from pstore can potentially be a large data
+source. Add a pstore_module parameter to efivars to allow disabling its
+use as a backend for pstore. Also add a config option,
+CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE, to allow setting the default
+value of this paramter to true (i.e. disabled by default).
+
+Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
+Cc: Josh Boyer <jwboyer@redhat.com>
+Cc: Matthew Garrett <mjg59@srcf.ucam.org>
+Cc: Seiji Aguchi <seiji.aguchi@hds.com>
+Cc: Tony Luck <tony.luck@intel.com>
+Signed-off-by: Matt Fleming <matt.fleming@intel.com>
+[bwh: Backported to 3.2: adjust context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Rui Xiang <rui.xiang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/firmware/Kconfig   |    9 +++++++++
+ drivers/firmware/efivars.c |    8 +++++++-
+ 2 files changed, 16 insertions(+), 1 deletion(-)
+
+--- a/drivers/firmware/Kconfig
++++ b/drivers/firmware/Kconfig
+@@ -62,6 +62,15 @@ config EFI_VARS_PSTORE
+         will allow writing console messages, crash dumps, or anything
+         else supported by pstore to EFI variables.
++config EFI_VARS_PSTORE_DEFAULT_DISABLE
++      bool "Disable using efivars as a pstore backend by default"
++      depends on EFI_VARS_PSTORE
++      default n
++      help
++        Saying Y here will disable the use of efivars as a storage
++        backend for pstore by default. This setting can be overridden
++        using the efivars module's pstore_disable parameter.
++
+ config EFI_PCDP
+       bool "Console device selection via EFI PCDP or HCDP table"
+       depends on ACPI && EFI && IA64
+--- a/drivers/firmware/efivars.c
++++ b/drivers/firmware/efivars.c
+@@ -92,6 +92,11 @@ MODULE_VERSION(EFIVARS_VERSION);
+ #define DUMP_NAME_LEN 52
++static bool efivars_pstore_disable =
++      IS_ENABLED(EFI_VARS_PSTORE_DEFAULT_DISABLE);
++
++module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644);
++
+ /*
+  * The maximum size of VariableName + Data = 1024
+  * Therefore, it's reasonable to save that much
+@@ -1350,7 +1355,8 @@ int register_efivars(struct efivars *efi
+       if (error)
+               unregister_efivars(efivars);
+-      efivar_pstore_register(efivars);
++      if (!efivars_pstore_disable)
++              efivar_pstore_register(efivars);
+ out:
+       kfree(variable_name);
diff --git a/queue-3.4/efivars-fix-check-for-config_efi_vars_pstore_default_disable.patch b/queue-3.4/efivars-fix-check-for-config_efi_vars_pstore_default_disable.patch
new file mode 100644 (file)
index 0000000..4bdce59
--- /dev/null
@@ -0,0 +1,32 @@
+From f9c0efa2e87f6fb07738c097985eb04932ffca90 Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Fri, 22 Mar 2013 19:56:51 +0000
+Subject: efivars: Fix check for CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE
+
+From: Ben Hutchings <ben@decadent.org.uk>
+
+commit ca0ba26fbbd2d81c43085df49ce0abfe34535a90 upstream.
+
+The 'CONFIG_' prefix is not implicit in IS_ENABLED().
+
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Seth Forshee <seth.forshee@canonical.com>
+Signed-off-by: Matt Fleming <matt.fleming@intel.com>
+Cc: Rui Xiang <rui.xiang@huawei.com>
+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
+@@ -93,7 +93,7 @@ MODULE_VERSION(EFIVARS_VERSION);
+ #define DUMP_NAME_LEN 52
+ static bool efivars_pstore_disable =
+-      IS_ENABLED(EFI_VARS_PSTORE_DEFAULT_DISABLE);
++      IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE);
+ module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644);
diff --git a/queue-3.4/modify-uefi-anti-bricking-code.patch b/queue-3.4/modify-uefi-anti-bricking-code.patch
new file mode 100644 (file)
index 0000000..735a75f
--- /dev/null
@@ -0,0 +1,153 @@
+From 134c3faa909c12ae1b9c3a37a5e733b1f6c3dfab Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <matthew.garrett@nebula.com>
+Date: Sat, 1 Jun 2013 16:06:20 -0400
+Subject: Modify UEFI anti-bricking code
+
+From: Matthew Garrett <matthew.garrett@nebula.com>
+
+commit f8b8404337de4e2466e2e1139ea68b1f8295974f upstream.
+
+This patch reworks the UEFI anti-bricking code, including an effective
+reversion of cc5a080c and 31ff2f20. It turns out that calling
+QueryVariableInfo() from boot services results in some firmware
+implementations jumping to physical addresses even after entering virtual
+mode, so until we have 1:1 mappings for UEFI runtime space this isn't
+going to work so well.
+
+Reverting these gets us back to the situation where we'd refuse to create
+variables on some systems because they classify deleted variables as "used"
+until the firmware triggers a garbage collection run, which they won't do
+until they reach a lower threshold. This results in it being impossible to
+install a bootloader, which is unhelpful.
+
+Feedback from Samsung indicates that the firmware doesn't need more than
+5KB of storage space for its own purposes, so that seems like a reasonable
+threshold. However, there's still no guarantee that a platform will attempt
+garbage collection merely because it drops below this threshold. It seems
+that this is often only triggered if an attempt to write generates a
+genuine EFI_OUT_OF_RESOURCES error. We can force that by attempting to
+create a variable larger than the remaining space. This should fail, but if
+it somehow succeeds we can then immediately delete it.
+
+I've tested this on the UEFI machines I have available, but I don't have
+a Samsung and so can't verify that it avoids the bricking problem.
+
+Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
+Signed-off-by: Lee, Chun-Y <jlee@suse.com> [ dummy variable cleanup ]
+Signed-off-by: Matt Fleming <matt.fleming@intel.com>
+[bwh: Backported to 3.2: the reverted changes were never applied here]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Rui Xiang <rui.xiang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/platform/efi/efi.c |   79 +++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 68 insertions(+), 11 deletions(-)
+
+--- a/arch/x86/platform/efi/efi.c
++++ b/arch/x86/platform/efi/efi.c
+@@ -50,6 +50,13 @@
+ #define EFI_DEBUG     1
++#define EFI_MIN_RESERVE 5120
++
++#define EFI_DUMMY_GUID \
++      EFI_GUID(0x4424ac57, 0xbe4b, 0x47dd, 0x9e, 0x97, 0xed, 0x50, 0xf0, 0x9f, 0x92, 0xa9)
++
++static efi_char16_t efi_dummy_name[6] = { 'D', 'U', 'M', 'M', 'Y', 0 };
++
+ struct efi __read_mostly efi = {
+       .mps        = EFI_INVALID_TABLE_ADDR,
+       .acpi       = EFI_INVALID_TABLE_ADDR,
+@@ -932,6 +939,13 @@ void __init efi_enter_virtual_mode(void)
+               runtime_code_page_mkexec();
+       kfree(new_memmap);
++
++      /* clean DUMMY object */
++      efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
++                       EFI_VARIABLE_NON_VOLATILE |
++                       EFI_VARIABLE_BOOTSERVICE_ACCESS |
++                       EFI_VARIABLE_RUNTIME_ACCESS,
++                       0, NULL);
+ }
+ /*
+@@ -983,22 +997,65 @@ efi_status_t efi_query_variable_store(u3
+       efi_status_t status;
+       u64 storage_size, remaining_size, max_size;
++      if (!(attributes & EFI_VARIABLE_NON_VOLATILE))
++              return 0;
++
+       status = efi.query_variable_info(attributes, &storage_size,
+                                        &remaining_size, &max_size);
+       if (status != EFI_SUCCESS)
+               return status;
+-      if (!max_size && remaining_size > size)
+-              printk_once(KERN_ERR FW_BUG "Broken EFI implementation"
+-                          " is returning MaxVariableSize=0\n");
+-
+-      if (!storage_size || size > remaining_size ||
+-          (max_size && size > max_size))
+-              return EFI_OUT_OF_RESOURCES;
+-
+-      if (!efi_no_storage_paranoia &&
+-          (remaining_size - size) < (storage_size / 2))
+-              return EFI_OUT_OF_RESOURCES;
++      /*
++       * Some firmware implementations refuse to boot if there's insufficient
++       * space in the variable store. We account for that by refusing the
++       * write if permitting it would reduce the available space to under
++       * 5KB. This figure was provided by Samsung, so should be safe.
++       */
++      if ((remaining_size - size < EFI_MIN_RESERVE) &&
++              !efi_no_storage_paranoia) {
++
++              /*
++               * Triggering garbage collection may require that the firmware
++               * generate a real EFI_OUT_OF_RESOURCES error. We can force
++               * that by attempting to use more space than is available.
++               */
++              unsigned long dummy_size = remaining_size + 1024;
++              void *dummy = kmalloc(dummy_size, GFP_ATOMIC);
++
++              status = efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
++                                        EFI_VARIABLE_NON_VOLATILE |
++                                        EFI_VARIABLE_BOOTSERVICE_ACCESS |
++                                        EFI_VARIABLE_RUNTIME_ACCESS,
++                                        dummy_size, dummy);
++
++              if (status == EFI_SUCCESS) {
++                      /*
++                       * This should have failed, so if it didn't make sure
++                       * that we delete it...
++                       */
++                      efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
++                                       EFI_VARIABLE_NON_VOLATILE |
++                                       EFI_VARIABLE_BOOTSERVICE_ACCESS |
++                                       EFI_VARIABLE_RUNTIME_ACCESS,
++                                       0, dummy);
++              }
++
++              /*
++               * The runtime code may now have triggered a garbage collection
++               * run, so check the variable info again
++               */
++              status = efi.query_variable_info(attributes, &storage_size,
++                                               &remaining_size, &max_size);
++
++              if (status != EFI_SUCCESS)
++                      return status;
++
++              /*
++               * There still isn't enough room, so return an error
++               */
++              if (remaining_size - size < EFI_MIN_RESERVE)
++                      return EFI_OUT_OF_RESOURCES;
++      }
+       return EFI_SUCCESS;
+ }
index b604498b4c238becc7cf5c443f592e4487ca2880..be3ce7f46170fbf3f69f425df78a6be4d28af8d2 100644 (file)
@@ -144,3 +144,12 @@ efivars-disable-external-interrupt-while-holding-efivars-lock.patch
 efi-be-more-paranoid-about-available-space-when-creating-variables.patch
 efivars-pstore-do-not-check-size-when-erasing-variable.patch
 efivars-allow-disabling-use-as-a-pstore-backend.patch
+efivars-add-module-parameter-to-disable-use-as-a-pstore-backend.patch
+efivars-fix-check-for-config_efi_vars_pstore_default_disable.patch
+efi_pstore-introducing-workqueue-updating-sysfs.patch
+x86-efivars-firmware-bug-workarounds-should-be-in-platform-code.patch
+x86-efi-check-max_size-only-if-it-is-non-zero.patch
+efi-export-efi_query_variable_store-for-efivars.ko.patch
+x86-efi-implement-efi_no_storage_paranoia-parameter.patch
+modify-uefi-anti-bricking-code.patch
+x86-efi-fix-dummy-variable-buffer-allocation.patch
diff --git a/queue-3.4/x86-efi-check-max_size-only-if-it-is-non-zero.patch b/queue-3.4/x86-efi-check-max_size-only-if-it-is-non-zero.patch
new file mode 100644 (file)
index 0000000..60974ae
--- /dev/null
@@ -0,0 +1,39 @@
+From b12bcd7b3fe04a5fcca945aaf5b74181d9a223f4 Mon Sep 17 00:00:00 2001
+From: Richard Weinberger <richard@nod.at>
+Date: Wed, 10 Apr 2013 10:59:34 +0200
+Subject: x86,efi: Check max_size only if it is non-zero.
+
+From: Richard Weinberger <richard@nod.at>
+
+commit 7791c8423f1f7f4dad94e753bae67461d5b80be8 upstream.
+
+Some EFI implementations return always a MaximumVariableSize of 0,
+check against max_size only if it is non-zero.
+My Intel DQ67SW desktop board has such an implementation.
+
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Signed-off-by: Matt Fleming <matt.fleming@intel.com>
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Rui Xiang <rui.xiang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/platform/efi/efi.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/platform/efi/efi.c
++++ b/arch/x86/platform/efi/efi.c
+@@ -979,7 +979,12 @@ efi_status_t efi_query_variable_store(u3
+       if (status != EFI_SUCCESS)
+               return status;
+-      if (!storage_size || size > remaining_size || size > max_size ||
++      if (!max_size && remaining_size > size)
++              printk_once(KERN_ERR FW_BUG "Broken EFI implementation"
++                          " is returning MaxVariableSize=0\n");
++
++      if (!storage_size || size > remaining_size ||
++          (max_size && size > max_size) ||
+           (remaining_size - size) < (storage_size / 2))
+               return EFI_OUT_OF_RESOURCES;
diff --git a/queue-3.4/x86-efi-fix-dummy-variable-buffer-allocation.patch b/queue-3.4/x86-efi-fix-dummy-variable-buffer-allocation.patch
new file mode 100644 (file)
index 0000000..32d7001
--- /dev/null
@@ -0,0 +1,49 @@
+From b35b16d2be61943373f16ceb6184a66da84ab229 Mon Sep 17 00:00:00 2001
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Sun, 16 Jun 2013 21:27:12 +0100
+Subject: x86/efi: Fix dummy variable buffer allocation
+
+From: Ben Hutchings <ben@decadent.org.uk>
+
+commit b8cb62f82103083a6e8fa5470bfe634a2c06514d upstream.
+
+1. Check for allocation failure
+2. Clear the buffer contents, as they may actually be written to flash
+3. Don't leak the buffer
+
+Compile-tested only.
+
+[ Tested successfully on my buggy ASUS machine - Matt ]
+
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Matt Fleming <matt.fleming@intel.com>
+Cc: Rui Xiang <rui.xiang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/platform/efi/efi.c |    7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/arch/x86/platform/efi/efi.c
++++ b/arch/x86/platform/efi/efi.c
+@@ -1020,7 +1020,10 @@ efi_status_t efi_query_variable_store(u3
+                * that by attempting to use more space than is available.
+                */
+               unsigned long dummy_size = remaining_size + 1024;
+-              void *dummy = kmalloc(dummy_size, GFP_ATOMIC);
++              void *dummy = kzalloc(dummy_size, GFP_ATOMIC);
++
++              if (!dummy)
++                      return EFI_OUT_OF_RESOURCES;
+               status = efi.set_variable(efi_dummy_name, &EFI_DUMMY_GUID,
+                                         EFI_VARIABLE_NON_VOLATILE |
+@@ -1040,6 +1043,8 @@ efi_status_t efi_query_variable_store(u3
+                                        0, dummy);
+               }
++              kfree(dummy);
++
+               /*
+                * The runtime code may now have triggered a garbage collection
+                * run, so check the variable info again
diff --git a/queue-3.4/x86-efi-implement-efi_no_storage_paranoia-parameter.patch b/queue-3.4/x86-efi-implement-efi_no_storage_paranoia-parameter.patch
new file mode 100644 (file)
index 0000000..63466e6
--- /dev/null
@@ -0,0 +1,73 @@
+From 2a068400fcef7b1563d60f294b584b728236307f Mon Sep 17 00:00:00 2001
+From: Richard Weinberger <richard@nod.at>
+Date: Wed, 17 Apr 2013 01:00:53 +0200
+Subject: x86,efi: Implement efi_no_storage_paranoia parameter
+
+From: Richard Weinberger <richard@nod.at>
+
+commit 8c58bf3eec3b8fc8162fe557e9361891c20758f2 upstream.
+
+Using this parameter one can disable the storage_size/2 check if
+he is really sure that the UEFI does sane gc and fulfills the spec.
+
+This parameter is useful if a devices uses more than 50% of the
+storage by default.
+The Intel DQSW67 desktop board is such a sucker for exmaple.
+
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Signed-off-by: Matt Fleming <matt.fleming@intel.com>
+[bwh: Backported to 3.2: adjust context]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Cc: Rui Xiang <rui.xiang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ Documentation/kernel-parameters.txt |    6 ++++++
+ arch/x86/platform/efi/efi.c         |   14 +++++++++++++-
+ 2 files changed, 19 insertions(+), 1 deletion(-)
+
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -773,6 +773,12 @@ bytes respectively. Such letter suffixes
+       edd=            [EDD]
+                       Format: {"off" | "on" | "skip[mbr]"}
++      efi_no_storage_paranoia [EFI; X86]
++                      Using this parameter you can use more than 50% of
++                      your efi variable storage. Use this parameter only if
++                      you are really sure that your UEFI does sane gc and
++                      fulfills the spec otherwise your board may brick.
++
+       eisa_irq_edge=  [PARISC,HW]
+                       See header of drivers/parisc/eisa.c.
+--- a/arch/x86/platform/efi/efi.c
++++ b/arch/x86/platform/efi/efi.c
+@@ -102,6 +102,15 @@ static int __init setup_add_efi_memmap(c
+ }
+ early_param("add_efi_memmap", setup_add_efi_memmap);
++static bool efi_no_storage_paranoia;
++
++static int __init setup_storage_paranoia(char *arg)
++{
++      efi_no_storage_paranoia = true;
++      return 0;
++}
++early_param("efi_no_storage_paranoia", setup_storage_paranoia);
++
+ static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+ {
+@@ -984,7 +993,10 @@ efi_status_t efi_query_variable_store(u3
+                           " is returning MaxVariableSize=0\n");
+       if (!storage_size || size > remaining_size ||
+-          (max_size && size > max_size) ||
++          (max_size && size > max_size))
++              return EFI_OUT_OF_RESOURCES;
++
++      if (!efi_no_storage_paranoia &&
+           (remaining_size - size) < (storage_size / 2))
+               return EFI_OUT_OF_RESOURCES;
diff --git a/queue-3.4/x86-efivars-firmware-bug-workarounds-should-be-in-platform-code.patch b/queue-3.4/x86-efivars-firmware-bug-workarounds-should-be-in-platform-code.patch
new file mode 100644 (file)
index 0000000..aa14771
--- /dev/null
@@ -0,0 +1,131 @@
+From a6e4d5a03e9e3587e88aba687d8f225f4f04c792 Mon Sep 17 00:00:00 2001
+From: Matt Fleming <matt.fleming@intel.com>
+Date: Mon, 25 Mar 2013 09:14:30 +0000
+Subject: x86, efivars: firmware bug workarounds should be in platform code
+
+From: Matt Fleming <matt.fleming@intel.com>
+
+commit a6e4d5a03e9e3587e88aba687d8f225f4f04c792 upstream.
+
+Let's not burden ia64 with checks in the common efivars code that we're not
+writing too much data to the variable store. That kind of thing is an x86
+firmware bug, plain and simple.
+
+efi_query_variable_store() provides platforms with a wrapper in which they can
+perform checks and workarounds for EFI variable storage bugs.
+
+Cc: H. Peter Anvin <hpa@zytor.com>
+Cc: Matthew Garrett <mjg59@srcf.ucam.org>
+Signed-off-by: Matt Fleming <matt.fleming@intel.com>
+[xr: Backported to 3.4: adjust context]
+Signed-off-by: Rui Xiang <rui.xiang@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/platform/efi/efi.c |   25 +++++++++++++++++++++++++
+ drivers/firmware/efivars.c  |   18 +++---------------
+ include/linux/efi.h         |    9 ++++++++-
+ 3 files changed, 36 insertions(+), 16 deletions(-)
+
+--- a/arch/x86/platform/efi/efi.c
++++ b/arch/x86/platform/efi/efi.c
+@@ -960,3 +960,28 @@ u64 efi_mem_attributes(unsigned long phy
+       }
+       return 0;
+ }
++
++/*
++ * Some firmware has serious problems when using more than 50% of the EFI
++ * variable store, i.e. it triggers bugs that can brick machines. Ensure that
++ * we never use more than this safe limit.
++ *
++ * Return EFI_SUCCESS if it is safe to write 'size' bytes to the variable
++ * store.
++ */
++efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
++{
++      efi_status_t status;
++      u64 storage_size, remaining_size, max_size;
++
++      status = efi.query_variable_info(attributes, &storage_size,
++                                       &remaining_size, &max_size);
++      if (status != EFI_SUCCESS)
++              return status;
++
++      if (!storage_size || size > remaining_size || size > max_size ||
++          (remaining_size - size) < (storage_size / 2))
++              return EFI_OUT_OF_RESOURCES;
++
++      return EFI_SUCCESS;
++}
+--- a/drivers/firmware/efivars.c
++++ b/drivers/firmware/efivars.c
+@@ -425,24 +425,12 @@ static efi_status_t
+ check_var_size_locked(struct efivars *efivars, u32 attributes,
+                       unsigned long size)
+ {
+-      u64 storage_size, remaining_size, max_size;
+-      efi_status_t status;
+       const struct efivar_operations *fops = efivars->ops;
+-      if (!efivars->ops->query_variable_info)
++      if (!efivars->ops->query_variable_store)
+               return EFI_UNSUPPORTED;
+-      status = fops->query_variable_info(attributes, &storage_size,
+-                                         &remaining_size, &max_size);
+-
+-      if (status != EFI_SUCCESS)
+-              return status;
+-
+-      if (!storage_size || size > remaining_size || size > max_size ||
+-          (remaining_size - size) < (storage_size / 2))
+-              return EFI_OUT_OF_RESOURCES;
+-
+-      return status;
++      return fops->query_variable_store(attributes, size);
+ }
+ static ssize_t
+@@ -1445,7 +1433,7 @@ efivars_init(void)
+       ops.get_variable = efi.get_variable;
+       ops.set_variable = efi.set_variable;
+       ops.get_next_variable = efi.get_next_variable;
+-      ops.query_variable_info = efi.query_variable_info;
++      ops.query_variable_store = efi_query_variable_store;
+       error = register_efivars(&__efivars, &ops, efi_kobj);
+       if (error)
+               goto err_put;
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -262,6 +262,7 @@ typedef efi_status_t efi_query_capsule_c
+                                             unsigned long count,
+                                             u64 *max_size,
+                                             int *reset_type);
++typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long size);
+ /*
+  *  EFI Configuration Table and GUID definitions
+@@ -503,8 +504,14 @@ extern void efi_gettimeofday (struct tim
+ extern void efi_enter_virtual_mode (void);    /* switch EFI to virtual mode, if possible */
+ #ifdef CONFIG_X86
+ extern void efi_free_boot_services(void);
++extern efi_status_t efi_query_variable_store(u32 attributes, unsigned long size);
+ #else
+ static inline void efi_free_boot_services(void) {}
++
++static inline efi_status_t efi_query_variable_store(u32 attributes, unsigned long size)
++{
++      return EFI_SUCCESS;
++}
+ #endif
+ extern u64 efi_get_iobase (void);
+ extern u32 efi_mem_type (unsigned long phys_addr);
+@@ -657,7 +664,7 @@ struct efivar_operations {
+       efi_get_variable_t *get_variable;
+       efi_get_next_variable_t *get_next_variable;
+       efi_set_variable_t *set_variable;
+-      efi_query_variable_info_t *query_variable_info;
++      efi_query_variable_store_t *query_variable_store;
+ };
+ struct efivars {