diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2009-02-19 11:46:36 -0500 |
|---|---|---|
| committer | Steven Rostedt <srostedt@redhat.com> | 2009-02-20 11:44:47 -0500 |
| commit | 3c3e5694add02e665bbbd0fecfbbdcc0b903097a (patch) | |
| tree | 949dd1e8f6f5903bedf3e20b407da1b4d2823881 | |
| parent | 07a66d7c53a538e1a9759954a82bb6c07365eff9 (diff) | |
x86: check PMD in spurious_fault handler
Impact: fix to prevent hard lockup on bad PMD permissions
If the PMD does not have the correct permissions for a page access,
but the PTE does, the spurious fault handler will mistake the fault
as a lazy TLB transaction. This will result in an infinite loop of:
fault -> spurious_fault check (pass) -> return to code -> fault
This patch adds a check and a warn on if the PTE passes the permissions
but the PMD does not.
[ Updated: Ingo Molnar suggested using WARN_ONCE with some text ]
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
| -rw-r--r-- | arch/x86/mm/fault.c | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index c76ef1d701c9..278d645d108a 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c | |||
| @@ -455,6 +455,7 @@ static int spurious_fault(unsigned long address, | |||
| 455 | pud_t *pud; | 455 | pud_t *pud; |
| 456 | pmd_t *pmd; | 456 | pmd_t *pmd; |
| 457 | pte_t *pte; | 457 | pte_t *pte; |
| 458 | int ret; | ||
| 458 | 459 | ||
| 459 | /* Reserved-bit violation or user access to kernel space? */ | 460 | /* Reserved-bit violation or user access to kernel space? */ |
| 460 | if (error_code & (PF_USER | PF_RSVD)) | 461 | if (error_code & (PF_USER | PF_RSVD)) |
| @@ -482,7 +483,17 @@ static int spurious_fault(unsigned long address, | |||
| 482 | if (!pte_present(*pte)) | 483 | if (!pte_present(*pte)) |
| 483 | return 0; | 484 | return 0; |
| 484 | 485 | ||
| 485 | return spurious_fault_check(error_code, pte); | 486 | ret = spurious_fault_check(error_code, pte); |
| 487 | if (!ret) | ||
| 488 | return 0; | ||
| 489 | |||
| 490 | /* | ||
| 491 | * Make sure we have permissions in PMD | ||
| 492 | * If not, then there's a bug in the page tables. | ||
| 493 | */ | ||
| 494 | ret = spurious_fault_check(error_code, (pte_t *) pmd); | ||
| 495 | WARN_ONCE(!ret, "PMD has incorrect permission bits\n"); | ||
| 496 | return ret; | ||
| 486 | } | 497 | } |
| 487 | 498 | ||
| 488 | /* | 499 | /* |
