]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.1
authorSasha Levin <sashal@kernel.org>
Tue, 24 Jan 2023 22:55:43 +0000 (17:55 -0500)
committerSasha Levin <sashal@kernel.org>
Tue, 24 Jan 2023 22:55:43 +0000 (17:55 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-6.1/arm64-efi-account-for-the-efi-runtime-stack-in-stack.patch [new file with mode: 0644]
queue-6.1/arm64-efi-avoid-workqueue-to-check-whether-efi-runti.patch [new file with mode: 0644]
queue-6.1/arm64-efi-recover-from-synchronous-exceptions-occurr.patch [new file with mode: 0644]
queue-6.1/series

diff --git a/queue-6.1/arm64-efi-account-for-the-efi-runtime-stack-in-stack.patch b/queue-6.1/arm64-efi-account-for-the-efi-runtime-stack-in-stack.patch
new file mode 100644 (file)
index 0000000..393d5ea
--- /dev/null
@@ -0,0 +1,91 @@
+From 8ac4d85ae44fdcd01aae5f4889b08a7600801fd2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 9 Dec 2022 12:10:13 +0100
+Subject: arm64: efi: Account for the EFI runtime stack in stack unwinder
+
+From: Ard Biesheuvel <ardb@kernel.org>
+
+[ Upstream commit 7ea55715c421d22c1b63f7129cae6a654091b695 ]
+
+The EFI runtime services run from a dedicated stack now, and so the
+stack unwinder needs to be informed about this.
+
+Acked-by: Mark Rutland <mark.rutland@arm.com>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/stacktrace.h | 15 +++++++++++++++
+ arch/arm64/kernel/stacktrace.c      | 12 ++++++++++++
+ 2 files changed, 27 insertions(+)
+
+diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h
+index 5a0edb064ea4..327cdcfcb1db 100644
+--- a/arch/arm64/include/asm/stacktrace.h
++++ b/arch/arm64/include/asm/stacktrace.h
+@@ -104,4 +104,19 @@ static inline struct stack_info stackinfo_get_sdei_critical(void)
+ #define stackinfo_get_sdei_critical() stackinfo_get_unknown()
+ #endif
++#ifdef CONFIG_EFI
++extern u64 *efi_rt_stack_top;
++
++static inline struct stack_info stackinfo_get_efi(void)
++{
++      unsigned long high = (u64)efi_rt_stack_top;
++      unsigned long low = high - THREAD_SIZE;
++
++      return (struct stack_info) {
++              .low = low,
++              .high = high,
++      };
++}
++#endif
++
+ #endif        /* __ASM_STACKTRACE_H */
+diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
+index 117e2c180f3c..83154303e682 100644
+--- a/arch/arm64/kernel/stacktrace.c
++++ b/arch/arm64/kernel/stacktrace.c
+@@ -5,6 +5,7 @@
+  * Copyright (C) 2012 ARM Ltd.
+  */
+ #include <linux/kernel.h>
++#include <linux/efi.h>
+ #include <linux/export.h>
+ #include <linux/ftrace.h>
+ #include <linux/sched.h>
+@@ -12,6 +13,7 @@
+ #include <linux/sched/task_stack.h>
+ #include <linux/stacktrace.h>
++#include <asm/efi.h>
+ #include <asm/irq.h>
+ #include <asm/stack_pointer.h>
+ #include <asm/stacktrace.h>
+@@ -186,6 +188,13 @@ void show_stack(struct task_struct *tsk, unsigned long *sp, const char *loglvl)
+                       : stackinfo_get_unknown();              \
+       })
++#define STACKINFO_EFI                                         \
++      ({                                                      \
++              ((task == current) && current_in_efi())         \
++                      ? stackinfo_get_efi()                   \
++                      : stackinfo_get_unknown();              \
++      })
++
+ noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry,
+                             void *cookie, struct task_struct *task,
+                             struct pt_regs *regs)
+@@ -199,6 +208,9 @@ noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry,
+ #if defined(CONFIG_VMAP_STACK) && defined(CONFIG_ARM_SDE_INTERFACE)
+               STACKINFO_SDEI(normal),
+               STACKINFO_SDEI(critical),
++#endif
++#ifdef CONFIG_EFI
++              STACKINFO_EFI,
+ #endif
+       };
+       struct unwind_state state = {
+-- 
+2.39.0
+
diff --git a/queue-6.1/arm64-efi-avoid-workqueue-to-check-whether-efi-runti.patch b/queue-6.1/arm64-efi-avoid-workqueue-to-check-whether-efi-runti.patch
new file mode 100644 (file)
index 0000000..6c6e053
--- /dev/null
@@ -0,0 +1,104 @@
+From 42d095c4a8567b8bf8d97c16970f79003a2c1a6c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Oct 2022 16:39:14 +0200
+Subject: arm64: efi: Avoid workqueue to check whether EFI runtime is live
+
+From: Ard Biesheuvel <ardb@kernel.org>
+
+[ Upstream commit 8a9a1a18731eb123e35f48176380a18b9782845e ]
+
+Comparing current_work() against efi_rts_work.work is sufficient to
+decide whether current is currently running EFI runtime services code at
+any level in its call stack.
+
+However, there are other potential users of the EFI runtime stack, such
+as the ACPI subsystem, which may invoke efi_call_virt_pointer()
+directly, and so any sync exceptions occurring in firmware during those
+calls are currently misidentified.
+
+So instead, let's check whether the stashed value of the thread stack
+pointer points into current's thread stack. This can only be the case if
+current was interrupted while running EFI runtime code. Note that this
+implies that we should clear the stashed value after switching back, to
+avoid false positives.
+
+Reviewed-by: Mark Rutland <mark.rutland@arm.com>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/efi.h       | 9 +++++++++
+ arch/arm64/kernel/efi-rt-wrapper.S | 6 ++++++
+ arch/arm64/kernel/efi.c            | 3 ++-
+ 3 files changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
+index 0edaf8e385b8..b13c22046de5 100644
+--- a/arch/arm64/include/asm/efi.h
++++ b/arch/arm64/include/asm/efi.h
+@@ -48,8 +48,17 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);
+ })
+ extern spinlock_t efi_rt_lock;
++extern u64 *efi_rt_stack_top;
+ efi_status_t __efi_rt_asm_wrapper(void *, const char *, ...);
++/*
++ * efi_rt_stack_top[-1] contains the value the stack pointer had before
++ * switching to the EFI runtime stack.
++ */
++#define current_in_efi()                                              \
++      (!preemptible() && efi_rt_stack_top != NULL &&                  \
++       on_task_stack(current, READ_ONCE(efi_rt_stack_top[-1]), 1))
++
+ #define ARCH_EFI_IRQ_FLAGS_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
+ /*
+diff --git a/arch/arm64/kernel/efi-rt-wrapper.S b/arch/arm64/kernel/efi-rt-wrapper.S
+index d872d18101d8..e8ae803662cf 100644
+--- a/arch/arm64/kernel/efi-rt-wrapper.S
++++ b/arch/arm64/kernel/efi-rt-wrapper.S
+@@ -46,7 +46,10 @@ SYM_FUNC_START(__efi_rt_asm_wrapper)
+       mov     x4, x6
+       blr     x8
++      mov     x16, sp
+       mov     sp, x29
++      str     xzr, [x16, #8]                  // clear recorded task SP value
++
+       ldp     x1, x2, [sp, #16]
+       cmp     x2, x18
+       ldp     x29, x30, [sp], #112
+@@ -71,6 +74,9 @@ SYM_FUNC_END(__efi_rt_asm_wrapper)
+ SYM_CODE_START(__efi_rt_asm_recover)
+       mov     sp, x30
++      ldr_l   x16, efi_rt_stack_top           // clear recorded task SP value
++      str     xzr, [x16, #-8]
++
+       ldp     x19, x20, [sp, #32]
+       ldp     x21, x22, [sp, #48]
+       ldp     x23, x24, [sp, #64]
+diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
+index fab05de2e12d..b273900f4566 100644
+--- a/arch/arm64/kernel/efi.c
++++ b/arch/arm64/kernel/efi.c
+@@ -11,6 +11,7 @@
+ #include <linux/init.h>
+ #include <asm/efi.h>
++#include <asm/stacktrace.h>
+ static bool region_is_misaligned(const efi_memory_desc_t *md)
+ {
+@@ -154,7 +155,7 @@ asmlinkage efi_status_t __efi_rt_asm_recover(void);
+ bool efi_runtime_fixup_exception(struct pt_regs *regs, const char *msg)
+ {
+        /* Check whether the exception occurred while running the firmware */
+-      if (current_work() != &efi_rts_work.work || regs->pc >= TASK_SIZE_64)
++      if (!current_in_efi() || regs->pc >= TASK_SIZE_64)
+               return false;
+       pr_err(FW_BUG "Unable to handle %s in EFI runtime service\n", msg);
+-- 
+2.39.0
+
diff --git a/queue-6.1/arm64-efi-recover-from-synchronous-exceptions-occurr.patch b/queue-6.1/arm64-efi-recover-from-synchronous-exceptions-occurr.patch
new file mode 100644 (file)
index 0000000..60c327c
--- /dev/null
@@ -0,0 +1,197 @@
+From d6d33475c308f7e389651c291ee31676fe6096d8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 28 Oct 2022 16:39:14 +0200
+Subject: arm64: efi: Recover from synchronous exceptions occurring in firmware
+
+From: Ard Biesheuvel <ardb@kernel.org>
+
+[ Upstream commit e8dfdf3162eb549d064b8c10b1564f7e8ee82591 ]
+
+Unlike x86, which has machinery to deal with page faults that occur
+during the execution of EFI runtime services, arm64 has nothing like
+that, and a synchronous exception raised by firmware code brings down
+the whole system.
+
+With more EFI based systems appearing that were not built to run Linux
+(such as the Windows-on-ARM laptops based on Qualcomm SOCs), as well as
+the introduction of PRM (platform specific firmware routines that are
+callable just like EFI runtime services), we are more likely to run into
+issues of this sort, and it is much more likely that we can identify and
+work around such issues if they don't bring down the system entirely.
+
+Since we already use a EFI runtime services call wrapper in assembler,
+we can quite easily add some code that captures the execution state at
+the point where the call is made, allowing us to revert to this state
+and proceed execution if the call triggered a synchronous exception.
+
+Given that the kernel and the firmware don't share any data structures
+that could end up in an indeterminate state, we can happily continue
+running, as long as we mark the EFI runtime services as unavailable from
+that point on.
+
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Acked-by: Catalin Marinas <catalin.marinas@arm.com>
+Stable-dep-of: 8a9a1a18731e ("arm64: efi: Avoid workqueue to check whether EFI runtime is live")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/efi.h            |  8 +++++++
+ arch/arm64/kernel/efi-rt-wrapper.S      | 32 +++++++++++++++++++++----
+ arch/arm64/kernel/efi.c                 | 22 +++++++++++++++++
+ arch/arm64/mm/fault.c                   |  4 ++++
+ drivers/firmware/efi/runtime-wrappers.c |  1 +
+ 5 files changed, 62 insertions(+), 5 deletions(-)
+
+diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
+index b9f3165075c9..0edaf8e385b8 100644
+--- a/arch/arm64/include/asm/efi.h
++++ b/arch/arm64/include/asm/efi.h
+@@ -14,8 +14,16 @@
+ #ifdef CONFIG_EFI
+ extern void efi_init(void);
++
++bool efi_runtime_fixup_exception(struct pt_regs *regs, const char *msg);
+ #else
+ #define efi_init()
++
++static inline
++bool efi_runtime_fixup_exception(struct pt_regs *regs, const char *msg)
++{
++      return false;
++}
+ #endif
+ int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
+diff --git a/arch/arm64/kernel/efi-rt-wrapper.S b/arch/arm64/kernel/efi-rt-wrapper.S
+index 2d3c4b02393e..d872d18101d8 100644
+--- a/arch/arm64/kernel/efi-rt-wrapper.S
++++ b/arch/arm64/kernel/efi-rt-wrapper.S
+@@ -7,7 +7,7 @@
+ #include <asm/assembler.h>
+ SYM_FUNC_START(__efi_rt_asm_wrapper)
+-      stp     x29, x30, [sp, #-32]!
++      stp     x29, x30, [sp, #-112]!
+       mov     x29, sp
+       /*
+@@ -17,11 +17,21 @@ SYM_FUNC_START(__efi_rt_asm_wrapper)
+        */
+       stp     x1, x18, [sp, #16]
++      /*
++       * Preserve all callee saved registers and preserve the stack pointer
++       * value at the base of the EFI runtime stack so we can recover from
++       * synchronous exceptions occurring while executing the firmware
++       * routines.
++       */
++      stp     x19, x20, [sp, #32]
++      stp     x21, x22, [sp, #48]
++      stp     x23, x24, [sp, #64]
++      stp     x25, x26, [sp, #80]
++      stp     x27, x28, [sp, #96]
++
+       ldr_l   x16, efi_rt_stack_top
+       mov     sp, x16
+-#ifdef CONFIG_SHADOW_CALL_STACK
+-      str     x18, [sp, #-16]!
+-#endif
++      stp     x18, x29, [sp, #-16]!
+       /*
+        * We are lucky enough that no EFI runtime services take more than
+@@ -39,7 +49,7 @@ SYM_FUNC_START(__efi_rt_asm_wrapper)
+       mov     sp, x29
+       ldp     x1, x2, [sp, #16]
+       cmp     x2, x18
+-      ldp     x29, x30, [sp], #32
++      ldp     x29, x30, [sp], #112
+       b.ne    0f
+       ret
+ 0:
+@@ -57,3 +67,15 @@ SYM_FUNC_START(__efi_rt_asm_wrapper)
+       b       efi_handle_corrupted_x18        // tail call
+ SYM_FUNC_END(__efi_rt_asm_wrapper)
++
++SYM_CODE_START(__efi_rt_asm_recover)
++      mov     sp, x30
++
++      ldp     x19, x20, [sp, #32]
++      ldp     x21, x22, [sp, #48]
++      ldp     x23, x24, [sp, #64]
++      ldp     x25, x26, [sp, #80]
++      ldp     x27, x28, [sp, #96]
++      ldp     x29, x30, [sp], #112
++      ret
++SYM_CODE_END(__efi_rt_asm_recover)
+diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
+index 386bd81ca12b..fab05de2e12d 100644
+--- a/arch/arm64/kernel/efi.c
++++ b/arch/arm64/kernel/efi.c
+@@ -149,6 +149,28 @@ DEFINE_SPINLOCK(efi_rt_lock);
+ asmlinkage u64 *efi_rt_stack_top __ro_after_init;
++asmlinkage efi_status_t __efi_rt_asm_recover(void);
++
++bool efi_runtime_fixup_exception(struct pt_regs *regs, const char *msg)
++{
++       /* Check whether the exception occurred while running the firmware */
++      if (current_work() != &efi_rts_work.work || regs->pc >= TASK_SIZE_64)
++              return false;
++
++      pr_err(FW_BUG "Unable to handle %s in EFI runtime service\n", msg);
++      add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
++      clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
++
++      regs->regs[0]   = EFI_ABORTED;
++      regs->regs[30]  = efi_rt_stack_top[-1];
++      regs->pc        = (u64)__efi_rt_asm_recover;
++
++      if (IS_ENABLED(CONFIG_SHADOW_CALL_STACK))
++              regs->regs[18] = efi_rt_stack_top[-2];
++
++      return true;
++}
++
+ /* EFI requires 8 KiB of stack space for runtime services */
+ static_assert(THREAD_SIZE >= SZ_8K);
+diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
+index 74f76514a48d..3eb2825d08cf 100644
+--- a/arch/arm64/mm/fault.c
++++ b/arch/arm64/mm/fault.c
+@@ -30,6 +30,7 @@
+ #include <asm/bug.h>
+ #include <asm/cmpxchg.h>
+ #include <asm/cpufeature.h>
++#include <asm/efi.h>
+ #include <asm/exception.h>
+ #include <asm/daifflags.h>
+ #include <asm/debug-monitors.h>
+@@ -397,6 +398,9 @@ static void __do_kernel_fault(unsigned long addr, unsigned long esr,
+               msg = "paging request";
+       }
++      if (efi_runtime_fixup_exception(regs, msg))
++              return;
++
+       die_kernel_fault(msg, addr, esr, regs);
+ }
+diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c
+index 60075e0e4943..1fba4e09cdcf 100644
+--- a/drivers/firmware/efi/runtime-wrappers.c
++++ b/drivers/firmware/efi/runtime-wrappers.c
+@@ -84,6 +84,7 @@ struct efi_runtime_work efi_rts_work;
+       else                                                            \
+               pr_err("Failed to queue work to efi_rts_wq.\n");        \
+                                                                       \
++      WARN_ON_ONCE(efi_rts_work.status == EFI_ABORTED);               \
+ exit:                                                                 \
+       efi_rts_work.efi_rts_id = EFI_NONE;                             \
+       efi_rts_work.status;                                            \
+-- 
+2.39.0
+
index 83e7d38e27247282b414b41624135fdf70444822..81bf9c60f148ef97eb265d0d38e205b4bffdf549 100644 (file)
@@ -191,3 +191,6 @@ ata-pata_cs5535-don-t-build-on-uml.patch
 firmware-coreboot-check-size-of-table-entry-and-use-.patch
 btrfs-zoned-enable-metadata-over-commit-for-non-zns-.patch
 revert-selftests-bpf-check-null-propagation-only-nei.patch
+arm64-efi-recover-from-synchronous-exceptions-occurr.patch
+arm64-efi-avoid-workqueue-to-check-whether-efi-runti.patch
+arm64-efi-account-for-the-efi-runtime-stack-in-stack.patch