From: Sasha Levin Date: Tue, 24 Jan 2023 22:55:43 +0000 (-0500) Subject: Fixes for 6.1 X-Git-Tag: v5.10.166~87 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b32795c0a8a0b0d74fe2ec070fa9c976a9d21f08;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 6.1 Signed-off-by: Sasha Levin --- 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 index 00000000000..393d5ea5b3f --- /dev/null +++ b/queue-6.1/arm64-efi-account-for-the-efi-runtime-stack-in-stack.patch @@ -0,0 +1,91 @@ +From 8ac4d85ae44fdcd01aae5f4889b08a7600801fd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Dec 2022 12:10:13 +0100 +Subject: arm64: efi: Account for the EFI runtime stack in stack unwinder + +From: Ard Biesheuvel + +[ 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 +Signed-off-by: Ard Biesheuvel +Signed-off-by: Sasha Levin +--- + 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 ++#include + #include + #include + #include +@@ -12,6 +13,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -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 index 00000000000..6c6e053cc3f --- /dev/null +++ b/queue-6.1/arm64-efi-avoid-workqueue-to-check-whether-efi-runti.patch @@ -0,0 +1,104 @@ +From 42d095c4a8567b8bf8d97c16970f79003a2c1a6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 16:39:14 +0200 +Subject: arm64: efi: Avoid workqueue to check whether EFI runtime is live + +From: Ard Biesheuvel + +[ 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 +Signed-off-by: Ard Biesheuvel +Signed-off-by: Sasha Levin +--- + 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 + + #include ++#include + + 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 index 00000000000..60c327c9473 --- /dev/null +++ b/queue-6.1/arm64-efi-recover-from-synchronous-exceptions-occurr.patch @@ -0,0 +1,197 @@ +From d6d33475c308f7e389651c291ee31676fe6096d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 16:39:14 +0200 +Subject: arm64: efi: Recover from synchronous exceptions occurring in firmware + +From: Ard Biesheuvel + +[ 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 +Acked-by: Catalin Marinas +Stable-dep-of: 8a9a1a18731e ("arm64: efi: Avoid workqueue to check whether EFI runtime is live") +Signed-off-by: Sasha Levin +--- + 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 + + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 + diff --git a/queue-6.1/series b/queue-6.1/series index 83e7d38e272..81bf9c60f14 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -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