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: 1d4d37159d
("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>
This commit is contained in:
Родитель
2e707106fa
Коммит
abc25bbcb5
|
@ -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_BADMAP 0x010000
|
||||||
#define VM_FAULT_BADACCESS 0x020000
|
#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
|
static vm_fault_t __kprobes
|
||||||
__do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int flags,
|
__do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int flags,
|
||||||
unsigned long vma_flags, struct pt_regs *regs)
|
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;
|
vm_flags = VM_WRITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fsr & FSR_LNX_PF)
|
if (fsr & FSR_LNX_PF) {
|
||||||
vm_flags = VM_EXEC;
|
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);
|
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
#ifdef CONFIG_ARM_LPAE
|
#ifdef CONFIG_ARM_LPAE
|
||||||
#define FSR_FS_AEA 17
|
#define FSR_FS_AEA 17
|
||||||
|
#define FS_PERM_NOLL 0xC
|
||||||
|
#define FS_PERM_NOLL_MASK 0x3C
|
||||||
|
|
||||||
static inline int fsr_fs(unsigned int fsr)
|
static inline int fsr_fs(unsigned int fsr)
|
||||||
{
|
{
|
||||||
|
@ -21,6 +23,8 @@ static inline int fsr_fs(unsigned int fsr)
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define FSR_FS_AEA 22
|
#define FSR_FS_AEA 22
|
||||||
|
#define FS_L1_PERM 0xD
|
||||||
|
#define FS_L2_PERM 0xF
|
||||||
|
|
||||||
static inline int fsr_fs(unsigned int fsr)
|
static inline int fsr_fs(unsigned int fsr)
|
||||||
{
|
{
|
||||||
|
|
Загрузка…
Ссылка в новой задаче