diff options
| -rw-r--r-- | arch/x86/kernel/cfi.c | 8 | ||||
| -rw-r--r-- | arch/x86/kernel/traps.c | 16 |
2 files changed, 17 insertions, 7 deletions
diff --git a/arch/x86/kernel/cfi.c b/arch/x86/kernel/cfi.c index f6905bef0af8..77086cf565ec 100644 --- a/arch/x86/kernel/cfi.c +++ b/arch/x86/kernel/cfi.c @@ -67,16 +67,16 @@ static bool decode_cfi_insn(struct pt_regs *regs, unsigned long *target, */ enum bug_trap_type handle_cfi_failure(struct pt_regs *regs) { - unsigned long target; + unsigned long target, addr = regs->ip; u32 type; switch (cfi_mode) { case CFI_KCFI: - if (!is_cfi_trap(regs->ip)) + if (!is_cfi_trap(addr)) return BUG_TRAP_TYPE_NONE; if (!decode_cfi_insn(regs, &target, &type)) - return report_cfi_failure_noaddr(regs, regs->ip); + return report_cfi_failure_noaddr(regs, addr); break; @@ -90,7 +90,7 @@ enum bug_trap_type handle_cfi_failure(struct pt_regs *regs) return BUG_TRAP_TYPE_NONE; } - return report_cfi_failure(regs, regs->ip, &target, type); + return report_cfi_failure(regs, addr, &target, type); } /* 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(); |
