aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/mm/fault.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index cfd65b63f36f..9808da29a653 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -8,6 +8,7 @@
8 */ 8 */
9 9
10#include <linux/acpi.h> 10#include <linux/acpi.h>
11#include <linux/bitfield.h>
11#include <linux/extable.h> 12#include <linux/extable.h>
12#include <linux/signal.h> 13#include <linux/signal.h>
13#include <linux/mm.h> 14#include <linux/mm.h>
@@ -242,6 +243,34 @@ static inline bool is_el1_permission_fault(unsigned long addr, unsigned int esr,
242 return false; 243 return false;
243} 244}
244 245
246static bool __kprobes is_spurious_el1_translation_fault(unsigned long addr,
247 unsigned int esr,
248 struct pt_regs *regs)
249{
250 unsigned long flags;
251 u64 par, dfsc;
252
253 if (ESR_ELx_EC(esr) != ESR_ELx_EC_DABT_CUR ||
254 (esr & ESR_ELx_FSC_TYPE) != ESR_ELx_FSC_FAULT)
255 return false;
256
257 local_irq_save(flags);
258 asm volatile("at s1e1r, %0" :: "r" (addr));
259 isb();
260 par = read_sysreg(par_el1);
261 local_irq_restore(flags);
262
263 if (!(par & SYS_PAR_EL1_F))
264 return false;
265
266 /*
267 * If we got a different type of fault from the AT instruction,
268 * treat the translation fault as spurious.
269 */
270 dfsc = FIELD_PREP(SYS_PAR_EL1_FST, par);
271 return (dfsc & ESR_ELx_FSC_TYPE) != ESR_ELx_FSC_FAULT;
272}
273
245static void die_kernel_fault(const char *msg, unsigned long addr, 274static void die_kernel_fault(const char *msg, unsigned long addr,
246 unsigned int esr, struct pt_regs *regs) 275 unsigned int esr, struct pt_regs *regs)
247{ 276{
@@ -270,6 +299,10 @@ static void __do_kernel_fault(unsigned long addr, unsigned int esr,
270 if (!is_el1_instruction_abort(esr) && fixup_exception(regs)) 299 if (!is_el1_instruction_abort(esr) && fixup_exception(regs))
271 return; 300 return;
272 301
302 if (WARN_RATELIMIT(is_spurious_el1_translation_fault(addr, esr, regs),
303 "Ignoring spurious kernel translation fault at virtual address %016lx\n", addr))
304 return;
305
273 if (is_el1_permission_fault(addr, esr, regs)) { 306 if (is_el1_permission_fault(addr, esr, regs)) {
274 if (esr & ESR_ELx_WNR) 307 if (esr & ESR_ELx_WNR)
275 msg = "write to read-only memory"; 308 msg = "write to read-only memory";