x86/alternatives: Introduce int3_emulate_jcc()
authorPeter Zijlstra <peterz@infradead.org>
Mon, 23 Jan 2023 20:59:16 +0000 (21:59 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 25 Feb 2023 10:25:41 +0000 (11:25 +0100)
commit db7adcfd1cec4e95155e37bc066fddab302c6340 upstream.

Move the kprobe Jcc emulation into int3_emulate_jcc() so it can be
used by more code -- specifically static_call() will need this.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Link: https://lore.kernel.org/r/20230123210607.057678245@infradead.org
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/include/asm/text-patching.h
arch/x86/kernel/kprobes/core.c

index 1cc1552..85b85a2 100644 (file)
@@ -183,6 +183,37 @@ void int3_emulate_ret(struct pt_regs *regs)
        unsigned long ip = int3_emulate_pop(regs);
        int3_emulate_jmp(regs, ip);
 }
+
+static __always_inline
+void int3_emulate_jcc(struct pt_regs *regs, u8 cc, unsigned long ip, unsigned long disp)
+{
+       static const unsigned long jcc_mask[6] = {
+               [0] = X86_EFLAGS_OF,
+               [1] = X86_EFLAGS_CF,
+               [2] = X86_EFLAGS_ZF,
+               [3] = X86_EFLAGS_CF | X86_EFLAGS_ZF,
+               [4] = X86_EFLAGS_SF,
+               [5] = X86_EFLAGS_PF,
+       };
+
+       bool invert = cc & 1;
+       bool match;
+
+       if (cc < 0xc) {
+               match = regs->flags & jcc_mask[cc >> 1];
+       } else {
+               match = ((regs->flags & X86_EFLAGS_SF) >> X86_EFLAGS_SF_BIT) ^
+                       ((regs->flags & X86_EFLAGS_OF) >> X86_EFLAGS_OF_BIT);
+               if (cc >= 0xe)
+                       match = match || (regs->flags & X86_EFLAGS_ZF);
+       }
+
+       if ((match && !invert) || (!match && invert))
+               ip += disp;
+
+       int3_emulate_jmp(regs, ip);
+}
+
 #endif /* !CONFIG_UML_X86 */
 
 #endif /* _ASM_X86_TEXT_PATCHING_H */
index 5be7f23..ea155f0 100644 (file)
@@ -471,50 +471,26 @@ static void kprobe_emulate_call(struct kprobe *p, struct pt_regs *regs)
 }
 NOKPROBE_SYMBOL(kprobe_emulate_call);
 
-static nokprobe_inline
-void __kprobe_emulate_jmp(struct kprobe *p, struct pt_regs *regs, bool cond)
+static void kprobe_emulate_jmp(struct kprobe *p, struct pt_regs *regs)
 {
        unsigned long ip = regs->ip - INT3_INSN_SIZE + p->ainsn.size;
 
-       if (cond)
-               ip += p->ainsn.rel32;
+       ip += p->ainsn.rel32;
        int3_emulate_jmp(regs, ip);
 }
-
-static void kprobe_emulate_jmp(struct kprobe *p, struct pt_regs *regs)
-{
-       __kprobe_emulate_jmp(p, regs, true);
-}
 NOKPROBE_SYMBOL(kprobe_emulate_jmp);
 
-static const unsigned long jcc_mask[6] = {
-       [0] = X86_EFLAGS_OF,
-       [1] = X86_EFLAGS_CF,
-       [2] = X86_EFLAGS_ZF,
-       [3] = X86_EFLAGS_CF | X86_EFLAGS_ZF,
-       [4] = X86_EFLAGS_SF,
-       [5] = X86_EFLAGS_PF,
-};
-
 static void kprobe_emulate_jcc(struct kprobe *p, struct pt_regs *regs)
 {
-       bool invert = p->ainsn.jcc.type & 1;
-       bool match;
+       unsigned long ip = regs->ip - INT3_INSN_SIZE + p->ainsn.size;
 
-       if (p->ainsn.jcc.type < 0xc) {
-               match = regs->flags & jcc_mask[p->ainsn.jcc.type >> 1];
-       } else {
-               match = ((regs->flags & X86_EFLAGS_SF) >> X86_EFLAGS_SF_BIT) ^
-                       ((regs->flags & X86_EFLAGS_OF) >> X86_EFLAGS_OF_BIT);
-               if (p->ainsn.jcc.type >= 0xe)
-                       match = match || (regs->flags & X86_EFLAGS_ZF);
-       }
-       __kprobe_emulate_jmp(p, regs, (match && !invert) || (!match && invert));
+       int3_emulate_jcc(regs, p->ainsn.jcc.type, ip, p->ainsn.rel32);
 }
 NOKPROBE_SYMBOL(kprobe_emulate_jcc);
 
 static void kprobe_emulate_loop(struct kprobe *p, struct pt_regs *regs)
 {
+       unsigned long ip = regs->ip - INT3_INSN_SIZE + p->ainsn.size;
        bool match;
 
        if (p->ainsn.loop.type != 3) {  /* LOOP* */
@@ -542,7 +518,9 @@ static void kprobe_emulate_loop(struct kprobe *p, struct pt_regs *regs)
        else if (p->ainsn.loop.type == 1)       /* LOOPE */
                match = match && (regs->flags & X86_EFLAGS_ZF);
 
-       __kprobe_emulate_jmp(p, regs, match);
+       if (match)
+               ip += p->ainsn.rel32;
+       int3_emulate_jmp(regs, ip);
 }
 NOKPROBE_SYMBOL(kprobe_emulate_loop);