diff options
Diffstat (limited to 'arch/powerpc/mm/fault.c')
-rw-r--r-- | arch/powerpc/mm/fault.c | 49 |
1 files changed, 33 insertions, 16 deletions
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 2e6fb1d758c3..a6dcfda3e11e 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c | |||
@@ -226,7 +226,9 @@ static int mm_fault_error(struct pt_regs *regs, unsigned long addr, | |||
226 | static bool bad_kernel_fault(bool is_exec, unsigned long error_code, | 226 | static bool bad_kernel_fault(bool is_exec, unsigned long error_code, |
227 | unsigned long address) | 227 | unsigned long address) |
228 | { | 228 | { |
229 | if (is_exec && (error_code & (DSISR_NOEXEC_OR_G | DSISR_KEYFAULT))) { | 229 | /* NX faults set DSISR_PROTFAULT on the 8xx, DSISR_NOEXEC_OR_G on others */ |
230 | if (is_exec && (error_code & (DSISR_NOEXEC_OR_G | DSISR_KEYFAULT | | ||
231 | DSISR_PROTFAULT))) { | ||
230 | printk_ratelimited(KERN_CRIT "kernel tried to execute" | 232 | printk_ratelimited(KERN_CRIT "kernel tried to execute" |
231 | " exec-protected page (%lx) -" | 233 | " exec-protected page (%lx) -" |
232 | "exploit attempt? (uid: %d)\n", | 234 | "exploit attempt? (uid: %d)\n", |
@@ -341,10 +343,21 @@ static inline void cmo_account_page_fault(void) | |||
341 | static inline void cmo_account_page_fault(void) { } | 343 | static inline void cmo_account_page_fault(void) { } |
342 | #endif /* CONFIG_PPC_SMLPAR */ | 344 | #endif /* CONFIG_PPC_SMLPAR */ |
343 | 345 | ||
344 | #ifdef CONFIG_PPC_STD_MMU | 346 | #ifdef CONFIG_PPC_BOOK3S |
345 | static void sanity_check_fault(bool is_write, unsigned long error_code) | 347 | static void sanity_check_fault(bool is_write, bool is_user, |
348 | unsigned long error_code, unsigned long address) | ||
346 | { | 349 | { |
347 | /* | 350 | /* |
351 | * Userspace trying to access kernel address, we get PROTFAULT for that. | ||
352 | */ | ||
353 | if (is_user && address >= TASK_SIZE) { | ||
354 | pr_crit_ratelimited("%s[%d]: User access of kernel address (%lx) - exploit attempt? (uid: %d)\n", | ||
355 | current->comm, current->pid, address, | ||
356 | from_kuid(&init_user_ns, current_uid())); | ||
357 | return; | ||
358 | } | ||
359 | |||
360 | /* | ||
348 | * For hash translation mode, we should never get a | 361 | * For hash translation mode, we should never get a |
349 | * PROTFAULT. Any update to pte to reduce access will result in us | 362 | * PROTFAULT. Any update to pte to reduce access will result in us |
350 | * removing the hash page table entry, thus resulting in a DSISR_NOHPTE | 363 | * removing the hash page table entry, thus resulting in a DSISR_NOHPTE |
@@ -373,12 +386,15 @@ static void sanity_check_fault(bool is_write, unsigned long error_code) | |||
373 | * For radix, we can get prot fault for autonuma case, because radix | 386 | * For radix, we can get prot fault for autonuma case, because radix |
374 | * page table will have them marked noaccess for user. | 387 | * page table will have them marked noaccess for user. |
375 | */ | 388 | */ |
376 | if (!radix_enabled() && !is_write) | 389 | if (radix_enabled() || is_write) |
377 | WARN_ON_ONCE(error_code & DSISR_PROTFAULT); | 390 | return; |
391 | |||
392 | WARN_ON_ONCE(error_code & DSISR_PROTFAULT); | ||
378 | } | 393 | } |
379 | #else | 394 | #else |
380 | static void sanity_check_fault(bool is_write, unsigned long error_code) { } | 395 | static void sanity_check_fault(bool is_write, bool is_user, |
381 | #endif /* CONFIG_PPC_STD_MMU */ | 396 | unsigned long error_code, unsigned long address) { } |
397 | #endif /* CONFIG_PPC_BOOK3S */ | ||
382 | 398 | ||
383 | /* | 399 | /* |
384 | * Define the correct "is_write" bit in error_code based | 400 | * Define the correct "is_write" bit in error_code based |
@@ -435,7 +451,7 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address, | |||
435 | } | 451 | } |
436 | 452 | ||
437 | /* Additional sanity check(s) */ | 453 | /* Additional sanity check(s) */ |
438 | sanity_check_fault(is_write, error_code); | 454 | sanity_check_fault(is_write, is_user, error_code, address); |
439 | 455 | ||
440 | /* | 456 | /* |
441 | * The kernel should never take an execute fault nor should it | 457 | * The kernel should never take an execute fault nor should it |
@@ -637,21 +653,22 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) | |||
637 | case 0x300: | 653 | case 0x300: |
638 | case 0x380: | 654 | case 0x380: |
639 | case 0xe00: | 655 | case 0xe00: |
640 | printk(KERN_ALERT "Unable to handle kernel paging request for " | 656 | pr_alert("BUG: %s at 0x%08lx\n", |
641 | "data at address 0x%08lx\n", regs->dar); | 657 | regs->dar < PAGE_SIZE ? "Kernel NULL pointer dereference" : |
658 | "Unable to handle kernel data access", regs->dar); | ||
642 | break; | 659 | break; |
643 | case 0x400: | 660 | case 0x400: |
644 | case 0x480: | 661 | case 0x480: |
645 | printk(KERN_ALERT "Unable to handle kernel paging request for " | 662 | pr_alert("BUG: Unable to handle kernel instruction fetch%s", |
646 | "instruction fetch\n"); | 663 | regs->nip < PAGE_SIZE ? " (NULL pointer?)\n" : "\n"); |
647 | break; | 664 | break; |
648 | case 0x600: | 665 | case 0x600: |
649 | printk(KERN_ALERT "Unable to handle kernel paging request for " | 666 | pr_alert("BUG: Unable to handle kernel unaligned access at 0x%08lx\n", |
650 | "unaligned access at address 0x%08lx\n", regs->dar); | 667 | regs->dar); |
651 | break; | 668 | break; |
652 | default: | 669 | default: |
653 | printk(KERN_ALERT "Unable to handle kernel paging request for " | 670 | pr_alert("BUG: Unable to handle unknown paging fault at 0x%08lx\n", |
654 | "unknown fault\n"); | 671 | regs->dar); |
655 | break; | 672 | break; |
656 | } | 673 | } |
657 | printk(KERN_ALERT "Faulting instruction address: 0x%08lx\n", | 674 | printk(KERN_ALERT "Faulting instruction address: 0x%08lx\n", |