[RFC PATCH] arm64: mm: recover from kernel-mode SEA via exception table
From: Nguyen Ngoc Thang <hidden>
Date: 2026-09-12 13:56:04
Also in:
lkml
Subsystem:
arm64 port (aarch64 architecture), the rest · Maintainers:
Catalin Marinas, Will Deacon, Linus Torvalds
do_sea() unconditionally calls die() for a synchronous external abort taken at EL1, without ever consulting the exception table. This is inconsistent with __do_kernel_fault(), which does check fixup_exception() before giving up. A SEA at EL1 is reachable and recoverable: futex's LL/SC atomic ops (__llsc_futex_cmpxchg/__llsc_futex_atomic_*) carry _ASM_EXTABLE_UACCESS_ERR entries, but if the user address is mapped to Device memory (e.g. a PCI BAR obtained via sysfs "resourceN" and mmap'd MAP_FIXED), the LDXR/STLXR pair faults with a SEA instead of a translation fault, and the extable fixup is never reached, so the kernel oopses instead of returning -EFAULT to userspace. Check fixup_exception() for kernel-mode SEAs before dying, mirroring __do_kernel_fault(). No taint is added on the recovered path since this is a userspace-triggerable condition, not a hardware failure; a ratelimited warning keeps a trace of it. Reported-by: syzbot+635d160c0d4133481520@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?extid=635d160c0d4133481520 Signed-off-by: Nguyen Ngoc Thang <redacted> --- Sent as RFC: verified by code inspection (ESR/DFSC decode matches the extable-carrying LL/SC futex path) but not yet reproduced under QEMU on my end; would appreciate a look before I chase the aarch64 repro further. arch/arm64/mm/fault.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 0b52557652be..fe5a5c5bbc27 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c@@ -878,6 +878,18 @@ static int do_sea(unsigned long far, unsigned long esr, struct pt_regs *regs) return 0; } + /* + * A SEA at EL1 can happen from uaccess helpers (e.g. LDXR/STLXR + * on a user page mapped as Device memory, as in the futex ops) + * that carry an extable fixup. Let it return -EFAULT instead of + * oopsing the kernel. + */ + if (!user_mode(regs) && fixup_exception(regs, esr)) { + pr_warn_ratelimited("Recovered SEA at kernel uaccess, addr=%#lx, esr=%#lx\n", + far, esr); + return 0; + } + if (esr & ESR_ELx_FnV) { siaddr = 0; } else {
--
2.43.0