arm64: efi: Robustify EFI runtime wrapper code
Subsystems (3)
Ard Biesheuvel
maintainercover arm64: efi: Robustify EFI runtime wrapper code
Make the EFI runtime wrapper code more robust, by switching to a dedicated stack and dealing with sync exceptions occurring in firmware by unwinding it. While at it, move the backup copy of register X18 onto the base of that stack too so we can can restore it if needed without reloading it from the ordinary stack.
Patch #2 is a v2 of a patch that got merged and reverted again in v6.1-rc.
This supersedes 'arm64: efi: Move runtime services asm wrapper out of .text'
Ard Biesheuvel (2):
arm64: efi: Execute runtime services from a dedicated stack
arm64: efi: Recover from synchronous exceptions occurring in firmware
arch/arm64/include/asm/efi.h | 11 +++++ arch/arm64/kernel/efi-rt-wrapper.S | 38 ++++++++++++++-- arch/arm64/kernel/efi.c | 47 ++++++++++++++++++++ arch/arm64/mm/fault.c | 4 ++ drivers/firmware/efi/runtime-wrappers.c | 1 + 5 files changed, 98 insertions(+), 3 deletions(-)
Signature · 1 line
2.35.1
Ard Biesheuvel
maintainerPATCH 1/2 arm64: efi: Execute runtime services from a dedicated stack
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of efi_call_virt_pointer() in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.
For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of efi_call_virt_pointer().
While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-)
arch/arm64/include/asm/efi.h +3 -0
@@ -25,6 +25,7 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md); ({ \efi_virtmap_load (); \__efi_fpsimd_begin (); \ +spin_lock (&efi_rt_lock); \ })#undef arch_efi_call_virt
@@ -33,10 +34,12 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);#define arch_efi_call_virt_teardown () \ ({ \ + spin_unlock(&efi_rt_lock); \ __efi_fpsimd_end(); \ efi_virtmap_unload(); \ }) +extern spinlock_t efi_rt_lock;efi_status_t __efi_rt_asm_wrapper (void *,const char *, ...);#define ARCH_EFI_IRQ_FLAGS_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)
arch/arm64/kernel/efi-rt-wrapper.S +12 -1
@@ -16,6 +16,12 @@ SYM_FUNC_START(__efi_rt_asm_wrapper) */ stp x1, x18, [sp, #16] + ldr_l x16, efi_rt_stack_top + mov sp, x16 +#ifdef CONFIG_SHADOW_CALL_STACK + str x18, [sp, #-16]! +#endif + /* * We are lucky enough that no EFI runtime services take more than * 5 arguments, so all are passed in registers rather than via the
@@ -29,6 +35,7 @@ SYM_FUNC_START(__efi_rt_asm_wrapper) mov x4, x6 blr x8 + mov sp, x29 ldp x1, x2, [sp, #16] cmp x2, x18 ldp x29, x30, [sp], #32
@@ -42,6 +49,10 @@ SYM_FUNC_START(__efi_rt_asm_wrapper) * called with preemption disabled and a separate shadow stack is used * for interrupts. */ - mov x18, x2 +#ifdef CONFIG_SHADOW_CALL_STACK + ldr_l x18, efi_rt_stack_top + ldr x18, [x18, #-16] +#endif + b efi_handle_corrupted_x18 // tail call SYM_FUNC_END(__efi_rt_asm_wrapper)
arch/arm64/kernel/efi.c +25 -0
@@ -144,3 +144,28 @@ asmlinkage efi_status_t efi_handle_corrupted_x18(efi_status_t s, const char *f)pr_err_ratelimited (FW_BUG "register x18 corrupted by EFI %s\n" , f);return s; } + +DEFINE_SPINLOCK (efi_rt_lock); + +asmlinkage u64 *efi_rt_stack_top __ro_after_init; + +/* required by the EFI spec */ +static_assert (THREAD_SIZE >=SZ_8K ); + +int __init arm64_efi_rt_init (void ) +{ +void *p =__vmalloc_node_range (THREAD_SIZE ,THREAD_ALIGN , +VMALLOC_START ,VMALLOC_END ,GFP_KERNEL , +PAGE_KERNEL ,0 ,NUMA_NO_NODE , +__builtin_return_address (0 )); + +if (!p) { +pr_warn ("Failed to allocate EFI runtime stack\n" ); +clear_bit (EFI_RUNTIME_SERVICES , &efi.flags); +return -ENOMEM ; + } + + efi_rt_stack_top = p +THREAD_SIZE ; +return 0 ; +} +core_initcall (arm64_efi_rt_init);
Signature · 1 line
2.35.1
Mark Rutland
reviewerRe: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
Hi Ard,
One drive-by comment below...
Quoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 5 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++
We'll need to teach the stack unwinder about this, or if we take an exception from the EFI stack, the backtrace will terminate as soon as it hits a frame record on the EFI stack.
In arch/arm64/kernel/stacktrace.c's arch_stack_walk(), that'll need to be added to the array of stack bounds. Ideally we'd only add that when a thread is making an EFI call.
Thanks,
Mark.
Quoted 100 lines
3 files changed, 40 insertions(+), 1 deletion(-)arch/arm64/include/asm/efi.h +3
-0@@ -25,6 +25,7 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md); ({ \efi_virtmap_load (); \__efi_fpsimd_begin (); \ +spin_lock (&efi_rt_lock); \ })#undef arch_efi_call_virt@@ -33,10 +34,12 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);#define arch_efi_call_virt_teardown () \ ({ \ + spin_unlock(&efi_rt_lock); \ __efi_fpsimd_end(); \ efi_virtmap_unload(); \ }) +extern spinlock_t efi_rt_lock;efi_status_t __efi_rt_asm_wrapper (void *,const char *, ...);#define ARCH_EFI_IRQ_FLAGS_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)arch/arm64/kernel/efi-rt-wrapper.S +12
-1@@ -16,6 +16,12 @@ SYM_FUNC_START(__efi_rt_asm_wrapper) */ stp x1, x18, [sp, #16] + ldr_l x16, efi_rt_stack_top + mov sp, x16 +#ifdef CONFIG_SHADOW_CALL_STACK + str x18, [sp, #-16]! +#endif + /* * We are lucky enough that no EFI runtime services take more than * 5 arguments, so all are passed in registers rather than via the@@ -29,6 +35,7 @@ SYM_FUNC_START(__efi_rt_asm_wrapper) mov x4, x6 blr x8 + mov sp, x29 ldp x1, x2, [sp, #16] cmp x2, x18 ldp x29, x30, [sp], #32@@ -42,6 +49,10 @@ SYM_FUNC_START(__efi_rt_asm_wrapper) * called with preemption disabled and a separate shadow stack is used * for interrupts. */ - mov x18, x2 +#ifdef CONFIG_SHADOW_CALL_STACK + ldr_l x18, efi_rt_stack_top + ldr x18, [x18, #-16] +#endif + b efi_handle_corrupted_x18 // tail call SYM_FUNC_END(__efi_rt_asm_wrapper)arch/arm64/kernel/efi.c +25
-0@@ -144,3 +144,28 @@ asmlinkage efi_status_t efi_handle_corrupted_x18(efi_status_t s, const char *f)pr_err_ratelimited (FW_BUG "register x18 corrupted by EFI %s\n" , f);return s; } + +DEFINE_SPINLOCK (efi_rt_lock); + +asmlinkage u64 *efi_rt_stack_top __ro_after_init; + +/* required by the EFI spec */ +static_assert (THREAD_SIZE >=SZ_8K ); + +int __init arm64_efi_rt_init (void ) +{ +void *p =__vmalloc_node_range (THREAD_SIZE ,THREAD_ALIGN , +VMALLOC_START ,VMALLOC_END ,GFP_KERNEL , +PAGE_KERNEL ,0 ,NUMA_NO_NODE , +__builtin_return_address (0 )); + +if (!p) { +pr_warn ("Failed to allocate EFI runtime stack\n" ); +clear_bit (EFI_RUNTIME_SERVICES , &efi.flags); +return -ENOMEM ; + } + + efi_rt_stack_top = p +THREAD_SIZE ; +return 0 ; +} +core_initcall (arm64_efi_rt_init);Signature · 1 line
2.35.1
Ard Biesheuvel
maintainerRe: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
Quoted 29 lines · Mark Rutland
Hi Ard,
One drive-by comment below...
Quoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 5 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++
Quoted 8 lines
We'll need to teach the stack unwinder about this, or if we take an exception from the EFI stack, the backtrace will terminate as soon as it hits a frame record on the EFI stack.
In arch/arm64/kernel/stacktrace.c's
arch_stack_walk(), that'll need to be added to the array of stack bounds. Ideally we'd only add that when a thread is making an EFI call.
Thanks, I'll look into that.
Re: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
In reply to Ard BiesheuvelQuoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 6 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-)
Could we have this in Stable please?
Upstream commit: ff7a167961d1b ("arm64: efi: Execute runtime services from a dedicated stack")
Ard, do we need Patch 2 as well, or can this be applied on its own?
Quoted 99 lines
arch/arm64/include/asm/efi.h +3
-0@@ -25,6 +25,7 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md); ({ \efi_virtmap_load (); \__efi_fpsimd_begin (); \ +spin_lock (&efi_rt_lock); \ })#undef arch_efi_call_virt@@ -33,10 +34,12 @@ int efi_set_mapping_permissions(struct mm_struct *mm, efi_memory_desc_t *md);#define arch_efi_call_virt_teardown () \ ({ \ + spin_unlock(&efi_rt_lock); \ __efi_fpsimd_end(); \ efi_virtmap_unload(); \ }) +extern spinlock_t efi_rt_lock;efi_status_t __efi_rt_asm_wrapper (void *,const char *, ...);#define ARCH_EFI_IRQ_FLAGS_MASK (PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT)arch/arm64/kernel/efi-rt-wrapper.S +12
-1@@ -16,6 +16,12 @@ SYM_FUNC_START(__efi_rt_asm_wrapper) */ stp x1, x18, [sp, #16] + ldr_l x16, efi_rt_stack_top + mov sp, x16 +#ifdef CONFIG_SHADOW_CALL_STACK + str x18, [sp, #-16]! +#endif + /* * We are lucky enough that no EFI runtime services take more than * 5 arguments, so all are passed in registers rather than via the@@ -29,6 +35,7 @@ SYM_FUNC_START(__efi_rt_asm_wrapper) mov x4, x6 blr x8 + mov sp, x29 ldp x1, x2, [sp, #16] cmp x2, x18 ldp x29, x30, [sp], #32@@ -42,6 +49,10 @@ SYM_FUNC_START(__efi_rt_asm_wrapper) * called with preemption disabled and a separate shadow stack is used * for interrupts. */ - mov x18, x2 +#ifdef CONFIG_SHADOW_CALL_STACK + ldr_l x18, efi_rt_stack_top + ldr x18, [x18, #-16] +#endif + b efi_handle_corrupted_x18 // tail call SYM_FUNC_END(__efi_rt_asm_wrapper)arch/arm64/kernel/efi.c +25
-0@@ -144,3 +144,28 @@ asmlinkage efi_status_t efi_handle_corrupted_x18(efi_status_t s, const char *f)pr_err_ratelimited (FW_BUG "register x18 corrupted by EFI %s\n" , f);return s; } + +DEFINE_SPINLOCK (efi_rt_lock); + +asmlinkage u64 *efi_rt_stack_top __ro_after_init; + +/* required by the EFI spec */ +static_assert (THREAD_SIZE >=SZ_8K ); + +int __init arm64_efi_rt_init (void ) +{ +void *p =__vmalloc_node_range (THREAD_SIZE ,THREAD_ALIGN , +VMALLOC_START ,VMALLOC_END ,GFP_KERNEL , +PAGE_KERNEL ,0 ,NUMA_NO_NODE , +__builtin_return_address (0 )); + +if (!p) { +pr_warn ("Failed to allocate EFI runtime stack\n" ); +clear_bit (EFI_RUNTIME_SERVICES , &efi.flags); +return -ENOMEM ; + } + + efi_rt_stack_top = p +THREAD_SIZE ; +return 0 ; +} +core_initcall (arm64_efi_rt_init);Signature · 1 line
2.35.1
Signature · 1 line
Lee Jones [李琼斯]
Ard Biesheuvel
maintainerRe: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
Quoted 27 lines · Lee Jones
Quoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 6 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-)
Quoted 6 lines
Could we have this in Stable please?
Upstream commit:
ff7a167961d1b("arm64: efi: Execute runtime services from a dedicated stack")Ard, do we need Patch 2 as well, or can this be applied on its own?
Thanks for the reminder.
Only patch #1 is needed. It should be applied to v5.10 and later.
Re: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
Quoted 30 lines · Ard Biesheuvel
Quoted 29 lines · Lee Jones
Quoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 6 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-)Could we have this in Stable please?
Quoted 8 lines
Quoted 4 lines
Upstream commit:
ff7a167961d1b("arm64: efi: Execute runtime services from a dedicated stack")Ard, do we need Patch 2 as well, or can this be applied on its own?
Thanks for the reminder.
Only patch #1 is needed. It should be applied to v5.10 and later.
Perfect, thanks Ard.
Signature · 1 line
Lee Jones [李琼斯]
Greg KH
maintainerRe: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
Quoted 34 lines · Lee Jones
Quoted 32 lines · Ard Biesheuvel
Quoted 31 lines · Lee Jones
Quoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 6 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-)Could we have this in Stable please?
Upstream commit:
ff7a167961d1b("arm64: efi: Execute runtime services from a dedicated stack")
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
Ard, do we need Patch 2 as well, or can this be applied on its own?
Thanks for the reminder.
Only patch #1 is needed. It should be applied to v5.10 and later.
Perfect, thanks Ard.
Now queued up, thanks.
greg k-h
Mark Rutland
reviewerRe: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
In reply to Ard BiesheuvelQuoted 30 lines · Ard Biesheuvel
Quoted 29 lines · Lee Jones
Quoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 6 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-)Could we have this in Stable please?
Quoted 8 lines
Quoted 4 lines
Upstream commit:
ff7a167961d1b("arm64: efi: Execute runtime services from a dedicated stack")Ard, do we need Patch 2 as well, or can this be applied on its own?
Thanks for the reminder.
Only patch #1 is needed. It should be applied to v5.10 and later.
Hold on, why did this go into mainline when I had an outstanding comment w.r.t. the stack unwinder?
From your last reply to me there I was expecting a respin with that fixed.
Mark.
Ard Biesheuvel
maintainerRe: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
Quoted 37 lines · Mark Rutland
Quoted 35 lines · Ard Biesheuvel
Quoted 33 lines · Lee Jones
Quoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 6 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-)Could we have this in Stable please?
Upstream commit:
ff7a167961d1b("arm64: efi: Execute runtime services from a dedicated stack")Ard, do we need Patch 2 as well, or can this be applied on its own?
Quoted 9 lines
Quoted 3 lines
Thanks for the reminder.
Only patch #1 is needed. It should be applied to v5.10 and later.
Hold on, why did this go into mainline when I had an outstanding comment w.r.t. the stack unwinder?
From your last reply to me there I was expecting a respin with that fixed.
Apologies for the confusion.
I have a patch for this queued up, but AIUI, that cannot be merged all the way back to v5.10, so these need to remain separate changes in any case.
Mark Rutland
reviewerRe: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
Quoted 48 lines · Ard Biesheuvel
Quoted 37 lines · Mark Rutland
Quoted 35 lines · Ard Biesheuvel
Quoted 33 lines · Lee Jones
Quoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 6 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-)Could we have this in Stable please?
Upstream commit:
ff7a167961d1b("arm64: efi: Execute runtime services from a dedicated stack")Ard, do we need Patch 2 as well, or can this be applied on its own?
Quoted 9 lines
Quoted 3 lines
Thanks for the reminder.
Only patch #1 is needed. It should be applied to v5.10 and later.
Hold on, why did this go into mainline when I had an outstanding comment w.r.t. the stack unwinder?
From your last reply to me there I was expecting a respin with that fixed.
Quoted 7 lines
Apologies for the confusion.
I have a patch for this queued up, but AIUI, that cannot be merged all the way back to v5.10, so these need to remain separate changes in any case.
Ah, ok, thanks for the pointer!
I'm a little uneasy here, still.
By backporting this we're also backporting the new breakage of the stack unwinder, and the minimal change for backports would be to add the lock and not the new stack (which was added for additinoal robustness, not to fix the bug the lock fixes).
I do appreciate that the additional stack is likely more useful than the occasional diagnostic output from the kernel, but it does seem like this has traded off one bug for another, and I'm just a little annoyed because I pointed that out before the first pull request was made.
I do know that this isn't malicious, and I'm not trying to start a fight, but now we have to consider whether we want/need to backport a stack unwinder fix to account for this, and we hadn't had that discussion before.
Thanks,
Mark.
Ard Biesheuvel
maintainerRe: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
Quoted 67 lines · Mark Rutland
Quoted 48 lines · Ard Biesheuvel
Quoted 37 lines · Mark Rutland
Quoted 35 lines · Ard Biesheuvel
Quoted 33 lines · Lee Jones
Quoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 6 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-)Could we have this in Stable please?
Upstream commit:
ff7a167961d1b("arm64: efi: Execute runtime services from a dedicated stack")Ard, do we need Patch 2 as well, or can this be applied on its own?
Quoted 9 lines
Quoted 3 lines
Thanks for the reminder.
Only patch #1 is needed. It should be applied to v5.10 and later.
Hold on, why did this go into mainline when I had an outstanding comment w.r.t. the stack unwinder?
From your last reply to me there I was expecting a respin with that fixed.
Quoted 7 lines
Apologies for the confusion.
I have a patch for this queued up, but AIUI, that cannot be merged all the way back to v5.10, so these need to remain separate changes in any case.
Ah, ok, thanks for the pointer!
I'm a little uneasy here, still.
By backporting this we're also backporting the new breakage of the stack unwinder, and the minimal change for backports would be to add the lock and not the new stack (which was added for additinoal robustness, not to fix the bug the lock fixes).
Quoted 9 lines
I do appreciate that the additional stack is likely more useful than the occasional diagnostic output from the kernel, but it does seem like this has traded off one bug for another, and I'm just a little annoyed because I pointed that out before the first pull request was made.
I do know that this isn't malicious, and I'm not trying to start a fight, but now we have to consider whether we want/need to backport a stack unwinder fix to account for this, and we hadn't had that discussion before.
In that case, let's drop these backports for the time being, and collaborate on a solution that works for all of us.
Greg, could you please drop these again? Thanks.
Re: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
Quoted 78 lines · Ard Biesheuvel
Quoted 67 lines · Mark Rutland
Quoted 48 lines · Ard Biesheuvel
Quoted 37 lines · Mark Rutland
Quoted 35 lines · Ard Biesheuvel
Quoted 33 lines · Lee Jones
Quoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 6 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-)Could we have this in Stable please?
Upstream commit:
ff7a167961d1b("arm64: efi: Execute runtime services from a dedicated stack")Ard, do we need Patch 2 as well, or can this be applied on its own?
Quoted 9 lines
Quoted 3 lines
Thanks for the reminder.
Only patch #1 is needed. It should be applied to v5.10 and later.
Hold on, why did this go into mainline when I had an outstanding comment w.r.t. the stack unwinder?
From your last reply to me there I was expecting a respin with that fixed.
Quoted 7 lines
Apologies for the confusion.
I have a patch for this queued up, but AIUI, that cannot be merged all the way back to v5.10, so these need to remain separate changes in any case.
Ah, ok, thanks for the pointer!
I'm a little uneasy here, still.
By backporting this we're also backporting the new breakage of the stack unwinder, and the minimal change for backports would be to add the lock and not the new stack (which was added for additinoal robustness, not to fix the bug the lock fixes).
Quoted 9 lines
I do appreciate that the additional stack is likely more useful than the occasional diagnostic output from the kernel, but it does seem like this has traded off one bug for another, and I'm just a little annoyed because I pointed that out before the first pull request was made.
I do know that this isn't malicious, and I'm not trying to start a fight, but now we have to consider whether we want/need to backport a stack unwinder fix to account for this, and we hadn't had that discussion before.
Quoted 4 lines
In that case, let's drop these backports for the time being, and collaborate on a solution that works for all of us.
Greg, could you please drop these again? Thanks.
Dropped now from all queues, thanks.
greg k-h
Re: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
Quoted 79 lines · Greg KH
Quoted 78 lines · Ard Biesheuvel
Quoted 76 lines · Mark Rutland
Quoted 48 lines · Ard Biesheuvel
Quoted 37 lines · Mark Rutland
Quoted 35 lines · Ard Biesheuvel
Quoted 33 lines · Lee Jones
Quoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 6 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-)Could we have this in Stable please?
Upstream commit:
ff7a167961d1b("arm64: efi: Execute runtime services from a dedicated stack")Ard, do we need Patch 2 as well, or can this be applied on its own?
Quoted 9 lines
Quoted 3 lines
Thanks for the reminder.
Only patch #1 is needed. It should be applied to v5.10 and later.
Hold on, why did this go into mainline when I had an outstanding comment w.r.t. the stack unwinder?
From your last reply to me there I was expecting a respin with that fixed.
Quoted 7 lines
Apologies for the confusion.
I have a patch for this queued up, but AIUI, that cannot be merged all the way back to v5.10, so these need to remain separate changes in any case.
Ah, ok, thanks for the pointer!
I'm a little uneasy here, still.
By backporting this we're also backporting the new breakage of the stack unwinder, and the minimal change for backports would be to add the lock and not the new stack (which was added for additinoal robustness, not to fix the bug the lock fixes).
I do appreciate that the additional stack is likely more useful than the occasional diagnostic output from the kernel, but it does seem like this has traded off one bug for another, and I'm just a little annoyed because I pointed that out before the first pull request was made.
I do know that this isn't malicious, and I'm not trying to start a fight, but now we have to consider whether we want/need to backport a stack unwinder fix to account for this, and we hadn't had that discussion before.
Quoted 6 lines
Quoted 4 lines
In that case, let's drop these backports for the time being, and collaborate on a solution that works for all of us.
Greg, could you please drop these again? Thanks.
Dropped now from all queues, thanks.
Now in Mainline as:
18bba1843fc7f efi: rt-wrapper: Add missing include ff7a167961d1b arm64: efi: Execute runtime services from a dedicated stack
Would you be kind enough to re-collect them please?
Thank you.
Signature · 1 line
Lee Jones [李琼斯]
Re: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
Quoted 86 lines · Lee Jones
Quoted 84 lines · Greg KH
Quoted 82 lines · Ard Biesheuvel
Quoted 67 lines · Mark Rutland
Quoted 48 lines · Ard Biesheuvel
Quoted 37 lines · Mark Rutland
Quoted 35 lines · Ard Biesheuvel
Quoted 33 lines · Lee Jones
Quoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 6 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-)Could we have this in Stable please?
Upstream commit:
ff7a167961d1b("arm64: efi: Execute runtime services from a dedicated stack")Ard, do we need Patch 2 as well, or can this be applied on its own?
Quoted 9 lines
Quoted 3 lines
Thanks for the reminder.
Only patch #1 is needed. It should be applied to v5.10 and later.
Hold on, why did this go into mainline when I had an outstanding comment w.r.t. the stack unwinder?
From your last reply to me there I was expecting a respin with that fixed.
Quoted 7 lines
Apologies for the confusion.
I have a patch for this queued up, but AIUI, that cannot be merged all the way back to v5.10, so these need to remain separate changes in any case.
Ah, ok, thanks for the pointer!
I'm a little uneasy here, still.
By backporting this we're also backporting the new breakage of the stack unwinder, and the minimal change for backports would be to add the lock and not the new stack (which was added for additinoal robustness, not to fix the bug the lock fixes).
Quoted 9 lines
I do appreciate that the additional stack is likely more useful than the occasional diagnostic output from the kernel, but it does seem like this has traded off one bug for another, and I'm just a little annoyed because I pointed that out before the first pull request was made.
I do know that this isn't malicious, and I'm not trying to start a fight, but now we have to consider whether we want/need to backport a stack unwinder fix to account for this, and we hadn't had that discussion before.
In that case, let's drop these backports for the time being, and collaborate on a solution that works for all of us.
Greg, could you please drop these again? Thanks.
Quoted 8 lines
Quoted 1 line
Dropped now from all queues, thanks.
Now in Mainline as:
18bba1843fc7fefi: rt-wrapper: Add missing includeff7a167961d1barm64: efi: Execute runtime services from a dedicated stackWould you be kind enough to re-collect them please?
Now queued up for 5.10.y and newer.
greg k-h
Re: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
In reply to Lee JonesDear Linux Kernel Developers,
I have reason to believe that the commit 4012603cbd469223f225637d265a233f034c567a, which was backported to the linux-5.10 branch, is introducing a bug that leads to a kernel crash.
Environment Details:
Kernel Version: linux-5.10.234
Architecture: aarch64
Kernel Configuration: Available at
https://syzkaller.appspot.com/bug?extid=75dc11b3aa0369757b7c
QEMU Version: 8.2.2
QEMU Launch Command:
qemu-system-aarch64 \
-m 4G \
-smp 4,sockets=1,cores=4,threads=1 \
-cpu cortex-a57 \
-machine virt,accel=tcg \
-kernel /home/user/lvc/linux-stable/arch/arm64/boot/Image \
-append "console=ttyS0 root=/dev/vda2 earlyprintk=serial
net.ifnames=0 rw debug loglevel=8" \
-drive
file=/home/user/lvc/image/disk.raw,format=raw,if=virtio,index=1 \
-bios /usr/share/AAVMF/AAVMF_CODE.fd \
-netdev user,id=net0,hostfwd=tcp::10022-:22 \
-device virtio-net-device,netdev=net0 \
-nographicSteps to Reproduce:
mount -t sysfs sysfs /sys
mount -t proc proc /proc
mount -t efivarfs efivarfs /sys/firmware/efi/efivars tools/testing/selftests/efivarfs/efivarfs.sh
Crash log:
[ 101.403235][ T38] Unable to handle kernel paging request at virtual address ffffa00023b20000 [ 101.403905][ T38] Mem abort info: [ 101.404159][ T38] ESR = 0x96000047 [ 101.404448][ T38] EC = 0x25: DABT (current EL), IL = 32 bits [ 101.404748][ T38] SET = 0, FnV = 0 [ 101.404988][ T38] EA = 0, S1PTW = 0 [ 101.405233][ T38] Data abort info: [ 101.405469][ T38] ISV = 0, ISS = 0x00000047 [ 101.405721][ T38] CM = 0, WnR = 1 [ 101.406070][ T38] swapper pgtable: 4k pages, 48-bit VAs, pgdp=0000000103336000 [ 101.406415][ T38] [ffffa00023b20000] pgd=000000013ffff003, p4d=000000013ffff003, pud=000000013fffe003, pmd=000000013fff9003, pte=0000000000000000 [ 101.407997][ T38] Internal error: Oops: 0000000096000047 [#1] PREEMPT SMP [ 101.408446][ T38] Modules linked in: [ 101.409010][ T38] CPU: 1 PID: 38 Comm: kworker/u8:2 Not tainted 5.10.234 #61 [ 101.409376][ T38] Hardware name: QEMU QEMU Virtual Machine, BIOS 2024.02-2ubuntu0.1 10/25/2024 [ 101.410689][ T38] Workqueue: efi_rts_wq efi_call_rts [ 101.411219][ T38] pstate: 000003c5 (nzcv DAIF -PAN -UAO -TCO BTYPE=--) [ 101.411574][ T38] pc : el1_sync+0xc/0x140 [ 101.411930][ T38] lr : 0x0 [ 101.412132][ T38] sp : ffffa00023b1ffd0 [ 101.412363][ T38] x29: 0000000000000000 x28: ffff0000cc741a80 [ 101.412761][ T38] x27: 0000000000000001 x26: 0000000000e800e8 [ 101.413117][ T38] x25: 0000000000800080 x24: ffff940004765298 [ 101.413465][ T38] x23: 00000000100003c5 x22: ffffa00018c95600 [ 101.413809][ T38] x21: ffffa0001923a980 x20: ffffa00018d30380 [ 101.414170][ T38] x19: ffffa0001bab8008 x18: 1fffe000198e8491 [ 101.414515][ T38] x17: 0000000000000000 x16: ffffa000102a26c0 [ 101.414882][ T38] x15: 0000000000000001 x14: ffff0000ccf34400 [ 101.415277][ T38] x13: 000000000000003c x12: ffff0000ccf34000 [ 101.415656][ T38] x11: 0000000000000018 x10: 0000000000000054 [ 101.416072][ T38] x9 : 4fc79849210be57c x8 : 11d293ca8be4df61 [ 101.416446][ T38] x7 : 0000000041b58ab3 x6 : ffff94000476522a [ 101.416820][ T38] x5 : 0000002200000000 x4 : 0000000200000000 [ 101.417190][ T38] x3 : 1fffe000198e8352 x2 : ffffa0001923a820 [ 101.417560][ T38] x1 : ffff0000cc741a80 x0 : 0000000000000000 [ 101.418109][ T38] Call trace: [ 101.418601][ T38] Code: d503201f a90007e0 a9010fe2 a90217e4 (a9031fe6) [ 101.419579][ T38] ---[ end trace 61316cddfdbbcb95 ]--- [ 103.623221][ T38] Kernel panic - not syncing: Oops: Fatal exception [ 103.623723][ T38] SMP: stopping secondary CPUs [ 105.221708][ T38] SMP: failed to stop secondary CPUs 0-3 [ 105.222306][ T38] Kernel Offset: disabled [ 105.222711][ T38] CPU features: 0x28240022,61002082 [ 105.222969][ T38] Memory Limit: none
I identified this commit as the potential cause of the crash using git bisect. The issue is reproducible with the above setup and configuration. If you need more details or logs, I am more than willing to provide them. Thank you for your attention to this matter.
Best regards,
Alexey Nepomnyashih
Mark Rutland
reviewerRe: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
In reply to Ard BiesheuvelQuoted 73 lines · Ard Biesheuvel
Quoted 72 lines · Mark Rutland
Quoted 48 lines · Ard Biesheuvel
Quoted 37 lines · Mark Rutland
Quoted 35 lines · Ard Biesheuvel
Quoted 33 lines · Lee Jones
Quoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 6 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-)Could we have this in Stable please?
Upstream commit:
ff7a167961d1b("arm64: efi: Execute runtime services from a dedicated stack")Ard, do we need Patch 2 as well, or can this be applied on its own?
Quoted 9 lines
Quoted 3 lines
Thanks for the reminder.
Only patch #1 is needed. It should be applied to v5.10 and later.
Hold on, why did this go into mainline when I had an outstanding comment w.r.t. the stack unwinder?
From your last reply to me there I was expecting a respin with that fixed.
Quoted 7 lines
Apologies for the confusion.
I have a patch for this queued up, but AIUI, that cannot be merged all the way back to v5.10, so these need to remain separate changes in any case.
Ah, ok, thanks for the pointer!
I'm a little uneasy here, still.
By backporting this we're also backporting the new breakage of the stack unwinder, and the minimal change for backports would be to add the lock and not the new stack (which was added for additinoal robustness, not to fix the bug the lock fixes).
I do appreciate that the additional stack is likely more useful than the occasional diagnostic output from the kernel, but it does seem like this has traded off one bug for another, and I'm just a little annoyed because I pointed that out before the first pull request was made.
Quoted 6 lines
Quoted 3 lines
I do know that this isn't malicious, and I'm not trying to start a fight, but now we have to consider whether we want/need to backport a stack unwinder fix to account for this, and we hadn't had that discussion before.
In that case, let's drop these backports for the time being, and collaborate on a solution that works for all of us.
Thanks!
IIUC our options here are:
1) Create a cut-down patch for stable that just adds the new lock but leaves out the new stack.
I may be missing a reason why that's insufficient or painful.
2) Backport this *but* also backport the follow-up fixes from your other series:
https://lore.kernel.org/r/[email protected]
Above you mentioned something about v5.10, was that just to say that some manual backporting was required, or that there was a structural problem that would require more invasive changes / prerequisites?
3) Something else?
My preference would be (1), but if we are encountering issue with stack size on stable kernels, then I'd be happy to help with manual backporting effort for (2), as long as we backported all the relevant bits in one go.
Does that make sense, and does that sound reasonable to you?
Thanks,
Mark.
Ard Biesheuvel
maintainerRe: [PATCH 1/2] arm64: efi: Execute runtime services from a dedicated stack
Quoted 82 lines · Mark Rutland
Quoted 73 lines · Ard Biesheuvel
Quoted 72 lines · Mark Rutland
Quoted 48 lines · Ard Biesheuvel
Quoted 37 lines · Mark Rutland
Quoted 35 lines · Ard Biesheuvel
Quoted 33 lines · Lee Jones
Quoted 17 lines · Ard Biesheuvel
With the introduction of PRMT in the ACPI subsystem, the EFI rts workqueue is no longer the only caller of
efi_call_virt_pointer()in the kernel. This means the EFI runtime services lock is no longer sufficient to manage concurrent calls into firmware, but also that firmware calls may occur that are not marshalled via the workqueue mechanism, but originate directly from the caller context.For added robustness, and to ensure that the runtime services have 8 KiB of stack space available as per the EFI spec, introduce a spinlock protected EFI runtime stack of 8 KiB, where the spinlock also ensures serialization between the EFI rts workqueue (which itself serializes EFI runtime calls) and other callers of
efi_call_virt_pointer().While at it, use the stack pivot to avoid reloading the shadow call stack pointer from the ordinary stack, as doing so could produce a gadget to defeat it.
Quoted 6 lines
Signed-off-by Ard Biesheuvel <[email protected]>--- arch/arm64/include/asm/efi.h | 3 +++ arch/arm64/kernel/efi-rt-wrapper.S | 13 +++++++++- arch/arm64/kernel/efi.c | 25 ++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-)Could we have this in Stable please?
Upstream commit:
ff7a167961d1b("arm64: efi: Execute runtime services from a dedicated stack")Ard, do we need Patch 2 as well, or can this be applied on its own?
Quoted 9 lines
Quoted 3 lines
Thanks for the reminder.
Only patch #1 is needed. It should be applied to v5.10 and later.
Hold on, why did this go into mainline when I had an outstanding comment w.r.t. the stack unwinder?
From your last reply to me there I was expecting a respin with that fixed.
Quoted 7 lines
Apologies for the confusion.
I have a patch for this queued up, but AIUI, that cannot be merged all the way back to v5.10, so these need to remain separate changes in any case.
Ah, ok, thanks for the pointer!
I'm a little uneasy here, still.
By backporting this we're also backporting the new breakage of the stack unwinder, and the minimal change for backports would be to add the lock and not the new stack (which was added for additinoal robustness, not to fix the bug the lock fixes).
I do appreciate that the additional stack is likely more useful than the occasional diagnostic output from the kernel, but it does seem like this has traded off one bug for another, and I'm just a little annoyed because I pointed that out before the first pull request was made.
Quoted 6 lines
Quoted 3 lines
I do know that this isn't malicious, and I'm not trying to start a fight, but now we have to consider whether we want/need to backport a stack unwinder fix to account for this, and we hadn't had that discussion before.
In that case, let's drop these backports for the time being, and collaborate on a solution that works for all of us.
Quoted 7 lines
Thanks!
IIUC our options here are:
1) Create a cut-down patch for stable that just adds the new lock but leaves out the new stack.
The lock by itself does nothing useful - it is only needed because there is now a single stack that is shared by all callers of EFI runtime code. The existing ones are serialized already, but ACPI may invoke efi_call_virt_pointer() as well, which is why the additional spinlock is required for completeness. However, that ACPI feature is relatively recent (and I am not aware of any arm64 systems that actually implement it in their firmware)
Quoted 2 lines
I may be missing a reason why that's insufficient or painful.
The reason for the backport is that it also allows us to stash the shadow call stack pointer elsewhere, as storing it on the normal stack as we do currently defeats the purpose.
Quoted 7 lines
2) Backport this *but* also backport the follow-up fixes from your other series:
https://lore.kernel.org/r/[email protected]Above you mentioned something about v5.10, was that just to say that some manual backporting was required, or that there was a structural problem that would require more invasive changes / prerequisites?
This is when the shadow call stack was introduced. Apologies for not making this clearer in the commit log.
Quoted 8 lines
3) Something else?
My preference would be (1), but if we are encountering issue with stack size on stable kernels, then I'd be happy to help with manual backporting effort for (2), as long as we backported all the relevant bits in one go.
Does that make sense, and does that sound reasonable to you?
What I had in mind (but did not communicate clearly) is to backport the patch that introduces the new stack to v5.10 and later, and to backport the patch that adds the stacktrace declaration as well, but separately (and probably not all the way back to v5.10)
Ard Biesheuvel
maintainerPATCH 2/2 arm64: efi: Recover from synchronous exceptions occurring in firmware
In reply to Ard BiesheuvelUnlike 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.
--- arch/arm64/include/asm/efi.h | 8 +++++ arch/arm64/kernel/efi-rt-wrapper.S | 31 ++++++++++++++++---- arch/arm64/kernel/efi.c | 22 ++++++++++++++ arch/arm64/mm/fault.c | 4 +++ drivers/firmware/efi/runtime-wrappers.c | 1 + 5 files changed, 61 insertions(+), 5 deletions(-)
arch/arm64/include/asm/efi.h +8 -0
@@ -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);
arch/arm64/kernel/efi-rt-wrapper.S +26 -5
@@ -6,7 +6,7 @@ #include <linux/linkage.h> SYM_FUNC_START(__efi_rt_asm_wrapper) - stp x29, x30, [sp, #-32]! + stp x29, x30, [sp, #-112]! mov x29, sp /*
@@ -16,11 +16,20 @@ SYM_FUNC_START(__efi_rt_asm_wrapper) */ stp x1, x18, [sp, #16] + /* + * Preserve all callee saved registers and record the stack pointer + * value in a per-CPU variable so we can recover from synchronous + * exceptions occurring while running 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
@@ -38,7 +47,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:
@@ -56,3 +65,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)
arch/arm64/kernel/efi.c +22 -0
@@ -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; +} +/* required by the EFI spec */ static_assert (THREAD_SIZE >=SZ_8K );
arch/arm64/mm/fault.c +4 -0
@@ -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>
@@ -391,6 +392,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); }
drivers/firmware/efi/runtime-wrappers.c +1 -0
@@ -83,6 +83,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; \
Signature · 1 line
2.35.1