summaryrefslogtreecommitdiff
path: root/arch/x86/kernel/traps.c
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2025-02-24 13:37:07 +0100
committerIngo Molnar <mingo@kernel.org>2025-02-26 12:22:39 +0100
commite33d805a1005bf7b8a5a53559c81a8e17f0b981b (patch)
tree465a6d08da0467b990a94b5f88883836daa300ab /arch/x86/kernel/traps.c
parent2e044911be75ce3321c5b3d10205ac0b54f8cb92 (diff)
downloadlinux-next-e33d805a1005bf7b8a5a53559c81a8e17f0b981b.tar.gz
linux-next-e33d805a1005bf7b8a5a53559c81a8e17f0b981b.zip
x86/traps: Allow custom fixups in handle_bug()
The normal fixup in handle_bug() is simply continuing at the next instruction. However upcoming patches make this the wrong thing, so allow handlers (specifically handle_cfi_failure()) to over-ride regs->ip. The callchain is such that the fixup needs to be done before it is determined if the exception is fatal, as such, revert any changes in that case. Additionally, have handle_cfi_failure() remember the regs->ip value it starts with for reporting. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Reviewed-by: Kees Cook <kees@kernel.org> Link: https://lore.kernel.org/r/20250224124200.275223080@infradead.org
Diffstat (limited to 'arch/x86/kernel/traps.c')
-rw-r--r--arch/x86/kernel/traps.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index a02a51bf433f..c169f3bd3c6c 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -287,11 +287,12 @@ static inline void handle_invalid_op(struct pt_regs *regs)
static noinstr bool handle_bug(struct pt_regs *regs)
{
+ unsigned long addr = regs->ip;
bool handled = false;
int ud_type, ud_len;
s32 ud_imm;
- ud_type = decode_bug(regs->ip, &ud_imm, &ud_len);
+ ud_type = decode_bug(addr, &ud_imm, &ud_len);
if (ud_type == BUG_NONE)
return handled;
@@ -339,8 +340,17 @@ static noinstr bool handle_bug(struct pt_regs *regs)
break;
}
- if (handled)
- regs->ip += ud_len;
+ /*
+ * When continuing, and regs->ip hasn't changed, move it to the next
+ * instruction. When not continuing execution, restore the instruction
+ * pointer.
+ */
+ if (handled) {
+ if (regs->ip == addr)
+ regs->ip += ud_len;
+ } else {
+ regs->ip = addr;
+ }
if (regs->flags & X86_EFLAGS_IF)
raw_local_irq_disable();