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