x86/fault: Plumb error code and fault address through to fault handlers
This is preparation for looking at trap number and fault address in the handlers for uaccess errors. No functional change. Signed-off-by: Jann Horn <jannh@google.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Kees Cook <keescook@chromium.org> Cc: Andy Lutomirski <luto@kernel.org> Cc: kernel-hardening@lists.openwall.com Cc: linux-kernel@vger.kernel.org Cc: dvyukov@google.com Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: "Naveen N. Rao" <naveen.n.rao@linux.vnet.ibm.com> Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: linux-fsdevel@vger.kernel.org Cc: Borislav Petkov <bp@alien8.de> Link: https://lkml.kernel.org/r/20180828201421.157735-6-jannh@google.com
This commit is contained in:
parent
75045f77f7
commit
81fd9c1844
|
@ -29,7 +29,8 @@ struct pt_regs;
|
|||
(b)->handler = (tmp).handler - (delta); \
|
||||
} while (0)
|
||||
|
||||
extern int fixup_exception(struct pt_regs *regs, int trapnr);
|
||||
extern int fixup_exception(struct pt_regs *regs, int trapnr,
|
||||
unsigned long error_code, unsigned long fault_addr);
|
||||
extern int fixup_bug(struct pt_regs *regs, int trapnr);
|
||||
extern bool ex_has_fault_handler(unsigned long ip);
|
||||
extern void early_fixup_exception(struct pt_regs *regs, int trapnr);
|
||||
|
|
|
@ -37,8 +37,10 @@ struct pt_regs {
|
|||
unsigned short __esh;
|
||||
unsigned short fs;
|
||||
unsigned short __fsh;
|
||||
/* On interrupt, gs and __gsh store the vector number. */
|
||||
unsigned short gs;
|
||||
unsigned short __gsh;
|
||||
/* On interrupt, this is the error code. */
|
||||
unsigned long orig_ax;
|
||||
unsigned long ip;
|
||||
unsigned short cs;
|
||||
|
|
|
@ -1315,7 +1315,7 @@ void do_machine_check(struct pt_regs *regs, long error_code)
|
|||
local_irq_disable();
|
||||
ist_end_non_atomic();
|
||||
} else {
|
||||
if (!fixup_exception(regs, X86_TRAP_MC))
|
||||
if (!fixup_exception(regs, X86_TRAP_MC, error_code, 0))
|
||||
mce_panic("Failed kernel mode recovery", &m, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -206,7 +206,7 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
|
|||
}
|
||||
|
||||
if (!user_mode(regs)) {
|
||||
if (fixup_exception(regs, trapnr))
|
||||
if (fixup_exception(regs, trapnr, error_code, 0))
|
||||
return 0;
|
||||
|
||||
tsk->thread.error_code = error_code;
|
||||
|
@ -551,7 +551,7 @@ do_general_protection(struct pt_regs *regs, long error_code)
|
|||
|
||||
tsk = current;
|
||||
if (!user_mode(regs)) {
|
||||
if (fixup_exception(regs, X86_TRAP_GP))
|
||||
if (fixup_exception(regs, X86_TRAP_GP, error_code, 0))
|
||||
return;
|
||||
|
||||
tsk->thread.error_code = error_code;
|
||||
|
@ -848,7 +848,7 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr)
|
|||
cond_local_irq_enable(regs);
|
||||
|
||||
if (!user_mode(regs)) {
|
||||
if (fixup_exception(regs, trapnr))
|
||||
if (fixup_exception(regs, trapnr, error_code, 0))
|
||||
return;
|
||||
|
||||
task->thread.error_code = error_code;
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
#include <asm/kdebug.h>
|
||||
|
||||
typedef bool (*ex_handler_t)(const struct exception_table_entry *,
|
||||
struct pt_regs *, int);
|
||||
struct pt_regs *, int, unsigned long,
|
||||
unsigned long);
|
||||
|
||||
static inline unsigned long
|
||||
ex_fixup_addr(const struct exception_table_entry *x)
|
||||
|
@ -22,7 +23,9 @@ ex_fixup_handler(const struct exception_table_entry *x)
|
|||
}
|
||||
|
||||
__visible bool ex_handler_default(const struct exception_table_entry *fixup,
|
||||
struct pt_regs *regs, int trapnr)
|
||||
struct pt_regs *regs, int trapnr,
|
||||
unsigned long error_code,
|
||||
unsigned long fault_addr)
|
||||
{
|
||||
regs->ip = ex_fixup_addr(fixup);
|
||||
return true;
|
||||
|
@ -30,7 +33,9 @@ __visible bool ex_handler_default(const struct exception_table_entry *fixup,
|
|||
EXPORT_SYMBOL(ex_handler_default);
|
||||
|
||||
__visible bool ex_handler_fault(const struct exception_table_entry *fixup,
|
||||
struct pt_regs *regs, int trapnr)
|
||||
struct pt_regs *regs, int trapnr,
|
||||
unsigned long error_code,
|
||||
unsigned long fault_addr)
|
||||
{
|
||||
regs->ip = ex_fixup_addr(fixup);
|
||||
regs->ax = trapnr;
|
||||
|
@ -43,7 +48,9 @@ EXPORT_SYMBOL_GPL(ex_handler_fault);
|
|||
* result of a refcount inc/dec/add/sub.
|
||||
*/
|
||||
__visible bool ex_handler_refcount(const struct exception_table_entry *fixup,
|
||||
struct pt_regs *regs, int trapnr)
|
||||
struct pt_regs *regs, int trapnr,
|
||||
unsigned long error_code,
|
||||
unsigned long fault_addr)
|
||||
{
|
||||
/* First unconditionally saturate the refcount. */
|
||||
*(int *)regs->cx = INT_MIN / 2;
|
||||
|
@ -96,7 +103,9 @@ EXPORT_SYMBOL(ex_handler_refcount);
|
|||
* out all the FPU registers) if we can't restore from the task's FPU state.
|
||||
*/
|
||||
__visible bool ex_handler_fprestore(const struct exception_table_entry *fixup,
|
||||
struct pt_regs *regs, int trapnr)
|
||||
struct pt_regs *regs, int trapnr,
|
||||
unsigned long error_code,
|
||||
unsigned long fault_addr)
|
||||
{
|
||||
regs->ip = ex_fixup_addr(fixup);
|
||||
|
||||
|
@ -109,7 +118,9 @@ __visible bool ex_handler_fprestore(const struct exception_table_entry *fixup,
|
|||
EXPORT_SYMBOL_GPL(ex_handler_fprestore);
|
||||
|
||||
__visible bool ex_handler_uaccess(const struct exception_table_entry *fixup,
|
||||
struct pt_regs *regs, int trapnr)
|
||||
struct pt_regs *regs, int trapnr,
|
||||
unsigned long error_code,
|
||||
unsigned long fault_addr)
|
||||
{
|
||||
regs->ip = ex_fixup_addr(fixup);
|
||||
return true;
|
||||
|
@ -117,7 +128,9 @@ __visible bool ex_handler_uaccess(const struct exception_table_entry *fixup,
|
|||
EXPORT_SYMBOL(ex_handler_uaccess);
|
||||
|
||||
__visible bool ex_handler_ext(const struct exception_table_entry *fixup,
|
||||
struct pt_regs *regs, int trapnr)
|
||||
struct pt_regs *regs, int trapnr,
|
||||
unsigned long error_code,
|
||||
unsigned long fault_addr)
|
||||
{
|
||||
/* Special hack for uaccess_err */
|
||||
current->thread.uaccess_err = 1;
|
||||
|
@ -127,7 +140,9 @@ __visible bool ex_handler_ext(const struct exception_table_entry *fixup,
|
|||
EXPORT_SYMBOL(ex_handler_ext);
|
||||
|
||||
__visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup,
|
||||
struct pt_regs *regs, int trapnr)
|
||||
struct pt_regs *regs, int trapnr,
|
||||
unsigned long error_code,
|
||||
unsigned long fault_addr)
|
||||
{
|
||||
if (pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pF)\n",
|
||||
(unsigned int)regs->cx, regs->ip, (void *)regs->ip))
|
||||
|
@ -142,7 +157,9 @@ __visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup
|
|||
EXPORT_SYMBOL(ex_handler_rdmsr_unsafe);
|
||||
|
||||
__visible bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup,
|
||||
struct pt_regs *regs, int trapnr)
|
||||
struct pt_regs *regs, int trapnr,
|
||||
unsigned long error_code,
|
||||
unsigned long fault_addr)
|
||||
{
|
||||
if (pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pF)\n",
|
||||
(unsigned int)regs->cx, (unsigned int)regs->dx,
|
||||
|
@ -156,12 +173,14 @@ __visible bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup
|
|||
EXPORT_SYMBOL(ex_handler_wrmsr_unsafe);
|
||||
|
||||
__visible bool ex_handler_clear_fs(const struct exception_table_entry *fixup,
|
||||
struct pt_regs *regs, int trapnr)
|
||||
struct pt_regs *regs, int trapnr,
|
||||
unsigned long error_code,
|
||||
unsigned long fault_addr)
|
||||
{
|
||||
if (static_cpu_has(X86_BUG_NULL_SEG))
|
||||
asm volatile ("mov %0, %%fs" : : "rm" (__USER_DS));
|
||||
asm volatile ("mov %0, %%fs" : : "rm" (0));
|
||||
return ex_handler_default(fixup, regs, trapnr);
|
||||
return ex_handler_default(fixup, regs, trapnr, error_code, fault_addr);
|
||||
}
|
||||
EXPORT_SYMBOL(ex_handler_clear_fs);
|
||||
|
||||
|
@ -178,7 +197,8 @@ __visible bool ex_has_fault_handler(unsigned long ip)
|
|||
return handler == ex_handler_fault;
|
||||
}
|
||||
|
||||
int fixup_exception(struct pt_regs *regs, int trapnr)
|
||||
int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code,
|
||||
unsigned long fault_addr)
|
||||
{
|
||||
const struct exception_table_entry *e;
|
||||
ex_handler_t handler;
|
||||
|
@ -202,7 +222,7 @@ int fixup_exception(struct pt_regs *regs, int trapnr)
|
|||
return 0;
|
||||
|
||||
handler = ex_fixup_handler(e);
|
||||
return handler(e, regs, trapnr);
|
||||
return handler(e, regs, trapnr, error_code, fault_addr);
|
||||
}
|
||||
|
||||
extern unsigned int early_recursion_flag;
|
||||
|
@ -238,9 +258,9 @@ void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
|
|||
* result in a hard-to-debug panic.
|
||||
*
|
||||
* Keep in mind that not all vectors actually get here. Early
|
||||
* fage faults, for example, are special.
|
||||
* page faults, for example, are special.
|
||||
*/
|
||||
if (fixup_exception(regs, trapnr))
|
||||
if (fixup_exception(regs, trapnr, regs->orig_ax, 0))
|
||||
return;
|
||||
|
||||
if (fixup_bug(regs, trapnr))
|
||||
|
|
|
@ -711,7 +711,7 @@ no_context(struct pt_regs *regs, unsigned long error_code,
|
|||
int sig;
|
||||
|
||||
/* Are we prepared to handle this kernel fault? */
|
||||
if (fixup_exception(regs, X86_TRAP_PF)) {
|
||||
if (fixup_exception(regs, X86_TRAP_PF, error_code, address)) {
|
||||
/*
|
||||
* Any interrupt that takes a fault gets the fixup. This makes
|
||||
* the below recursive fault logic only apply to a faults from
|
||||
|
|
Loading…
Reference in New Issue