diff options
Diffstat (limited to 'arch/arm64/mm/fault.c')
| -rw-r--r-- | arch/arm64/mm/fault.c | 131 | 
1 files changed, 74 insertions, 57 deletions
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 9b7f89df49db..ce441d29e7f6 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -596,7 +596,7 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)  	info.si_signo = SIGBUS;  	info.si_errno = 0; -	info.si_code  = 0; +	info.si_code  = BUS_FIXME;  	if (esr & ESR_ELx_FnV)  		info.si_addr = NULL;  	else @@ -607,70 +607,70 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)  }  static const struct fault_info fault_info[] = { -	{ do_bad,		SIGBUS,  0,		"ttbr address size fault"	}, -	{ do_bad,		SIGBUS,  0,		"level 1 address size fault"	}, -	{ do_bad,		SIGBUS,  0,		"level 2 address size fault"	}, -	{ do_bad,		SIGBUS,  0,		"level 3 address size fault"	}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"ttbr address size fault"	}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"level 1 address size fault"	}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"level 2 address size fault"	}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"level 3 address size fault"	},  	{ do_translation_fault,	SIGSEGV, SEGV_MAPERR,	"level 0 translation fault"	},  	{ do_translation_fault,	SIGSEGV, SEGV_MAPERR,	"level 1 translation fault"	},  	{ do_translation_fault,	SIGSEGV, SEGV_MAPERR,	"level 2 translation fault"	},  	{ do_translation_fault,	SIGSEGV, SEGV_MAPERR,	"level 3 translation fault"	}, -	{ do_bad,		SIGBUS,  0,		"unknown 8"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 8"			},  	{ do_page_fault,	SIGSEGV, SEGV_ACCERR,	"level 1 access flag fault"	},  	{ do_page_fault,	SIGSEGV, SEGV_ACCERR,	"level 2 access flag fault"	},  	{ do_page_fault,	SIGSEGV, SEGV_ACCERR,	"level 3 access flag fault"	}, -	{ do_bad,		SIGBUS,  0,		"unknown 12"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 12"			},  	{ do_page_fault,	SIGSEGV, SEGV_ACCERR,	"level 1 permission fault"	},  	{ do_page_fault,	SIGSEGV, SEGV_ACCERR,	"level 2 permission fault"	},  	{ do_page_fault,	SIGSEGV, SEGV_ACCERR,	"level 3 permission fault"	}, -	{ do_sea,		SIGBUS,  0,		"synchronous external abort"	}, -	{ do_bad,		SIGBUS,  0,		"unknown 17"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 18"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 19"			}, -	{ do_sea,		SIGBUS,  0,		"level 0 (translation table walk)"	}, -	{ do_sea,		SIGBUS,  0,		"level 1 (translation table walk)"	}, -	{ do_sea,		SIGBUS,  0,		"level 2 (translation table walk)"	}, -	{ do_sea,		SIGBUS,  0,		"level 3 (translation table walk)"	}, -	{ do_sea,		SIGBUS,  0,		"synchronous parity or ECC error" },	// Reserved when RAS is implemented -	{ do_bad,		SIGBUS,  0,		"unknown 25"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 26"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 27"			}, -	{ do_sea,		SIGBUS,  0,		"level 0 synchronous parity error (translation table walk)"	},	// Reserved when RAS is implemented -	{ do_sea,		SIGBUS,  0,		"level 1 synchronous parity error (translation table walk)"	},	// Reserved when RAS is implemented -	{ do_sea,		SIGBUS,  0,		"level 2 synchronous parity error (translation table walk)"	},	// Reserved when RAS is implemented -	{ do_sea,		SIGBUS,  0,		"level 3 synchronous parity error (translation table walk)"	},	// Reserved when RAS is implemented -	{ do_bad,		SIGBUS,  0,		"unknown 32"			}, +	{ do_sea,		SIGBUS,  BUS_FIXME,	"synchronous external abort"	}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 17"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 18"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 19"			}, +	{ do_sea,		SIGBUS,  BUS_FIXME,	"level 0 (translation table walk)"	}, +	{ do_sea,		SIGBUS,  BUS_FIXME,	"level 1 (translation table walk)"	}, +	{ do_sea,		SIGBUS,  BUS_FIXME,	"level 2 (translation table walk)"	}, +	{ do_sea,		SIGBUS,  BUS_FIXME,	"level 3 (translation table walk)"	}, +	{ do_sea,		SIGBUS,  BUS_FIXME,	"synchronous parity or ECC error" },	// Reserved when RAS is implemented +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 25"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 26"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 27"			}, +	{ do_sea,		SIGBUS,  BUS_FIXME,	"level 0 synchronous parity error (translation table walk)"	},	// Reserved when RAS is implemented +	{ do_sea,		SIGBUS,  BUS_FIXME,	"level 1 synchronous parity error (translation table walk)"	},	// Reserved when RAS is implemented +	{ do_sea,		SIGBUS,  BUS_FIXME,	"level 2 synchronous parity error (translation table walk)"	},	// Reserved when RAS is implemented +	{ do_sea,		SIGBUS,  BUS_FIXME,	"level 3 synchronous parity error (translation table walk)"	},	// Reserved when RAS is implemented +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 32"			},  	{ do_alignment_fault,	SIGBUS,  BUS_ADRALN,	"alignment fault"		}, -	{ do_bad,		SIGBUS,  0,		"unknown 34"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 35"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 36"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 37"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 38"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 39"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 40"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 41"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 42"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 43"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 44"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 45"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 46"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 47"			}, -	{ do_bad,		SIGBUS,  0,		"TLB conflict abort"		}, -	{ do_bad,		SIGBUS,  0,		"Unsupported atomic hardware update fault"	}, -	{ do_bad,		SIGBUS,  0,		"unknown 50"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 51"			}, -	{ do_bad,		SIGBUS,  0,		"implementation fault (lockdown abort)" }, -	{ do_bad,		SIGBUS,  0,		"implementation fault (unsupported exclusive)" }, -	{ do_bad,		SIGBUS,  0,		"unknown 54"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 55"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 56"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 57"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 58" 			}, -	{ do_bad,		SIGBUS,  0,		"unknown 59"			}, -	{ do_bad,		SIGBUS,  0,		"unknown 60"			}, -	{ do_bad,		SIGBUS,  0,		"section domain fault"		}, -	{ do_bad,		SIGBUS,  0,		"page domain fault"		}, -	{ do_bad,		SIGBUS,  0,		"unknown 63"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 34"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 35"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 36"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 37"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 38"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 39"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 40"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 41"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 42"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 43"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 44"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 45"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 46"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 47"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"TLB conflict abort"		}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"Unsupported atomic hardware update fault"	}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 50"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 51"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"implementation fault (lockdown abort)" }, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"implementation fault (unsupported exclusive)" }, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 54"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 55"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 56"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 57"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 58" 			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 59"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 60"			}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"section domain fault"		}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"page domain fault"		}, +	{ do_bad,		SIGBUS,  BUS_FIXME,	"unknown 63"			},  };  int handle_guest_sea(phys_addr_t addr, unsigned int esr) @@ -707,6 +707,23 @@ asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr,  	arm64_notify_die("", regs, &info, esr);  } +asmlinkage void __exception do_el0_ia_bp_hardening(unsigned long addr, +						   unsigned int esr, +						   struct pt_regs *regs) +{ +	/* +	 * We've taken an instruction abort from userspace and not yet +	 * re-enabled IRQs. If the address is a kernel address, apply +	 * BP hardening prior to enabling IRQs and pre-emption. +	 */ +	if (addr > TASK_SIZE) +		arm64_apply_bp_hardening(); + +	local_irq_enable(); +	do_mem_abort(addr, esr, regs); +} + +  asmlinkage void __exception do_sp_pc_abort(unsigned long addr,  					   unsigned int esr,  					   struct pt_regs *regs) @@ -739,11 +756,11 @@ static struct fault_info __refdata debug_fault_info[] = {  	{ do_bad,	SIGTRAP,	TRAP_HWBKPT,	"hardware breakpoint"	},  	{ do_bad,	SIGTRAP,	TRAP_HWBKPT,	"hardware single-step"	},  	{ do_bad,	SIGTRAP,	TRAP_HWBKPT,	"hardware watchpoint"	}, -	{ do_bad,	SIGBUS,		0,		"unknown 3"		}, +	{ do_bad,	SIGBUS,		BUS_FIXME,	"unknown 3"		},  	{ do_bad,	SIGTRAP,	TRAP_BRKPT,	"aarch32 BKPT"		}, -	{ do_bad,	SIGTRAP,	0,		"aarch32 vector catch"	}, +	{ do_bad,	SIGTRAP,	TRAP_FIXME,	"aarch32 vector catch"	},  	{ early_brk64,	SIGTRAP,	TRAP_BRKPT,	"aarch64 BRK"		}, -	{ do_bad,	SIGBUS,		0,		"unknown 7"		}, +	{ do_bad,	SIGBUS,		BUS_FIXME,	"unknown 7"		},  };  void __init hook_debug_fault_code(int nr,  |