From: Wang Kefeng Date: Wed, 22 Sep 2021 13:56:32 +0000 (+0100) Subject: ARM: 9131/1: mm: Fix PXN process with LPAE feature X-Git-Tag: v6.1-rc5~2761^2^3~11 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=abc25bbcb55c08183d30ee79a308aeef16b62dcb;p=platform%2Fkernel%2Flinux-starfive.git ARM: 9131/1: mm: Fix PXN process with LPAE feature When user code execution with privilege mode, it will lead to infinite loop in the page fault handler if ARM_LPAE enabled, The issue could be reproduced with "echo EXEC_USERSPACE > /sys/kernel/debug/provoke-crash/DIRECT" As Permission fault shows in ARM spec, IFSR format when using the Short-descriptor translation table format Permission fault: 01101 First level 01111 Second level IFSR format when using the Long-descriptor translation table format Permission fault: 0011LL LL bits indicate levelb. Add is_permission_fault() function to check permission fault and die if permission fault occurred under instruction fault in do_page_fault(). Fixes: 1d4d37159d01 ("ARM: 8235/1: Support for the PXN CPU feature on ARMv7") Signed-off-by: Kefeng Wang Signed-off-by: Russell King (Oracle) --- diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 82bcfe5..bc8779d 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -194,6 +194,19 @@ void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs) #define VM_FAULT_BADMAP 0x010000 #define VM_FAULT_BADACCESS 0x020000 +static inline bool is_permission_fault(unsigned int fsr) +{ + int fs = fsr_fs(fsr); +#ifdef CONFIG_ARM_LPAE + if ((fs & FS_PERM_NOLL_MASK) == FS_PERM_NOLL) + return true; +#else + if (fs == FS_L1_PERM || fs == FS_L2_PERM) + return true; +#endif + return false; +} + static vm_fault_t __kprobes __do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int flags, unsigned long vma_flags, struct pt_regs *regs) @@ -253,9 +266,14 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) vm_flags = VM_WRITE; } - if (fsr & FSR_LNX_PF) + if (fsr & FSR_LNX_PF) { vm_flags = VM_EXEC; + if (is_permission_fault(fsr) && !user_mode(regs)) + die_kernel_fault("execution of memory", + mm, addr, fsr, regs); + } + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); /* diff --git a/arch/arm/mm/fault.h b/arch/arm/mm/fault.h index 9ecc209..83b5ab3 100644 --- a/arch/arm/mm/fault.h +++ b/arch/arm/mm/fault.h @@ -14,6 +14,8 @@ #ifdef CONFIG_ARM_LPAE #define FSR_FS_AEA 17 +#define FS_PERM_NOLL 0xC +#define FS_PERM_NOLL_MASK 0x3C static inline int fsr_fs(unsigned int fsr) { @@ -21,6 +23,8 @@ static inline int fsr_fs(unsigned int fsr) } #else #define FSR_FS_AEA 22 +#define FS_L1_PERM 0xD +#define FS_L2_PERM 0xF static inline int fsr_fs(unsigned int fsr) {