]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
x86/alternatives: Add and use text_gen_insn() helper
authorPeter Zijlstra <peterz@infradead.org>
Thu, 3 Oct 2019 12:50:42 +0000 (14:50 +0200)
committerIngo Molnar <mingo@kernel.org>
Wed, 27 Nov 2019 06:44:24 +0000 (07:44 +0100)
Provide a simple helper function to create common instruction
encodings.

Tested-by: Alexei Starovoitov <ast@kernel.org>
Tested-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Daniel Bristot de Oliveira <bristot@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: https://lkml.kernel.org/r/20191111132457.703538332@infradead.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/include/asm/text-patching.h
arch/x86/kernel/alternative.c
arch/x86/kernel/jump_label.c
arch/x86/kernel/kprobes/opt.c

index 3bcd26623a1fa0ab582b319722c5c8d113bc90b2..95beb85aef65a75e3b3d04915a1ddc31bc54cd1a 100644 (file)
@@ -49,6 +49,8 @@ extern void text_poke_bp(void *addr, const void *opcode, size_t len, const void
 extern void text_poke_queue(void *addr, const void *opcode, size_t len, const void *emulate);
 extern void text_poke_finish(void);
 
+extern void *text_gen_insn(u8 opcode, const void *addr, const void *dest);
+
 extern int after_bootmem;
 extern __ro_after_init struct mm_struct *poking_mm;
 extern __ro_after_init unsigned long poking_addr;
index 42e7f0af88da29575f7d0e8f5ec4d6f0717ba60f..714b4a2a6f81ae6f3289b7557daa3e3fa88ebe7d 100644 (file)
@@ -1237,3 +1237,39 @@ void text_poke_bp(void *addr, const void *opcode, size_t len, const void *emulat
        text_poke_loc_init(&tp, addr, opcode, len, emulate);
        text_poke_bp_batch(&tp, 1);
 }
+
+union text_poke_insn {
+       u8 text[POKE_MAX_OPCODE_SIZE];
+       struct {
+               u8 opcode;
+               s32 disp;
+       } __attribute__((packed));
+};
+
+void *text_gen_insn(u8 opcode, const void *addr, const void *dest)
+{
+       static union text_poke_insn insn; /* text_mutex */
+       int size = 0;
+
+       lockdep_assert_held(&text_mutex);
+
+       insn.opcode = opcode;
+
+#define __CASE(insn)   \
+       case insn##_INSN_OPCODE: size = insn##_INSN_SIZE; break
+
+       switch(opcode) {
+       __CASE(INT3);
+       __CASE(CALL);
+       __CASE(JMP32);
+       __CASE(JMP8);
+       }
+
+       if (size > 1) {
+               insn.disp = (long)dest - (long)(addr + size);
+               if (size == 2)
+                       BUG_ON((insn.disp >> 31) != (insn.disp >> 7));
+       }
+
+       return &insn.text;
+}
index cf8c847c7b5d81d3fb46f5b78363cc564edc4a17..9c4498ea0b3c0d212d2d21ab20ca6cae309ef729 100644 (file)
 #include <asm/alternative.h>
 #include <asm/text-patching.h>
 
-union jump_code_union {
-       char code[JUMP_LABEL_NOP_SIZE];
-       struct {
-               char jump;
-               int offset;
-       } __attribute__((packed));
-};
-
-static void bug_at(unsigned char *ip, int line)
+static void bug_at(const void *ip, int line)
 {
        /*
         * The location is not an op that we were expecting.
@@ -38,33 +30,32 @@ static void bug_at(unsigned char *ip, int line)
 static const void *
 __jump_label_set_jump_code(struct jump_entry *entry, enum jump_label_type type, int init)
 {
-       static union jump_code_union code; /* relies on text_mutex */
        const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP };
        const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5];
-       const void *expect;
+       const void *expect, *code;
+       const void *addr, *dest;
        int line;
 
-       lockdep_assert_held(&text_mutex);
+       addr = (void *)jump_entry_code(entry);
+       dest = (void *)jump_entry_target(entry);
 
-       code.jump = JMP32_INSN_OPCODE;
-       code.offset = jump_entry_target(entry) -
-                      (jump_entry_code(entry) + JUMP_LABEL_NOP_SIZE);
+       code = text_gen_insn(JMP32_INSN_OPCODE, addr, dest);
 
        if (init) {
                expect = default_nop; line = __LINE__;
        } else if (type == JUMP_LABEL_JMP) {
                expect = ideal_nop; line = __LINE__;
        } else {
-               expect = code.code; line = __LINE__;
+               expect = code; line = __LINE__;
        }
 
-       if (memcmp((void *)jump_entry_code(entry), expect, JUMP_LABEL_NOP_SIZE))
-               bug_at((void *)jump_entry_code(entry), line);
+       if (memcmp(addr, expect, JUMP_LABEL_NOP_SIZE))
+               bug_at(addr, line);
 
        if (type == JUMP_LABEL_NOP)
-               memcpy(&code, ideal_nop, JUMP_LABEL_NOP_SIZE);
+               code = ideal_nop;
 
-       return &code;
+       return code;
 }
 
 static void inline __jump_label_transform(struct jump_entry *entry,
index 8900329c28a7104f68a4a38c8816e3d9dc6c5edd..9b01ee7b3923a8da5ef4fc8dc0d0c02e43d49cbd 100644 (file)
@@ -447,18 +447,13 @@ void arch_optimize_kprobes(struct list_head *oplist)
 void arch_unoptimize_kprobe(struct optimized_kprobe *op)
 {
        u8 insn_buff[RELATIVEJUMP_SIZE];
-       u8 emulate_buff[RELATIVEJUMP_SIZE];
 
        /* Set int3 to first byte for kprobes */
        insn_buff[0] = BREAKPOINT_INSTRUCTION;
        memcpy(insn_buff + 1, op->optinsn.copied_insn, RELATIVE_ADDR_SIZE);
 
-       emulate_buff[0] = RELATIVEJUMP_OPCODE;
-       *(s32 *)(&emulate_buff[1]) = (s32)((long)op->optinsn.insn -
-                       ((long)op->kp.addr + RELATIVEJUMP_SIZE));
-
        text_poke_bp(op->kp.addr, insn_buff, RELATIVEJUMP_SIZE,
-                    emulate_buff);
+                    text_gen_insn(JMP32_INSN_OPCODE, op->kp.addr, op->optinsn.insn));
 }
 
 /*