1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2014-2016 Pratyush Anand <panand@redhat.com>
4 */
5#include <linux/highmem.h>
6#include <linux/ptrace.h>
7#include <linux/uprobes.h>
8#include <asm/cacheflush.h>
9
10#include "decode-insn.h"
11
12#define UPROBE_INV_FAULT_CODE	UINT_MAX
13
14void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
15		void *src, unsigned long len)
16{
17	void *xol_page_kaddr = kmap_atomic(page);
18	void *dst = xol_page_kaddr + (vaddr & ~PAGE_MASK);
19
20	/* Initialize the slot */
21	memcpy(dst, src, len);
22
23	/* flush caches (dcache/icache) */
24	sync_icache_aliases((unsigned long)dst, (unsigned long)dst + len);
25
26	kunmap_atomic(xol_page_kaddr);
27}
28
29unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
30{
31	return instruction_pointer(regs);
32}
33
34int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
35		unsigned long addr)
36{
37	probe_opcode_t insn;
38
39	/* TODO: Currently we do not support AARCH32 instruction probing */
40	if (mm->context.flags & MMCF_AARCH32)
41		return -EOPNOTSUPP;
42	else if (!IS_ALIGNED(addr, AARCH64_INSN_SIZE))
43		return -EINVAL;
44
45	insn = *(probe_opcode_t *)(&auprobe->insn[0]);
46
47	switch (arm_probe_decode_insn(insn, &auprobe->api)) {
48	case INSN_REJECTED:
49		return -EINVAL;
50
51	case INSN_GOOD_NO_SLOT:
52		auprobe->simulate = true;
53		break;
54
55	default:
56		break;
57	}
58
59	return 0;
60}
61
62int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
63{
64	struct uprobe_task *utask = current->utask;
65
66	/* Initialize with an invalid fault code to detect if ol insn trapped */
67	current->thread.fault_code = UPROBE_INV_FAULT_CODE;
68
69	/* Instruction points to execute ol */
70	instruction_pointer_set(regs, utask->xol_vaddr);
71
72	user_enable_single_step(current);
73
74	return 0;
75}
76
77int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
78{
79	struct uprobe_task *utask = current->utask;
80
81	WARN_ON_ONCE(current->thread.fault_code != UPROBE_INV_FAULT_CODE);
82
83	/* Instruction points to execute next to breakpoint address */
84	instruction_pointer_set(regs, utask->vaddr + 4);
85
86	user_disable_single_step(current);
87
88	return 0;
89}
90bool arch_uprobe_xol_was_trapped(struct task_struct *t)
91{
92	/*
93	 * Between arch_uprobe_pre_xol and arch_uprobe_post_xol, if an xol
94	 * insn itself is trapped, then detect the case with the help of
95	 * invalid fault code which is being set in arch_uprobe_pre_xol
96	 */
97	if (t->thread.fault_code != UPROBE_INV_FAULT_CODE)
98		return true;
99
100	return false;
101}
102
103bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
104{
105	probe_opcode_t insn;
106	unsigned long addr;
107
108	if (!auprobe->simulate)
109		return false;
110
111	insn = *(probe_opcode_t *)(&auprobe->insn[0]);
112	addr = instruction_pointer(regs);
113
114	if (auprobe->api.handler)
115		auprobe->api.handler(insn, addr, regs);
116
117	return true;
118}
119
120void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
121{
122	struct uprobe_task *utask = current->utask;
123
124	/*
125	 * Task has received a fatal signal, so reset back to probbed
126	 * address.
127	 */
128	instruction_pointer_set(regs, utask->vaddr);
129
130	user_disable_single_step(current);
131}
132
133bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
134		struct pt_regs *regs)
135{
136	/*
137	 * If a simple branch instruction (B) was called for retprobed
138	 * assembly label then return true even when regs->sp and ret->stack
139	 * are same. It will ensure that cleanup and reporting of return
140	 * instances corresponding to callee label is done when
141	 * handle_trampoline for called function is executed.
142	 */
143	if (ctx == RP_CHECK_CHAIN_CALL)
144		return regs->sp <= ret->stack;
145	else
146		return regs->sp < ret->stack;
147}
148
149unsigned long
150arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
151				  struct pt_regs *regs)
152{
153	unsigned long orig_ret_vaddr;
154
155	orig_ret_vaddr = procedure_link_pointer(regs);
156	/* Replace the return addr with trampoline addr */
157	procedure_link_pointer_set(regs, trampoline_vaddr);
158
159	return orig_ret_vaddr;
160}
161
162int arch_uprobe_exception_notify(struct notifier_block *self,
163				 unsigned long val, void *data)
164{
165	return NOTIFY_DONE;
166}
167
168static int uprobe_breakpoint_handler(struct pt_regs *regs,
169				     unsigned long esr)
170{
171	if (uprobe_pre_sstep_notifier(regs))
172		return DBG_HOOK_HANDLED;
173
174	return DBG_HOOK_ERROR;
175}
176
177static int uprobe_single_step_handler(struct pt_regs *regs,
178				      unsigned long esr)
179{
180	struct uprobe_task *utask = current->utask;
181
182	WARN_ON(utask && (instruction_pointer(regs) != utask->xol_vaddr + 4));
183	if (uprobe_post_sstep_notifier(regs))
184		return DBG_HOOK_HANDLED;
185
186	return DBG_HOOK_ERROR;
187}
188
189/* uprobe breakpoint handler hook */
190static struct break_hook uprobes_break_hook = {
191	.imm = UPROBES_BRK_IMM,
192	.fn = uprobe_breakpoint_handler,
193};
194
195/* uprobe single step handler hook */
196static struct step_hook uprobes_step_hook = {
197	.fn = uprobe_single_step_handler,
198};
199
200static int __init arch_init_uprobes(void)
201{
202	register_user_break_hook(&uprobes_break_hook);
203	register_user_step_hook(&uprobes_step_hook);
204
205	return 0;
206}
207
208device_initcall(arch_init_uprobes);
209