1 // SPDX-License-Identifier: GPL-2.0-or-later 1 2 /* 3 * x86 implementation of rethook. Mostly copie 4 */ 5 #include <linux/bug.h> 6 #include <linux/rethook.h> 7 #include <linux/kprobes.h> 8 #include <linux/objtool.h> 9 10 #include "kprobes/common.h" 11 12 __visible void arch_rethook_trampoline_callbac 13 14 #ifndef ANNOTATE_NOENDBR 15 #define ANNOTATE_NOENDBR 16 #endif 17 18 /* 19 * When a target function returns, this code s 20 * arch_rethook_trampoline_callback(), which c 21 */ 22 asm( 23 ".text\n" 24 ".global arch_rethook_trampoline\n" 25 ".type arch_rethook_trampoline, @funct 26 "arch_rethook_trampoline:\n" 27 #ifdef CONFIG_X86_64 28 ANNOTATE_NOENDBR /* This is onl 29 /* Push a fake return address to tell 30 " pushq $arch_rethook_trampoline 31 UNWIND_HINT_FUNC 32 " pushq $" __stringify(__KERNEL_ 33 /* Save the 'sp - 16', this will be fi 34 " pushq %rsp\n" 35 " pushfq\n" 36 SAVE_REGS_STRING 37 " movq %rsp, %rdi\n" 38 " call arch_rethook_trampoline_c 39 RESTORE_REGS_STRING 40 /* In the callback function, 'regs->fl 41 " addq $16, %rsp\n" 42 " popfq\n" 43 #else 44 /* Push a fake return address to tell 45 " pushl $arch_rethook_trampoline 46 UNWIND_HINT_FUNC 47 " pushl %ss\n" 48 /* Save the 'sp - 8', this will be fix 49 " pushl %esp\n" 50 " pushfl\n" 51 SAVE_REGS_STRING 52 " movl %esp, %eax\n" 53 " call arch_rethook_trampoline_c 54 RESTORE_REGS_STRING 55 /* In the callback function, 'regs->fl 56 " addl $8, %esp\n" 57 " popfl\n" 58 #endif 59 ASM_RET 60 ".size arch_rethook_trampoline, .-arch 61 ); 62 NOKPROBE_SYMBOL(arch_rethook_trampoline); 63 64 /* 65 * Called from arch_rethook_trampoline 66 */ 67 __used __visible void arch_rethook_trampoline_ 68 { 69 unsigned long *frame_pointer; 70 71 /* fixup registers */ 72 regs->cs = __KERNEL_CS; 73 #ifdef CONFIG_X86_32 74 regs->gs = 0; 75 #endif 76 regs->ip = (unsigned long)&arch_rethoo 77 regs->orig_ax = ~0UL; 78 regs->sp += 2*sizeof(long); 79 frame_pointer = (long *)(regs + 1); 80 81 /* 82 * The return address at 'frame_pointe 83 * arch_rethook_fixup_return() which c 84 * rethook_trampoline_handler(). 85 */ 86 rethook_trampoline_handler(regs, (unsi 87 88 /* 89 * Copy FLAGS to 'pt_regs::ss' so that 90 * can do RET right after POPF. 91 */ 92 *(unsigned long *)®s->ss = regs->fl 93 } 94 NOKPROBE_SYMBOL(arch_rethook_trampoline_callba 95 96 /* 97 * arch_rethook_trampoline() skips updating fr 98 * saved in arch_rethook_trampoline_callback() 99 * function's frame pointer. Thus the arch_ret 100 * a standard stack frame with CONFIG_FRAME_PO 101 * Let's mark it non-standard function. Anyway 102 * unwind without the hint. 103 */ 104 STACK_FRAME_NON_STANDARD_FP(arch_rethook_tramp 105 106 /* This is called from rethook_trampoline_hand 107 void arch_rethook_fixup_return(struct pt_regs 108 unsigned long c 109 { 110 unsigned long *frame_pointer = (void * 111 112 /* Replace fake return address with re 113 *frame_pointer = correct_ret_addr; 114 } 115 NOKPROBE_SYMBOL(arch_rethook_fixup_return); 116 117 void arch_rethook_prepare(struct rethook_node 118 { 119 unsigned long *stack = (unsigned long 120 121 rh->ret_addr = stack[0]; 122 rh->frame = regs->sp; 123 124 /* Replace the return addr with trampo 125 stack[0] = (unsigned long) arch_rethoo 126 } 127 NOKPROBE_SYMBOL(arch_rethook_prepare); 128
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.