提交 d8b57bb7 编写于 作者: T Thomas Gleixner 提交者: Ingo Molnar

x86: make spurious fault handler aware of large mappings

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: NThomas Gleixner <tglx@linutronix.de>
Signed-off-by: NIngo Molnar <mingo@elte.hu>
上级 3aa4b37d
...@@ -428,6 +428,16 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs, ...@@ -428,6 +428,16 @@ static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
} }
#endif #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 * Handle a spurious fault caused by a stale TLB entry. This allows
* us to lazily refresh the TLB when increasing the permissions of a * us to lazily refresh the TLB when increasing the permissions of a
...@@ -457,20 +467,21 @@ static int spurious_fault(unsigned long address, ...@@ -457,20 +467,21 @@ static int spurious_fault(unsigned long address,
if (!pud_present(*pud)) if (!pud_present(*pud))
return 0; return 0;
if (pud_large(*pud))
return spurious_fault_check(error_code, (pte_t *) pud);
pmd = pmd_offset(pud, address); pmd = pmd_offset(pud, address);
if (!pmd_present(*pmd)) if (!pmd_present(*pmd))
return 0; return 0;
if (pmd_large(*pmd))
return spurious_fault_check(error_code, (pte_t *) pmd);
pte = pte_offset_kernel(pmd, address); pte = pte_offset_kernel(pmd, address);
if (!pte_present(*pte)) if (!pte_present(*pte))
return 0; return 0;
if ((error_code & PF_WRITE) && !pte_write(*pte)) return spurious_fault_check(error_code, pte);
return 0;
if ((error_code & PF_INSTR) && !pte_exec(*pte))
return 0;
return 1;
} }
/* /*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册