Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <wangkefeng.wang@huawei.com>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>

authored by

Wang Kefeng and committed by
Russell King (Oracle)
abc25bbc 2e707106

+23 -1
+19 -1
arch/arm/mm/fault.c
··· 194 194 #define VM_FAULT_BADMAP 0x010000 195 195 #define VM_FAULT_BADACCESS 0x020000 196 196 197 + static inline bool is_permission_fault(unsigned int fsr) 198 + { 199 + int fs = fsr_fs(fsr); 200 + #ifdef CONFIG_ARM_LPAE 201 + if ((fs & FS_PERM_NOLL_MASK) == FS_PERM_NOLL) 202 + return true; 203 + #else 204 + if (fs == FS_L1_PERM || fs == FS_L2_PERM) 205 + return true; 206 + #endif 207 + return false; 208 + } 209 + 197 210 static vm_fault_t __kprobes 198 211 __do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int flags, 199 212 unsigned long vma_flags, struct pt_regs *regs) ··· 266 253 vm_flags = VM_WRITE; 267 254 } 268 255 269 - if (fsr & FSR_LNX_PF) 256 + if (fsr & FSR_LNX_PF) { 270 257 vm_flags = VM_EXEC; 258 + 259 + if (is_permission_fault(fsr) && !user_mode(regs)) 260 + die_kernel_fault("execution of memory", 261 + mm, addr, fsr, regs); 262 + } 271 263 272 264 perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); 273 265
+4
arch/arm/mm/fault.h
··· 14 14 15 15 #ifdef CONFIG_ARM_LPAE 16 16 #define FSR_FS_AEA 17 17 + #define FS_PERM_NOLL 0xC 18 + #define FS_PERM_NOLL_MASK 0x3C 17 19 18 20 static inline int fsr_fs(unsigned int fsr) 19 21 { ··· 23 21 } 24 22 #else 25 23 #define FSR_FS_AEA 22 24 + #define FS_L1_PERM 0xD 25 + #define FS_L2_PERM 0xF 26 26 27 27 static inline int fsr_fs(unsigned int fsr) 28 28 {