xref: /linux/arch/x86/kernel/kprobes/opt.c (revision aefb2f2e)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f684199fSMasami Hiramatsu /*
3f684199fSMasami Hiramatsu  *  Kernel Probes Jump Optimization (Optprobes)
4f684199fSMasami Hiramatsu  *
5f684199fSMasami Hiramatsu  * Copyright (C) IBM Corporation, 2002, 2004
6f684199fSMasami Hiramatsu  * Copyright (C) Hitachi Ltd., 2012
7f684199fSMasami Hiramatsu  */
8f684199fSMasami Hiramatsu #include <linux/kprobes.h>
93e46bb40SAdrian Hunter #include <linux/perf_event.h>
10f684199fSMasami Hiramatsu #include <linux/ptrace.h>
11f684199fSMasami Hiramatsu #include <linux/string.h>
12f684199fSMasami Hiramatsu #include <linux/slab.h>
13f684199fSMasami Hiramatsu #include <linux/hardirq.h>
14f684199fSMasami Hiramatsu #include <linux/preempt.h>
15744c193eSPaul Gortmaker #include <linux/extable.h>
16f684199fSMasami Hiramatsu #include <linux/kdebug.h>
17f684199fSMasami Hiramatsu #include <linux/kallsyms.h>
1863dc6325SMasami Hiramatsu (Google) #include <linux/kgdb.h>
19f684199fSMasami Hiramatsu #include <linux/ftrace.h>
2000089c04SJulien Thierry #include <linux/objtool.h>
2165fddcfcSMike Rapoport #include <linux/pgtable.h>
226333e8f7SPeter Zijlstra #include <linux/static_call.h>
23f684199fSMasami Hiramatsu 
2435de5b06SAndy Lutomirski #include <asm/text-patching.h>
25f684199fSMasami Hiramatsu #include <asm/cacheflush.h>
26f684199fSMasami Hiramatsu #include <asm/desc.h>
277c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
28f684199fSMasami Hiramatsu #include <asm/alternative.h>
29f684199fSMasami Hiramatsu #include <asm/insn.h>
30f684199fSMasami Hiramatsu #include <asm/debugreg.h>
31e6ccbff0SLaura Abbott #include <asm/set_memory.h>
32d9f5f32aSMasami Hiramatsu #include <asm/sections.h>
33c86a32c0SMasami Hiramatsu #include <asm/nospec-branch.h>
34f684199fSMasami Hiramatsu 
35f684199fSMasami Hiramatsu #include "common.h"
36f684199fSMasami Hiramatsu 
__recover_optprobed_insn(kprobe_opcode_t * buf,unsigned long addr)37f684199fSMasami Hiramatsu unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr)
38f684199fSMasami Hiramatsu {
39f684199fSMasami Hiramatsu 	struct optimized_kprobe *op;
40f684199fSMasami Hiramatsu 	struct kprobe *kp;
41f684199fSMasami Hiramatsu 	long offs;
42f684199fSMasami Hiramatsu 	int i;
43f684199fSMasami Hiramatsu 
44ab09e95cSPeter Zijlstra 	for (i = 0; i < JMP32_INSN_SIZE; i++) {
45f684199fSMasami Hiramatsu 		kp = get_kprobe((void *)addr - i);
46f684199fSMasami Hiramatsu 		/* This function only handles jump-optimized kprobe */
47f684199fSMasami Hiramatsu 		if (kp && kprobe_optimized(kp)) {
48f684199fSMasami Hiramatsu 			op = container_of(kp, struct optimized_kprobe, kp);
49868a6fc0SYang Jihong 			/* If op is optimized or under unoptimizing */
50868a6fc0SYang Jihong 			if (list_empty(&op->list) || optprobe_queued_unopt(op))
51f684199fSMasami Hiramatsu 				goto found;
52f684199fSMasami Hiramatsu 		}
53f684199fSMasami Hiramatsu 	}
54f684199fSMasami Hiramatsu 
55f684199fSMasami Hiramatsu 	return addr;
56f684199fSMasami Hiramatsu found:
57f684199fSMasami Hiramatsu 	/*
58f684199fSMasami Hiramatsu 	 * If the kprobe can be optimized, original bytes which can be
59f684199fSMasami Hiramatsu 	 * overwritten by jump destination address. In this case, original
60f684199fSMasami Hiramatsu 	 * bytes must be recovered from op->optinsn.copied_insn buffer.
61f684199fSMasami Hiramatsu 	 */
62fe557319SChristoph Hellwig 	if (copy_from_kernel_nofault(buf, (void *)addr,
63ea1e34fcSMasami Hiramatsu 		MAX_INSN_SIZE * sizeof(kprobe_opcode_t)))
64ea1e34fcSMasami Hiramatsu 		return 0UL;
65ea1e34fcSMasami Hiramatsu 
66f684199fSMasami Hiramatsu 	if (addr == (unsigned long)kp->addr) {
67f684199fSMasami Hiramatsu 		buf[0] = kp->opcode;
68ab09e95cSPeter Zijlstra 		memcpy(buf + 1, op->optinsn.copied_insn, DISP32_SIZE);
69f684199fSMasami Hiramatsu 	} else {
70f684199fSMasami Hiramatsu 		offs = addr - (unsigned long)kp->addr - 1;
71ab09e95cSPeter Zijlstra 		memcpy(buf, op->optinsn.copied_insn + offs, DISP32_SIZE - offs);
72f684199fSMasami Hiramatsu 	}
73f684199fSMasami Hiramatsu 
74f684199fSMasami Hiramatsu 	return (unsigned long)buf;
75f684199fSMasami Hiramatsu }
76f684199fSMasami Hiramatsu 
synthesize_clac(kprobe_opcode_t * addr)77d8a73868SPeter Zijlstra static void synthesize_clac(kprobe_opcode_t *addr)
78d8a73868SPeter Zijlstra {
79d8a73868SPeter Zijlstra 	/*
80d8a73868SPeter Zijlstra 	 * Can't be static_cpu_has() due to how objtool treats this feature bit.
81d8a73868SPeter Zijlstra 	 * This isn't a fast path anyway.
82d8a73868SPeter Zijlstra 	 */
83d8a73868SPeter Zijlstra 	if (!boot_cpu_has(X86_FEATURE_SMAP))
84d8a73868SPeter Zijlstra 		return;
85d8a73868SPeter Zijlstra 
86d8a73868SPeter Zijlstra 	/* Replace the NOP3 with CLAC */
87d8a73868SPeter Zijlstra 	addr[0] = 0x0f;
88d8a73868SPeter Zijlstra 	addr[1] = 0x01;
89d8a73868SPeter Zijlstra 	addr[2] = 0xca;
90d8a73868SPeter Zijlstra }
91d8a73868SPeter Zijlstra 
92f684199fSMasami Hiramatsu /* Insert a move instruction which sets a pointer to eax/rdi (1st arg). */
synthesize_set_arg1(kprobe_opcode_t * addr,unsigned long val)937ec8a97aSMasami Hiramatsu static void synthesize_set_arg1(kprobe_opcode_t *addr, unsigned long val)
94f684199fSMasami Hiramatsu {
95f684199fSMasami Hiramatsu #ifdef CONFIG_X86_64
96f684199fSMasami Hiramatsu 	*addr++ = 0x48;
97f684199fSMasami Hiramatsu 	*addr++ = 0xbf;
98f684199fSMasami Hiramatsu #else
99f684199fSMasami Hiramatsu 	*addr++ = 0xb8;
100f684199fSMasami Hiramatsu #endif
101f684199fSMasami Hiramatsu 	*(unsigned long *)addr = val;
102f684199fSMasami Hiramatsu }
103f684199fSMasami Hiramatsu 
10404bb591cSAndi Kleen asm (
105877b145fSMasami Hiramatsu 			".pushsection .rodata\n"
106c207aee4SJosh Poimboeuf 			"optprobe_template_func:\n"
107f684199fSMasami Hiramatsu 			".global optprobe_template_entry\n"
108f684199fSMasami Hiramatsu 			"optprobe_template_entry:\n"
109f684199fSMasami Hiramatsu #ifdef CONFIG_X86_64
11045c23bf4SMasami Hiramatsu 			"       pushq $" __stringify(__KERNEL_DS) "\n"
11145c23bf4SMasami Hiramatsu 			/* Save the 'sp - 8', this will be fixed later. */
112f684199fSMasami Hiramatsu 			"	pushq %rsp\n"
113f684199fSMasami Hiramatsu 			"	pushfq\n"
114d8a73868SPeter Zijlstra 			".global optprobe_template_clac\n"
115d8a73868SPeter Zijlstra 			"optprobe_template_clac:\n"
116d8a73868SPeter Zijlstra 			ASM_NOP3
117f684199fSMasami Hiramatsu 			SAVE_REGS_STRING
118f684199fSMasami Hiramatsu 			"	movq %rsp, %rsi\n"
119f684199fSMasami Hiramatsu 			".global optprobe_template_val\n"
120f684199fSMasami Hiramatsu 			"optprobe_template_val:\n"
121f684199fSMasami Hiramatsu 			ASM_NOP5
122f684199fSMasami Hiramatsu 			ASM_NOP5
123f684199fSMasami Hiramatsu 			".global optprobe_template_call\n"
124f684199fSMasami Hiramatsu 			"optprobe_template_call:\n"
125f684199fSMasami Hiramatsu 			ASM_NOP5
12645c23bf4SMasami Hiramatsu 			/* Copy 'regs->flags' into 'regs->ss'. */
1273c88c692SPeter Zijlstra 			"	movq 18*8(%rsp), %rdx\n"
12845c23bf4SMasami Hiramatsu 			"	movq %rdx, 20*8(%rsp)\n"
129f684199fSMasami Hiramatsu 			RESTORE_REGS_STRING
13045c23bf4SMasami Hiramatsu 			/* Skip 'regs->flags' and 'regs->sp'. */
13145c23bf4SMasami Hiramatsu 			"	addq $16, %rsp\n"
13245c23bf4SMasami Hiramatsu 			/* And pop flags register from 'regs->ss'. */
133f684199fSMasami Hiramatsu 			"	popfq\n"
134f684199fSMasami Hiramatsu #else /* CONFIG_X86_32 */
13545c23bf4SMasami Hiramatsu 			"	pushl %ss\n"
13645c23bf4SMasami Hiramatsu 			/* Save the 'sp - 4', this will be fixed later. */
1373c88c692SPeter Zijlstra 			"	pushl %esp\n"
1383c88c692SPeter Zijlstra 			"	pushfl\n"
139d8a73868SPeter Zijlstra 			".global optprobe_template_clac\n"
140d8a73868SPeter Zijlstra 			"optprobe_template_clac:\n"
141d8a73868SPeter Zijlstra 			ASM_NOP3
142f684199fSMasami Hiramatsu 			SAVE_REGS_STRING
143f684199fSMasami Hiramatsu 			"	movl %esp, %edx\n"
144f684199fSMasami Hiramatsu 			".global optprobe_template_val\n"
145f684199fSMasami Hiramatsu 			"optprobe_template_val:\n"
146f684199fSMasami Hiramatsu 			ASM_NOP5
147f684199fSMasami Hiramatsu 			".global optprobe_template_call\n"
148f684199fSMasami Hiramatsu 			"optprobe_template_call:\n"
149f684199fSMasami Hiramatsu 			ASM_NOP5
15045c23bf4SMasami Hiramatsu 			/* Copy 'regs->flags' into 'regs->ss'. */
1513c88c692SPeter Zijlstra 			"	movl 14*4(%esp), %edx\n"
15245c23bf4SMasami Hiramatsu 			"	movl %edx, 16*4(%esp)\n"
153f684199fSMasami Hiramatsu 			RESTORE_REGS_STRING
15445c23bf4SMasami Hiramatsu 			/* Skip 'regs->flags' and 'regs->sp'. */
15545c23bf4SMasami Hiramatsu 			"	addl $8, %esp\n"
15645c23bf4SMasami Hiramatsu 			/* And pop flags register from 'regs->ss'. */
1573c88c692SPeter Zijlstra 			"	popfl\n"
158f684199fSMasami Hiramatsu #endif
159f684199fSMasami Hiramatsu 			".global optprobe_template_end\n"
160c207aee4SJosh Poimboeuf 			"optprobe_template_end:\n"
161877b145fSMasami Hiramatsu 			".popsection\n");
162c207aee4SJosh Poimboeuf 
163c207aee4SJosh Poimboeuf void optprobe_template_func(void);
164c207aee4SJosh Poimboeuf STACK_FRAME_NON_STANDARD(optprobe_template_func);
165f684199fSMasami Hiramatsu 
166d8a73868SPeter Zijlstra #define TMPL_CLAC_IDX \
167d8a73868SPeter Zijlstra 	((long)optprobe_template_clac - (long)optprobe_template_entry)
168f684199fSMasami Hiramatsu #define TMPL_MOVE_IDX \
169a8976fc8SMasami Hiramatsu 	((long)optprobe_template_val - (long)optprobe_template_entry)
170f684199fSMasami Hiramatsu #define TMPL_CALL_IDX \
171a8976fc8SMasami Hiramatsu 	((long)optprobe_template_call - (long)optprobe_template_entry)
172f684199fSMasami Hiramatsu #define TMPL_END_IDX \
173a8976fc8SMasami Hiramatsu 	((long)optprobe_template_end - (long)optprobe_template_entry)
174f684199fSMasami Hiramatsu 
175f684199fSMasami Hiramatsu /* Optimized kprobe call back function: called from optinsn */
1769326638cSMasami Hiramatsu static void
optimized_callback(struct optimized_kprobe * op,struct pt_regs * regs)1779326638cSMasami Hiramatsu optimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
178f684199fSMasami Hiramatsu {
179f684199fSMasami Hiramatsu 	/* This is possible if op is under delayed unoptimizing */
180f684199fSMasami Hiramatsu 	if (kprobe_disabled(&op->kp))
181f684199fSMasami Hiramatsu 		return;
182f684199fSMasami Hiramatsu 
1839a09f261SMasami Hiramatsu 	preempt_disable();
184f684199fSMasami Hiramatsu 	if (kprobe_running()) {
185f684199fSMasami Hiramatsu 		kprobes_inc_nmissed_count(&op->kp);
186f684199fSMasami Hiramatsu 	} else {
187cd52edadSMasami Hiramatsu 		struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
18845c23bf4SMasami Hiramatsu 		/* Adjust stack pointer */
18945c23bf4SMasami Hiramatsu 		regs->sp += sizeof(long);
190f684199fSMasami Hiramatsu 		/* Save skipped registers */
191f684199fSMasami Hiramatsu 		regs->cs = __KERNEL_CS;
1923c88c692SPeter Zijlstra #ifdef CONFIG_X86_32
193f684199fSMasami Hiramatsu 		regs->gs = 0;
194f684199fSMasami Hiramatsu #endif
195ab09e95cSPeter Zijlstra 		regs->ip = (unsigned long)op->kp.addr + INT3_INSN_SIZE;
196f684199fSMasami Hiramatsu 		regs->orig_ax = ~0UL;
197f684199fSMasami Hiramatsu 
198f684199fSMasami Hiramatsu 		__this_cpu_write(current_kprobe, &op->kp);
199f684199fSMasami Hiramatsu 		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
200f684199fSMasami Hiramatsu 		opt_pre_handler(&op->kp, regs);
201f684199fSMasami Hiramatsu 		__this_cpu_write(current_kprobe, NULL);
202f684199fSMasami Hiramatsu 	}
2032e62024cSMasami Hiramatsu 	preempt_enable();
204f684199fSMasami Hiramatsu }
2059326638cSMasami Hiramatsu NOKPROBE_SYMBOL(optimized_callback);
206f684199fSMasami Hiramatsu 
copy_optimized_instructions(u8 * dest,u8 * src,u8 * real)20763fef14fSMasami Hiramatsu static int copy_optimized_instructions(u8 *dest, u8 *src, u8 *real)
208f684199fSMasami Hiramatsu {
209a8d11cd0SMasami Hiramatsu 	struct insn insn;
210f684199fSMasami Hiramatsu 	int len = 0, ret;
211f684199fSMasami Hiramatsu 
212ab09e95cSPeter Zijlstra 	while (len < JMP32_INSN_SIZE) {
21343a1b0cbSMasami Hiramatsu 		ret = __copy_instruction(dest + len, src + len, real + len, &insn);
214a8d11cd0SMasami Hiramatsu 		if (!ret || !can_boost(&insn, src + len))
215f684199fSMasami Hiramatsu 			return -EINVAL;
216f684199fSMasami Hiramatsu 		len += ret;
217f684199fSMasami Hiramatsu 	}
218f684199fSMasami Hiramatsu 	/* Check whether the address range is reserved */
219f684199fSMasami Hiramatsu 	if (ftrace_text_reserved(src, src + len - 1) ||
220f684199fSMasami Hiramatsu 	    alternatives_text_reserved(src, src + len - 1) ||
2216333e8f7SPeter Zijlstra 	    jump_label_text_reserved(src, src + len - 1) ||
2226333e8f7SPeter Zijlstra 	    static_call_text_reserved(src, src + len - 1))
223f684199fSMasami Hiramatsu 		return -EBUSY;
224f684199fSMasami Hiramatsu 
225f684199fSMasami Hiramatsu 	return len;
226f684199fSMasami Hiramatsu }
227f684199fSMasami Hiramatsu 
228f684199fSMasami Hiramatsu /* Check whether insn is indirect jump */
insn_is_indirect_jump(struct insn * insn)229833fd800SPetr Pavlu static int insn_is_indirect_jump(struct insn *insn)
230f684199fSMasami Hiramatsu {
231f684199fSMasami Hiramatsu 	return ((insn->opcode.bytes[0] == 0xff &&
232f684199fSMasami Hiramatsu 		(X86_MODRM_REG(insn->modrm.value) & 6) == 4) || /* Jump */
233f684199fSMasami Hiramatsu 		insn->opcode.bytes[0] == 0xea);	/* Segment based jump */
234f684199fSMasami Hiramatsu }
235f684199fSMasami Hiramatsu 
236f684199fSMasami Hiramatsu /* Check whether insn jumps into specified address range */
insn_jump_into_range(struct insn * insn,unsigned long start,int len)237f684199fSMasami Hiramatsu static int insn_jump_into_range(struct insn *insn, unsigned long start, int len)
238f684199fSMasami Hiramatsu {
239f684199fSMasami Hiramatsu 	unsigned long target = 0;
240f684199fSMasami Hiramatsu 
241f684199fSMasami Hiramatsu 	switch (insn->opcode.bytes[0]) {
242f684199fSMasami Hiramatsu 	case 0xe0:	/* loopne */
243f684199fSMasami Hiramatsu 	case 0xe1:	/* loope */
244f684199fSMasami Hiramatsu 	case 0xe2:	/* loop */
245f684199fSMasami Hiramatsu 	case 0xe3:	/* jcxz */
246f684199fSMasami Hiramatsu 	case 0xe9:	/* near relative jump */
247f684199fSMasami Hiramatsu 	case 0xeb:	/* short relative jump */
248f684199fSMasami Hiramatsu 		break;
249f684199fSMasami Hiramatsu 	case 0x0f:
250f684199fSMasami Hiramatsu 		if ((insn->opcode.bytes[1] & 0xf0) == 0x80) /* jcc near */
251f684199fSMasami Hiramatsu 			break;
252f684199fSMasami Hiramatsu 		return 0;
253f684199fSMasami Hiramatsu 	default:
254f684199fSMasami Hiramatsu 		if ((insn->opcode.bytes[0] & 0xf0) == 0x70) /* jcc short */
255f684199fSMasami Hiramatsu 			break;
256f684199fSMasami Hiramatsu 		return 0;
257f684199fSMasami Hiramatsu 	}
258f684199fSMasami Hiramatsu 	target = (unsigned long)insn->next_byte + insn->immediate.value;
259f684199fSMasami Hiramatsu 
260f684199fSMasami Hiramatsu 	return (start <= target && target <= start + len);
261f684199fSMasami Hiramatsu }
262f684199fSMasami Hiramatsu 
263f684199fSMasami Hiramatsu /* Decode whole function to ensure any instructions don't jump into target */
can_optimize(unsigned long paddr)2647ec8a97aSMasami Hiramatsu static int can_optimize(unsigned long paddr)
265f684199fSMasami Hiramatsu {
266f684199fSMasami Hiramatsu 	unsigned long addr, size = 0, offset = 0;
267f684199fSMasami Hiramatsu 	struct insn insn;
268f684199fSMasami Hiramatsu 	kprobe_opcode_t buf[MAX_INSN_SIZE];
269f684199fSMasami Hiramatsu 
270f684199fSMasami Hiramatsu 	/* Lookup symbol including addr */
271f684199fSMasami Hiramatsu 	if (!kallsyms_lookup_size_offset(paddr, &size, &offset))
272f684199fSMasami Hiramatsu 		return 0;
273f684199fSMasami Hiramatsu 
274f684199fSMasami Hiramatsu 	/*
275f684199fSMasami Hiramatsu 	 * Do not optimize in the entry code due to the unstable
276d9f5f32aSMasami Hiramatsu 	 * stack handling and registers setup.
277f684199fSMasami Hiramatsu 	 */
278d9f5f32aSMasami Hiramatsu 	if (((paddr >= (unsigned long)__entry_text_start) &&
279f0178fc0SThomas Gleixner 	     (paddr <  (unsigned long)__entry_text_end)))
280f684199fSMasami Hiramatsu 		return 0;
281f684199fSMasami Hiramatsu 
282f684199fSMasami Hiramatsu 	/* Check there is enough space for a relative jump. */
283ab09e95cSPeter Zijlstra 	if (size - offset < JMP32_INSN_SIZE)
284f684199fSMasami Hiramatsu 		return 0;
285f684199fSMasami Hiramatsu 
286f684199fSMasami Hiramatsu 	/* Decode instructions */
287f684199fSMasami Hiramatsu 	addr = paddr - offset;
288f684199fSMasami Hiramatsu 	while (addr < paddr - offset + size) { /* Decode until function end */
2896ba48ff4SDave Hansen 		unsigned long recovered_insn;
29077e768ecSBorislav Petkov 		int ret;
29177e768ecSBorislav Petkov 
292f684199fSMasami Hiramatsu 		if (search_exception_tables(addr))
293f684199fSMasami Hiramatsu 			/*
294f684199fSMasami Hiramatsu 			 * Since some fixup code will jumps into this function,
295f684199fSMasami Hiramatsu 			 * we can't optimize kprobe in this function.
296f684199fSMasami Hiramatsu 			 */
297f684199fSMasami Hiramatsu 			return 0;
2986ba48ff4SDave Hansen 		recovered_insn = recover_probed_instruction(buf, addr);
2992a6730c8SPetr Mladek 		if (!recovered_insn)
3002a6730c8SPetr Mladek 			return 0;
30177e768ecSBorislav Petkov 
30252fa82c2SPeter Zijlstra 		ret = insn_decode_kernel(&insn, (void *)recovered_insn);
30377e768ecSBorislav Petkov 		if (ret < 0)
30477e768ecSBorislav Petkov 			return 0;
30563dc6325SMasami Hiramatsu (Google) #ifdef CONFIG_KGDB
3060d07c0ecSMasami Hiramatsu 		/*
30763dc6325SMasami Hiramatsu (Google) 		 * If there is a dynamically installed kgdb sw breakpoint,
30863dc6325SMasami Hiramatsu (Google) 		 * this function should not be probed.
3090d07c0ecSMasami Hiramatsu 		 */
31063dc6325SMasami Hiramatsu (Google) 		if (insn.opcode.bytes[0] == INT3_INSN_OPCODE &&
31163dc6325SMasami Hiramatsu (Google) 		    kgdb_has_hit_break(addr))
31263dc6325SMasami Hiramatsu (Google) 			return 0;
31363dc6325SMasami Hiramatsu (Google) #endif
314f684199fSMasami Hiramatsu 		/* Recover address */
315f684199fSMasami Hiramatsu 		insn.kaddr = (void *)addr;
316f684199fSMasami Hiramatsu 		insn.next_byte = (void *)(addr + insn.length);
317833fd800SPetr Pavlu 		/*
318833fd800SPetr Pavlu 		 * Check any instructions don't jump into target, indirectly or
319833fd800SPetr Pavlu 		 * directly.
320833fd800SPetr Pavlu 		 *
321833fd800SPetr Pavlu 		 * The indirect case is present to handle a code with jump
322833fd800SPetr Pavlu 		 * tables. When the kernel uses retpolines, the check should in
323833fd800SPetr Pavlu 		 * theory additionally look for jumps to indirect thunks.
324833fd800SPetr Pavlu 		 * However, the kernel built with retpolines or IBT has jump
325833fd800SPetr Pavlu 		 * tables disabled so the check can be skipped altogether.
326833fd800SPetr Pavlu 		 */
327*aefb2f2eSBreno Leitao 		if (!IS_ENABLED(CONFIG_MITIGATION_RETPOLINE) &&
328833fd800SPetr Pavlu 		    !IS_ENABLED(CONFIG_X86_KERNEL_IBT) &&
329833fd800SPetr Pavlu 		    insn_is_indirect_jump(&insn))
330833fd800SPetr Pavlu 			return 0;
331833fd800SPetr Pavlu 		if (insn_jump_into_range(&insn, paddr + INT3_INSN_SIZE,
332ab09e95cSPeter Zijlstra 					 DISP32_SIZE))
333f684199fSMasami Hiramatsu 			return 0;
334f684199fSMasami Hiramatsu 		addr += insn.length;
335f684199fSMasami Hiramatsu 	}
336f684199fSMasami Hiramatsu 
337f684199fSMasami Hiramatsu 	return 1;
338f684199fSMasami Hiramatsu }
339f684199fSMasami Hiramatsu 
340f684199fSMasami Hiramatsu /* Check optimized_kprobe can actually be optimized. */
arch_check_optimized_kprobe(struct optimized_kprobe * op)3417ec8a97aSMasami Hiramatsu int arch_check_optimized_kprobe(struct optimized_kprobe *op)
342f684199fSMasami Hiramatsu {
343f684199fSMasami Hiramatsu 	int i;
344f684199fSMasami Hiramatsu 	struct kprobe *p;
345f684199fSMasami Hiramatsu 
346f684199fSMasami Hiramatsu 	for (i = 1; i < op->optinsn.size; i++) {
347f684199fSMasami Hiramatsu 		p = get_kprobe(op->kp.addr + i);
348f1c97a1bSYang Jihong 		if (p && !kprobe_disarmed(p))
349f684199fSMasami Hiramatsu 			return -EEXIST;
350f684199fSMasami Hiramatsu 	}
351f684199fSMasami Hiramatsu 
352f684199fSMasami Hiramatsu 	return 0;
353f684199fSMasami Hiramatsu }
354f684199fSMasami Hiramatsu 
355f684199fSMasami Hiramatsu /* Check the addr is within the optimized instructions. */
arch_within_optimized_kprobe(struct optimized_kprobe * op,kprobe_opcode_t * addr)3567ec8a97aSMasami Hiramatsu int arch_within_optimized_kprobe(struct optimized_kprobe *op,
357c42421e2SMasami Hiramatsu 				 kprobe_opcode_t *addr)
358f684199fSMasami Hiramatsu {
359c42421e2SMasami Hiramatsu 	return (op->kp.addr <= addr &&
360c42421e2SMasami Hiramatsu 		op->kp.addr + op->optinsn.size > addr);
361f684199fSMasami Hiramatsu }
362f684199fSMasami Hiramatsu 
363f684199fSMasami Hiramatsu /* Free optimized instruction slot */
3647ec8a97aSMasami Hiramatsu static
__arch_remove_optimized_kprobe(struct optimized_kprobe * op,int dirty)365f684199fSMasami Hiramatsu void __arch_remove_optimized_kprobe(struct optimized_kprobe *op, int dirty)
366f684199fSMasami Hiramatsu {
3673e46bb40SAdrian Hunter 	u8 *slot = op->optinsn.insn;
3683e46bb40SAdrian Hunter 	if (slot) {
3693e46bb40SAdrian Hunter 		int len = TMPL_END_IDX + op->optinsn.size + JMP32_INSN_SIZE;
3703e46bb40SAdrian Hunter 
3713e46bb40SAdrian Hunter 		/* Record the perf event before freeing the slot */
3723e46bb40SAdrian Hunter 		if (dirty)
3733e46bb40SAdrian Hunter 			perf_event_text_poke(slot, slot, len, NULL, 0);
3743e46bb40SAdrian Hunter 
3753e46bb40SAdrian Hunter 		free_optinsn_slot(slot, dirty);
376f684199fSMasami Hiramatsu 		op->optinsn.insn = NULL;
377f684199fSMasami Hiramatsu 		op->optinsn.size = 0;
378f684199fSMasami Hiramatsu 	}
379f684199fSMasami Hiramatsu }
380f684199fSMasami Hiramatsu 
arch_remove_optimized_kprobe(struct optimized_kprobe * op)3817ec8a97aSMasami Hiramatsu void arch_remove_optimized_kprobe(struct optimized_kprobe *op)
382f684199fSMasami Hiramatsu {
383f684199fSMasami Hiramatsu 	__arch_remove_optimized_kprobe(op, 1);
384f684199fSMasami Hiramatsu }
385f684199fSMasami Hiramatsu 
386f684199fSMasami Hiramatsu /*
387f684199fSMasami Hiramatsu  * Copy replacing target instructions
388f684199fSMasami Hiramatsu  * Target instructions MUST be relocatable (checked inside)
389f684199fSMasami Hiramatsu  * This is called when new aggr(opt)probe is allocated or reused.
390f684199fSMasami Hiramatsu  */
arch_prepare_optimized_kprobe(struct optimized_kprobe * op,struct kprobe * __unused)391cbf6ab52SMasami Hiramatsu int arch_prepare_optimized_kprobe(struct optimized_kprobe *op,
392cbf6ab52SMasami Hiramatsu 				  struct kprobe *__unused)
393f684199fSMasami Hiramatsu {
39463fef14fSMasami Hiramatsu 	u8 *buf = NULL, *slot;
39563fef14fSMasami Hiramatsu 	int ret, len;
396f684199fSMasami Hiramatsu 	long rel;
397f684199fSMasami Hiramatsu 
398f684199fSMasami Hiramatsu 	if (!can_optimize((unsigned long)op->kp.addr))
399f684199fSMasami Hiramatsu 		return -EILSEQ;
400f684199fSMasami Hiramatsu 
40163fef14fSMasami Hiramatsu 	buf = kzalloc(MAX_OPTINSN_SIZE, GFP_KERNEL);
40263fef14fSMasami Hiramatsu 	if (!buf)
403f684199fSMasami Hiramatsu 		return -ENOMEM;
404f684199fSMasami Hiramatsu 
40563fef14fSMasami Hiramatsu 	op->optinsn.insn = slot = get_optinsn_slot();
40663fef14fSMasami Hiramatsu 	if (!slot) {
40763fef14fSMasami Hiramatsu 		ret = -ENOMEM;
40863fef14fSMasami Hiramatsu 		goto out;
40963fef14fSMasami Hiramatsu 	}
41063fef14fSMasami Hiramatsu 
411f684199fSMasami Hiramatsu 	/*
412f684199fSMasami Hiramatsu 	 * Verify if the address gap is in 2GB range, because this uses
413f684199fSMasami Hiramatsu 	 * a relative jump.
414f684199fSMasami Hiramatsu 	 */
415ab09e95cSPeter Zijlstra 	rel = (long)slot - (long)op->kp.addr + JMP32_INSN_SIZE;
416256aae5eSWang Nan 	if (abs(rel) > 0x7fffffff) {
41763fef14fSMasami Hiramatsu 		ret = -ERANGE;
41863fef14fSMasami Hiramatsu 		goto err;
419256aae5eSWang Nan 	}
420f684199fSMasami Hiramatsu 
421f684199fSMasami Hiramatsu 	/* Copy arch-dep-instance from template */
422a8976fc8SMasami Hiramatsu 	memcpy(buf, optprobe_template_entry, TMPL_END_IDX);
423f684199fSMasami Hiramatsu 
42463fef14fSMasami Hiramatsu 	/* Copy instructions into the out-of-line buffer */
42563fef14fSMasami Hiramatsu 	ret = copy_optimized_instructions(buf + TMPL_END_IDX, op->kp.addr,
42663fef14fSMasami Hiramatsu 					  slot + TMPL_END_IDX);
42763fef14fSMasami Hiramatsu 	if (ret < 0)
42863fef14fSMasami Hiramatsu 		goto err;
42963fef14fSMasami Hiramatsu 	op->optinsn.size = ret;
43063fef14fSMasami Hiramatsu 	len = TMPL_END_IDX + op->optinsn.size;
43163fef14fSMasami Hiramatsu 
432d8a73868SPeter Zijlstra 	synthesize_clac(buf + TMPL_CLAC_IDX);
433d8a73868SPeter Zijlstra 
434f684199fSMasami Hiramatsu 	/* Set probe information */
435f684199fSMasami Hiramatsu 	synthesize_set_arg1(buf + TMPL_MOVE_IDX, (unsigned long)op);
436f684199fSMasami Hiramatsu 
437f684199fSMasami Hiramatsu 	/* Set probe function call */
43863fef14fSMasami Hiramatsu 	synthesize_relcall(buf + TMPL_CALL_IDX,
43963fef14fSMasami Hiramatsu 			   slot + TMPL_CALL_IDX, optimized_callback);
440f684199fSMasami Hiramatsu 
441f684199fSMasami Hiramatsu 	/* Set returning jmp instruction at the tail of out-of-line buffer */
44263fef14fSMasami Hiramatsu 	synthesize_reljump(buf + len, slot + len,
443f684199fSMasami Hiramatsu 			   (u8 *)op->kp.addr + op->optinsn.size);
444ab09e95cSPeter Zijlstra 	len += JMP32_INSN_SIZE;
445f684199fSMasami Hiramatsu 
4463e46bb40SAdrian Hunter 	/*
4473e46bb40SAdrian Hunter 	 * Note	len = TMPL_END_IDX + op->optinsn.size + JMP32_INSN_SIZE is also
4483e46bb40SAdrian Hunter 	 * used in __arch_remove_optimized_kprobe().
4493e46bb40SAdrian Hunter 	 */
4503e46bb40SAdrian Hunter 
45132b1cbe3SMarco Ammon 	/* We have to use text_poke() for instruction buffer because it is RO */
4523e46bb40SAdrian Hunter 	perf_event_text_poke(slot, NULL, 0, buf, len);
45363fef14fSMasami Hiramatsu 	text_poke(slot, buf, len);
4543e46bb40SAdrian Hunter 
45563fef14fSMasami Hiramatsu 	ret = 0;
45663fef14fSMasami Hiramatsu out:
45763fef14fSMasami Hiramatsu 	kfree(buf);
45863fef14fSMasami Hiramatsu 	return ret;
459d0381c81SMasami Hiramatsu 
46063fef14fSMasami Hiramatsu err:
46163fef14fSMasami Hiramatsu 	__arch_remove_optimized_kprobe(op, 0);
46263fef14fSMasami Hiramatsu 	goto out;
463f684199fSMasami Hiramatsu }
464f684199fSMasami Hiramatsu 
465a7b0133eSMasami Hiramatsu /*
466f2cb4f95SPeter Zijlstra  * Replace breakpoints (INT3) with relative jumps (JMP.d32).
467a7b0133eSMasami Hiramatsu  * Caller must call with locking kprobe_mutex and text_mutex.
468f2cb4f95SPeter Zijlstra  *
469f2cb4f95SPeter Zijlstra  * The caller will have installed a regular kprobe and after that issued
470f2cb4f95SPeter Zijlstra  * syncrhonize_rcu_tasks(), this ensures that the instruction(s) that live in
471f2cb4f95SPeter Zijlstra  * the 4 bytes after the INT3 are unused and can now be overwritten.
472a7b0133eSMasami Hiramatsu  */
arch_optimize_kprobes(struct list_head * oplist)4737ec8a97aSMasami Hiramatsu void arch_optimize_kprobes(struct list_head *oplist)
474f684199fSMasami Hiramatsu {
475a7b0133eSMasami Hiramatsu 	struct optimized_kprobe *op, *tmp;
476ab09e95cSPeter Zijlstra 	u8 insn_buff[JMP32_INSN_SIZE];
477a7b0133eSMasami Hiramatsu 
478a7b0133eSMasami Hiramatsu 	list_for_each_entry_safe(op, tmp, oplist, list) {
479f684199fSMasami Hiramatsu 		s32 rel = (s32)((long)op->optinsn.insn -
480ab09e95cSPeter Zijlstra 			((long)op->kp.addr + JMP32_INSN_SIZE));
481f684199fSMasami Hiramatsu 
482a7b0133eSMasami Hiramatsu 		WARN_ON(kprobe_disabled(&op->kp));
483a7b0133eSMasami Hiramatsu 
484f684199fSMasami Hiramatsu 		/* Backup instructions which will be replaced by jump address */
485ab09e95cSPeter Zijlstra 		memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_INSN_SIZE,
486ab09e95cSPeter Zijlstra 		       DISP32_SIZE);
487f684199fSMasami Hiramatsu 
488ab09e95cSPeter Zijlstra 		insn_buff[0] = JMP32_INSN_OPCODE;
4891fc654cfSIngo Molnar 		*(s32 *)(&insn_buff[1]) = rel;
490f684199fSMasami Hiramatsu 
491ab09e95cSPeter Zijlstra 		text_poke_bp(op->kp.addr, insn_buff, JMP32_INSN_SIZE, NULL);
492f684199fSMasami Hiramatsu 
493f684199fSMasami Hiramatsu 		list_del_init(&op->list);
494a7b0133eSMasami Hiramatsu 	}
495f684199fSMasami Hiramatsu }
496f684199fSMasami Hiramatsu 
497f2cb4f95SPeter Zijlstra /*
498f2cb4f95SPeter Zijlstra  * Replace a relative jump (JMP.d32) with a breakpoint (INT3).
499f2cb4f95SPeter Zijlstra  *
500f2cb4f95SPeter Zijlstra  * After that, we can restore the 4 bytes after the INT3 to undo what
501f2cb4f95SPeter Zijlstra  * arch_optimize_kprobes() scribbled. This is safe since those bytes will be
502f2cb4f95SPeter Zijlstra  * unused once the INT3 lands.
503f2cb4f95SPeter Zijlstra  */
arch_unoptimize_kprobe(struct optimized_kprobe * op)5047ec8a97aSMasami Hiramatsu void arch_unoptimize_kprobe(struct optimized_kprobe *op)
505f684199fSMasami Hiramatsu {
5063e46bb40SAdrian Hunter 	u8 new[JMP32_INSN_SIZE] = { INT3_INSN_OPCODE, };
5073e46bb40SAdrian Hunter 	u8 old[JMP32_INSN_SIZE];
5083e46bb40SAdrian Hunter 	u8 *addr = op->kp.addr;
5093e46bb40SAdrian Hunter 
5103e46bb40SAdrian Hunter 	memcpy(old, op->kp.addr, JMP32_INSN_SIZE);
5113e46bb40SAdrian Hunter 	memcpy(new + INT3_INSN_SIZE,
5123e46bb40SAdrian Hunter 	       op->optinsn.copied_insn,
5133e46bb40SAdrian Hunter 	       JMP32_INSN_SIZE - INT3_INSN_SIZE);
5143e46bb40SAdrian Hunter 
5153e46bb40SAdrian Hunter 	text_poke(addr, new, INT3_INSN_SIZE);
5165c02ece8SPeter Zijlstra 	text_poke_sync();
5173e46bb40SAdrian Hunter 	text_poke(addr + INT3_INSN_SIZE,
5183e46bb40SAdrian Hunter 		  new + INT3_INSN_SIZE,
5193e46bb40SAdrian Hunter 		  JMP32_INSN_SIZE - INT3_INSN_SIZE);
5203e46bb40SAdrian Hunter 	text_poke_sync();
5213e46bb40SAdrian Hunter 
5223e46bb40SAdrian Hunter 	perf_event_text_poke(op->kp.addr, old, JMP32_INSN_SIZE, new, JMP32_INSN_SIZE);
523f684199fSMasami Hiramatsu }
524f684199fSMasami Hiramatsu 
525f684199fSMasami Hiramatsu /*
526f684199fSMasami Hiramatsu  * Recover original instructions and breakpoints from relative jumps.
527f684199fSMasami Hiramatsu  * Caller must call with locking kprobe_mutex.
528f684199fSMasami Hiramatsu  */
arch_unoptimize_kprobes(struct list_head * oplist,struct list_head * done_list)529f684199fSMasami Hiramatsu extern void arch_unoptimize_kprobes(struct list_head *oplist,
530f684199fSMasami Hiramatsu 				    struct list_head *done_list)
531f684199fSMasami Hiramatsu {
532f684199fSMasami Hiramatsu 	struct optimized_kprobe *op, *tmp;
533f684199fSMasami Hiramatsu 
534f684199fSMasami Hiramatsu 	list_for_each_entry_safe(op, tmp, oplist, list) {
535a7b0133eSMasami Hiramatsu 		arch_unoptimize_kprobe(op);
536f684199fSMasami Hiramatsu 		list_move(&op->list, done_list);
537f684199fSMasami Hiramatsu 	}
538f684199fSMasami Hiramatsu }
539f684199fSMasami Hiramatsu 
setup_detour_execution(struct kprobe * p,struct pt_regs * regs,int reenter)5409326638cSMasami Hiramatsu int setup_detour_execution(struct kprobe *p, struct pt_regs *regs, int reenter)
541f684199fSMasami Hiramatsu {
542f684199fSMasami Hiramatsu 	struct optimized_kprobe *op;
543f684199fSMasami Hiramatsu 
544f684199fSMasami Hiramatsu 	if (p->flags & KPROBE_FLAG_OPTIMIZED) {
545f684199fSMasami Hiramatsu 		/* This kprobe is really able to run optimized path. */
546f684199fSMasami Hiramatsu 		op = container_of(p, struct optimized_kprobe, kp);
547f684199fSMasami Hiramatsu 		/* Detour through copied instructions */
548f684199fSMasami Hiramatsu 		regs->ip = (unsigned long)op->optinsn.insn + TMPL_END_IDX;
549f684199fSMasami Hiramatsu 		if (!reenter)
550f684199fSMasami Hiramatsu 			reset_current_kprobe();
551f684199fSMasami Hiramatsu 		return 1;
552f684199fSMasami Hiramatsu 	}
553f684199fSMasami Hiramatsu 	return 0;
554f684199fSMasami Hiramatsu }
5559326638cSMasami Hiramatsu NOKPROBE_SYMBOL(setup_detour_execution);
556