Skip to content

Commit

Permalink
x86: make spurious fault handler aware of large mappings
Browse files Browse the repository at this point in the history
In very rare cases, on certain CPUs, we could end up in the spurious
fault handler and ignore a large pud/pmd mapping. The resulting pte
pointer points into the mapped physical space and dereferencing it
will fault recursively.

Make the code aware of large mappings and do the permission check
on the pmd/pud entry, when a large pud/pmd mapping is detected.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Thomas Gleixner authored and Ingo Molnar committed Feb 6, 2008
1 parent 3aa4b37 commit d8b57bb
Showing 1 changed file with 17 additions and 6 deletions.
23 changes: 17 additions & 6 deletions arch/x86/mm/fault.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,16 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
}
#endif

static int spurious_fault_check(unsigned long error_code, pte_t *pte)
{
if ((error_code & PF_WRITE) && !pte_write(*pte))
return 0;
if ((error_code & PF_INSTR) && !pte_exec(*pte))
return 0;

return 1;
}

/*
* Handle a spurious fault caused by a stale TLB entry. This allows
* us to lazily refresh the TLB when increasing the permissions of a
Expand Down Expand Up @@ -457,20 +467,21 @@ static int spurious_fault(unsigned long address,
if (!pud_present(*pud))
return 0;

if (pud_large(*pud))
return spurious_fault_check(error_code, (pte_t *) pud);

pmd = pmd_offset(pud, address);
if (!pmd_present(*pmd))
return 0;

if (pmd_large(*pmd))
return spurious_fault_check(error_code, (pte_t *) pmd);

pte = pte_offset_kernel(pmd, address);
if (!pte_present(*pte))
return 0;

if ((error_code & PF_WRITE) && !pte_write(*pte))
return 0;
if ((error_code & PF_INSTR) && !pte_exec(*pte))
return 0;

return 1;
return spurious_fault_check(error_code, pte);
}

/*
Expand Down

0 comments on commit d8b57bb

Please sign in to comment.