Merge tag 'efi-fixes-for-v6.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi

Pull EFI fixes from Ard Biesheuvel:

 - A pair of tweaks to the EFI random seed code so that externally
   provided version of this config table are handled more robustly

 - Another fix for the v6.0 EFI variable refactor that turned out to
   break Apple machines which don't provide QueryVariableInfo()

 - Add some guard rails to the EFI runtime service call wrapper so we
   can recover from synchronous exceptions caused by firmware

* tag 'efi-fixes-for-v6.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi:
  arm64: efi: Recover from synchronous exceptions occurring in firmware
  efi: efivars: Fix variable writes with unsupported query_variable_store()
  efi: random: Use 'ACPI reclaim' memory for random seed
  efi: random: reduce seed size to 32 bytes
  efi/tpm: Pass correct address to memblock_reserve
This commit is contained in:
Linus Torvalds
2022-11-04 14:37:25 -07:00
9 changed files with 98 additions and 54 deletions

View File

@@ -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);

View File

@@ -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,6 +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]
adr_this_cpu x8, __efi_rt_asm_recover_sp, x9
str x29, [x8]
/*
* We are lucky enough that no EFI runtime services take more than
* 5 arguments, so all are passed in registers rather than via the
@@ -31,7 +45,7 @@ SYM_FUNC_START(__efi_rt_asm_wrapper)
ldp x1, x2, [sp, #16]
cmp x2, x18
ldp x29, x30, [sp], #32
ldp x29, x30, [sp], #112
b.ne 0f
ret
0:
@@ -45,3 +59,18 @@ SYM_FUNC_START(__efi_rt_asm_wrapper)
mov x18, x2
b efi_handle_corrupted_x18 // tail call
SYM_FUNC_END(__efi_rt_asm_wrapper)
SYM_FUNC_START(__efi_rt_asm_recover)
ldr_this_cpu x8, __efi_rt_asm_recover_sp, x9
mov sp, x8
ldp x0, x18, [sp, #16]
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
b efi_handle_runtime_exception
SYM_FUNC_END(__efi_rt_asm_recover)

View File

@@ -9,6 +9,7 @@
#include <linux/efi.h>
#include <linux/init.h>
#include <linux/percpu.h>
#include <asm/efi.h>
@@ -128,3 +129,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;
}
asmlinkage DEFINE_PER_CPU(u64, __efi_rt_asm_recover_sp);
asmlinkage efi_status_t __efi_rt_asm_recover(void);
asmlinkage efi_status_t efi_handle_runtime_exception(const char *f)
{
pr_err(FW_BUG "Synchronous exception occurred in EFI runtime service %s()\n", f);
clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
return EFI_ABORTED;
}
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);
dump_stack();
regs->pc = (u64)__efi_rt_asm_recover;
return true;
}

View File

@@ -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);
}