diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-09-20 08:18:47 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-09-20 11:53:40 -0400 |
commit | df297bf6c7933e7b021cdc1bf3f9e319ea3a7e9c (patch) | |
tree | 9ef6353c4100c83176c4e7b5ef3933dc342f91df /arch/arm/mm | |
parent | d374bf14a5ff18133bd6a6cc00f189949f7ba8fb (diff) |
ARM: Add support for checking access permissions on prefetch aborts
ARMv6 introduces non-executable mappings, which can cause prefetch aborts
when an attempt is made to execute from such a mapping. Currently, this
causes us to loop in the page fault handler since we don't correctly
check for proper permissions.
Fix this by checking that VMAs have VM_EXEC set for prefetch aborts.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mm')
-rw-r--r-- | arch/arm/mm/fault.c | 9 |
1 files changed, 6 insertions, 3 deletions
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index b7ce07d416cd..379f78556055 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c | |||
@@ -26,8 +26,9 @@ | |||
26 | #include "fault.h" | 26 | #include "fault.h" |
27 | 27 | ||
28 | /* | 28 | /* |
29 | * Fault status register encodings | 29 | * Fault status register encodings. We steal bit 31 for our own purposes. |
30 | */ | 30 | */ |
31 | #define FSR_LNX_PF (1 << 31) | ||
31 | #define FSR_WRITE (1 << 11) | 32 | #define FSR_WRITE (1 << 11) |
32 | #define FSR_FS4 (1 << 10) | 33 | #define FSR_FS4 (1 << 10) |
33 | #define FSR_FS3_0 (15) | 34 | #define FSR_FS3_0 (15) |
@@ -205,6 +206,8 @@ static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma) | |||
205 | 206 | ||
206 | if (fsr & FSR_WRITE) | 207 | if (fsr & FSR_WRITE) |
207 | mask = VM_WRITE; | 208 | mask = VM_WRITE; |
209 | if (fsr & FSR_LNX_PF) | ||
210 | mask = VM_EXEC; | ||
208 | 211 | ||
209 | return vma->vm_flags & mask ? false : true; | 212 | return vma->vm_flags & mask ? false : true; |
210 | } | 213 | } |
@@ -503,7 +506,7 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
503 | const struct fsr_info *inf = fsr_info + fsr_fs(fsr); | 506 | const struct fsr_info *inf = fsr_info + fsr_fs(fsr); |
504 | struct siginfo info; | 507 | struct siginfo info; |
505 | 508 | ||
506 | if (!inf->fn(addr, fsr, regs)) | 509 | if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs)) |
507 | return; | 510 | return; |
508 | 511 | ||
509 | printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", | 512 | printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n", |
@@ -519,6 +522,6 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
519 | asmlinkage void __exception | 522 | asmlinkage void __exception |
520 | do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) | 523 | do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) |
521 | { | 524 | { |
522 | do_translation_fault(addr, 0, regs); | 525 | do_translation_fault(addr, FSR_LNX_PF, regs); |
523 | } | 526 | } |
524 | 527 | ||