From: Mark Rutland mark.rutland@arm.com
mainline inclusion from mainline-v6.2-rc1 commit 0bb1fbffc631064db567ccaeb9ed6b6df6342b66 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8YLWW
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
------------------------------------------------------
Alexander noted that KFENCE only expects to handle faults from invalid page table entries (i.e. translation faults), but arm64's fault handling logic will call kfence_handle_page_fault() for other types of faults, including alignment faults caused by unaligned atomics. This has the unfortunate property of causing those other faults to be reported as "KFENCE: use-after-free", which is misleading and hinders debugging.
Fix this by only forwarding unhandled translation faults to the KFENCE code, similar to what x86 does already.
Alexander has verified that this passes all the tests in the KFENCE test suite and avoids bogus reports on misaligned atomics.
Link: https://lore.kernel.org/all/20221102081620.1465154-1-zhongbaisong@huawei.com... Fixes: 840b23986344 ("arm64, kfence: enable KFENCE for ARM64") Signed-off-by: Mark Rutland mark.rutland@arm.com Reviewed-by: Alexander Potapenko glider@google.com Tested-by: Alexander Potapenko glider@google.com Cc: Catalin Marinas catalin.marinas@arm.com Cc: Marco Elver elver@google.com Cc: Will Deacon will@kernel.org Link: https://lore.kernel.org/r/20221114104411.2853040-1-mark.rutland@arm.com Signed-off-by: Will Deacon will@kernel.org Signed-off-by: Nanyong Sun sunnanyong@huawei.com --- arch/arm64/mm/fault.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 9bd10909861a..629b55672eb8 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -299,6 +299,11 @@ static void die_kernel_fault(const char *msg, unsigned long addr, do_exit(SIGKILL); }
+static bool is_translation_fault(unsigned long esr) +{ + return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_FAULT; +} + static void __do_kernel_fault(unsigned long addr, unsigned int esr, struct pt_regs *regs) { @@ -325,7 +330,8 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr, } else if (addr < PAGE_SIZE) { msg = "NULL pointer dereference"; } else { - if (kfence_handle_page_fault(addr, esr & ESR_ELx_WNR, regs)) + if (is_translation_fault(esr) && + kfence_handle_page_fault(addr, esr & ESR_ELx_WNR, regs)) return;
msg = "paging request";