Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0 */ 2 : : #ifndef _ASM_X86_TEXT_PATCHING_H 3 : : #define _ASM_X86_TEXT_PATCHING_H 4 : : 5 : : #include <linux/types.h> 6 : : #include <linux/stddef.h> 7 : : #include <asm/ptrace.h> 8 : : 9 : : struct paravirt_patch_site; 10 : : #ifdef CONFIG_PARAVIRT 11 : : void apply_paravirt(struct paravirt_patch_site *start, 12 : : struct paravirt_patch_site *end); 13 : : #else 14 : : static inline void apply_paravirt(struct paravirt_patch_site *start, 15 : : struct paravirt_patch_site *end) 16 : : {} 17 : : #define __parainstructions NULL 18 : : #define __parainstructions_end NULL 19 : : #endif 20 : : 21 : : /* 22 : : * Currently, the max observed size in the kernel code is 23 : : * JUMP_LABEL_NOP_SIZE/RELATIVEJUMP_SIZE, which are 5. 24 : : * Raise it if needed. 25 : : */ 26 : : #define POKE_MAX_OPCODE_SIZE 5 27 : : 28 : : extern void text_poke_early(void *addr, const void *opcode, size_t len); 29 : : 30 : : /* 31 : : * Clear and restore the kernel write-protection flag on the local CPU. 32 : : * Allows the kernel to edit read-only pages. 33 : : * Side-effect: any interrupt handler running between save and restore will have 34 : : * the ability to write to read-only pages. 35 : : * 36 : : * Warning: 37 : : * Code patching in the UP case is safe if NMIs and MCE handlers are stopped and 38 : : * no thread can be preempted in the instructions being modified (no iret to an 39 : : * invalid instruction possible) or if the instructions are changed from a 40 : : * consistent state to another consistent state atomically. 41 : : * On the local CPU you need to be protected against NMI or MCE handlers seeing 42 : : * an inconsistent instruction while you patch. 43 : : */ 44 : : extern void *text_poke(void *addr, const void *opcode, size_t len); 45 : : extern void text_poke_sync(void); 46 : : extern void *text_poke_kgdb(void *addr, const void *opcode, size_t len); 47 : : extern int poke_int3_handler(struct pt_regs *regs); 48 : : extern void text_poke_bp(void *addr, const void *opcode, size_t len, const void *emulate); 49 : : 50 : : extern void text_poke_queue(void *addr, const void *opcode, size_t len, const void *emulate); 51 : : extern void text_poke_finish(void); 52 : : 53 : : #define INT3_INSN_SIZE 1 54 : : #define INT3_INSN_OPCODE 0xCC 55 : : 56 : : #define CALL_INSN_SIZE 5 57 : : #define CALL_INSN_OPCODE 0xE8 58 : : 59 : : #define JMP32_INSN_SIZE 5 60 : : #define JMP32_INSN_OPCODE 0xE9 61 : : 62 : : #define JMP8_INSN_SIZE 2 63 : : #define JMP8_INSN_OPCODE 0xEB 64 : : 65 : : #define DISP32_SIZE 4 66 : : 67 : 37531 : static inline int text_opcode_size(u8 opcode) 68 : : { 69 : 37531 : int size = 0; 70 : : 71 : : #define __CASE(insn) \ 72 : : case insn##_INSN_OPCODE: size = insn##_INSN_SIZE; break 73 : : 74 [ + - - - ]: 37531 : switch(opcode) { 75 : : __CASE(INT3); 76 : : __CASE(CALL); 77 : : __CASE(JMP32); 78 : : __CASE(JMP8); 79 : : } 80 : : 81 : : #undef __CASE 82 : : 83 [ + - - - : 37531 : return size; - - ] 84 : : } 85 : : 86 : : union text_poke_insn { 87 : : u8 text[POKE_MAX_OPCODE_SIZE]; 88 : : struct { 89 : : u8 opcode; 90 : : s32 disp; 91 : : } __attribute__((packed)); 92 : : }; 93 : : 94 : : static __always_inline 95 : 36816 : void *text_gen_insn(u8 opcode, const void *addr, const void *dest) 96 : : { 97 : 36816 : static union text_poke_insn insn; /* per instance */ 98 : 36816 : int size = text_opcode_size(opcode); 99 : : 100 : 36816 : insn.opcode = opcode; 101 : : 102 : 36816 : if (size > 1) { 103 : 36816 : insn.disp = (long)dest - (long)(addr + size); 104 : 36816 : if (size == 2) { 105 : : /* 106 : : * Ensure that for JMP9 the displacement 107 : : * actually fits the signed byte. 108 : : */ 109 : 36816 : BUG_ON((insn.disp >> 31) != (insn.disp >> 7)); 110 : : } 111 : : } 112 : : 113 [ + + ]: 36816 : return &insn.text; 114 : : } 115 : : 116 : : extern int after_bootmem; 117 : : extern __ro_after_init struct mm_struct *poking_mm; 118 : : extern __ro_after_init unsigned long poking_addr; 119 : : 120 : : #ifndef CONFIG_UML_X86 121 : 13 : static inline void int3_emulate_jmp(struct pt_regs *regs, unsigned long ip) 122 : : { 123 : 13 : regs->ip = ip; 124 : 0 : } 125 : : 126 : 13 : static inline void int3_emulate_push(struct pt_regs *regs, unsigned long val) 127 : : { 128 : : /* 129 : : * The int3 handler in entry_64.S adds a gap between the 130 : : * stack where the break point happened, and the saving of 131 : : * pt_regs. We can extend the original stack because of 132 : : * this gap. See the idtentry macro's create_gap option. 133 : : * 134 : : * Similarly entry_32.S will have a gap on the stack for (any) hardware 135 : : * exception and pt_regs; see FIXUP_FRAME. 136 : : */ 137 : 13 : regs->sp -= sizeof(unsigned long); 138 : 13 : *(unsigned long *)regs->sp = val; 139 : : } 140 : : 141 : 13 : static inline void int3_emulate_call(struct pt_regs *regs, unsigned long func) 142 : : { 143 : 13 : int3_emulate_push(regs, regs->ip - INT3_INSN_SIZE + CALL_INSN_SIZE); 144 : 13 : int3_emulate_jmp(regs, func); 145 : 0 : } 146 : : #endif /* !CONFIG_UML_X86 */ 147 : : 148 : : #endif /* _ASM_X86_TEXT_PATCHING_H */