summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-23 09:24:34 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-23 09:24:34 -0700
commit388b607d107c07aaade04c7f22f344cab6bdccd3 (patch)
treefa1da3adc9fbd185280c75d64084c3d36f6e23f5 /drivers
parent91959a31a3990073b55b506af044eda09c359fb4 (diff)
parentb2326338dc683e8c1067c0cbf7a47986c4190902 (diff)
Merge tag 'efi-next-for-v7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi
Pull EFI updates from Ard Biesheuvel: - Set a timeout for EFI runtime service completions, and declare the firmware wedged if it is exceeded. Note that this requires special handling in case the firmware does return after all - Rate limit the efivarfs statfs() handler as the QueryVariableInfo() runtime service can be costly - Sanity check the size of struct properties_header on Mac/x86 - Tweak the prototype of efi_guid_to_str() * tag 'efi-next-for-v7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi: efivarfs: Rate limit statfs() handler efi: apple-properties: validate setup data header length efi: make efi_guid_to_str() take a const GUID pointer efi/runtime-wrappers: retire the worker if a wedged call ever returns efi/runtime-wrappers: honour EFI_RUNTIME_SERVICES in the non-blocking paths efi/runtime-wrappers: bound the wait for EFI runtime service calls efi/runtime-wrappers: check EFI_RUNTIME_SERVICES before using efi_rts_work efi/runtime-wrappers: handle queue_work() failure with goto exit efi/runtime-wrappers: factor out efi_rts_park_worker() efi: fix stale reference to efi_recover_from_page_fault()
Diffstat (limited to 'drivers')
-rw-r--r--drivers/firmware/efi/apple-properties.c5
-rw-r--r--drivers/firmware/efi/runtime-wrappers.c70
2 files changed, 64 insertions, 11 deletions
diff --git a/drivers/firmware/efi/apple-properties.c b/drivers/firmware/efi/apple-properties.c
index 2e525e17fba7..f401a04edf4c 100644
--- a/drivers/firmware/efi/apple-properties.c
+++ b/drivers/firmware/efi/apple-properties.c
@@ -207,7 +207,10 @@ static int __init map_properties(void)
}
properties = (struct properties_header *)data->data;
- if (properties->version != 1) {
+ if (data_len < sizeof(*properties)) {
+ pr_err("truncated properties header\n");
+ ret = -EINVAL;
+ } else if (properties->version != 1) {
pr_err("unsupported version:\n");
print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET,
16, 1, properties, data_len, true);
diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c
index da8d29621644..2344b9d1e81f 100644
--- a/drivers/firmware/efi/runtime-wrappers.c
+++ b/drivers/firmware/efi/runtime-wrappers.c
@@ -119,6 +119,14 @@ union efi_rts_args {
struct efi_runtime_work efi_rts_work;
/*
+ * Upper bound on how long we wait for a single EFI runtime service
+ * call to finish before declaring firmware wedged. Chosen to be longer
+ * than any plausible legitimate call (including UpdateCapsule on slow
+ * SPI-NOR) while still bounding userspace wait time.
+ */
+#define EFI_RTS_TIMEOUT (120 * HZ)
+
+/*
* efi_queue_work: Queue EFI runtime service call and wait for completion
* @_rts: EFI runtime service function identifier
* @_args: Arguments to pass to the EFI runtime service
@@ -202,7 +210,7 @@ void efi_call_virt_check_flags(unsigned long flags, const void *caller)
*/
static DEFINE_SEMAPHORE(efi_runtime_lock, 1);
-static struct task_struct *efi_runtime_lock_owner;
+static struct task_struct *efi_runtime_lock_owner __used;
/*
* Expose the EFI runtime lock to the UV platform
@@ -212,6 +220,19 @@ extern struct semaphore __efi_uv_runtime_lock __alias(efi_runtime_lock);
#endif
/*
+ * Park a worker that must never run efi_rts_wq again: EFI runtime services
+ * have been disabled and its efi_rts_work is abandoned. Loop in schedule()
+ * so a spurious wakeup cannot resume it.
+ */
+void __noreturn efi_rts_park_worker(void)
+{
+ for (;;) {
+ set_current_state(TASK_IDLE);
+ schedule();
+ }
+}
+
+/*
* Calls the appropriate efi_runtime_service() with the appropriate
* arguments.
*/
@@ -221,6 +242,9 @@ static void __nocfi efi_call_rts(struct work_struct *work)
efi_status_t status = EFI_NOT_FOUND;
unsigned long flags;
+ if (!efi_enabled(EFI_RUNTIME_SERVICES))
+ efi_rts_park_worker();
+
efi_runtime_lock_owner = current;
arch_efi_call_virt_setup();
@@ -312,6 +336,9 @@ static void __nocfi efi_call_rts(struct work_struct *work)
efi_call_virt_check_flags(flags, efi_rts_work.caller);
arch_efi_call_virt_teardown();
+ if (!efi_enabled(EFI_RUNTIME_SERVICES))
+ efi_rts_park_worker();
+
efi_rts_work.status = status;
complete(&efi_rts_work.efi_rts_comp);
efi_runtime_lock_owner = NULL;
@@ -320,17 +347,16 @@ static void __nocfi efi_call_rts(struct work_struct *work)
static efi_status_t __efi_queue_work(enum efi_rts_ids id,
union efi_rts_args *args)
{
+ if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
+ pr_warn_once("EFI Runtime Services are disabled!\n");
+ return EFI_DEVICE_ERROR;
+ }
+
efi_rts_work.efi_rts_id = id;
efi_rts_work.args = args;
efi_rts_work.caller = __builtin_return_address(0);
efi_rts_work.status = EFI_ABORTED;
- if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
- pr_warn_once("EFI Runtime Services are disabled!\n");
- efi_rts_work.status = EFI_DEVICE_ERROR;
- goto exit;
- }
-
init_completion(&efi_rts_work.efi_rts_comp);
INIT_WORK(&efi_rts_work.work, efi_call_rts);
@@ -338,10 +364,18 @@ static efi_status_t __efi_queue_work(enum efi_rts_ids id,
* queue_work() returns 0 if work was already on queue,
* _ideally_ this should never happen.
*/
- if (queue_work(efi_rts_wq, &efi_rts_work.work))
- wait_for_completion(&efi_rts_work.efi_rts_comp);
- else
+ if (!queue_work(efi_rts_wq, &efi_rts_work.work)) {
pr_err("Failed to queue work to efi_rts_wq.\n");
+ goto exit;
+ }
+
+ if (!wait_for_completion_timeout(&efi_rts_work.efi_rts_comp,
+ EFI_RTS_TIMEOUT)) {
+ pr_err("EFI runtime service %d wedged in firmware; disabling EFI runtime services\n",
+ id);
+ clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+ return EFI_ABORTED;
+ }
WARN_ON_ONCE(efi_rts_work.status == EFI_ABORTED);
exit:
@@ -449,6 +483,11 @@ virt_efi_set_variable_nb(efi_char16_t *name, efi_guid_t *vendor, u32 attr,
if (down_trylock(&efi_runtime_lock))
return EFI_NOT_READY;
+ if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
+ up(&efi_runtime_lock);
+ return EFI_DEVICE_ERROR;
+ }
+
efi_runtime_lock_owner = current;
status = efi_call_virt_pointer(efi.runtime, set_variable, name, vendor,
attr, data_size, data);
@@ -488,6 +527,11 @@ virt_efi_query_variable_info_nb(u32 attr, u64 *storage_space,
if (down_trylock(&efi_runtime_lock))
return EFI_NOT_READY;
+ if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
+ up(&efi_runtime_lock);
+ return EFI_DEVICE_ERROR;
+ }
+
efi_runtime_lock_owner = current;
status = efi_call_virt_pointer(efi.runtime, query_variable_info, attr,
storage_space, remaining_space,
@@ -518,6 +562,12 @@ virt_efi_reset_system(int reset_type, efi_status_t status,
return;
}
+ if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
+ pr_warn("EFI Runtime Services are disabled, not invoking reset_system()\n");
+ up(&efi_runtime_lock);
+ return;
+ }
+
efi_runtime_lock_owner = current;
arch_efi_call_virt_setup();
efi_rts_work.efi_rts_id = EFI_RESET_SYSTEM;