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#include <asm/gcs.h>
10
11#include "decode-insn.h"
12
13#define UPROBE_INV_FAULT_CODE UINT_MAX
14
15void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
16 void *src, unsigned long len)
17{
18 void *xol_page_kaddr = kmap_atomic(page);
19 void *dst = xol_page_kaddr + (vaddr & ~PAGE_MASK);
20
21 /*
22 * Initial cache maintenance of the xol page done via set_pte_at().
23 * Subsequent CMOs only needed if the xol slot changes.
24 */
25 if (!memcmp(p: dst, q: src, size: len))
26 goto done;
27
28 /* Initialize the slot */
29 memcpy(dst, src, len);
30
31 /* flush caches (dcache/icache) */
32 sync_icache_aliases((unsigned long)dst, (unsigned long)dst + len);
33
34done:
35 kunmap_atomic(xol_page_kaddr);
36}
37
38unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
39{
40 return instruction_pointer(regs);
41}
42
43int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
44 unsigned long addr)
45{
46 u32 insn;
47
48 /* TODO: Currently we do not support AARCH32 instruction probing */
49 if (mm->context.flags & MMCF_AARCH32)
50 return -EOPNOTSUPP;
51 else if (!IS_ALIGNED(addr, AARCH64_INSN_SIZE))
52 return -EINVAL;
53
54 insn = le32_to_cpu(auprobe->insn);
55
56 switch (arm_probe_decode_insn(insn, asi: &auprobe->api)) {
57 case INSN_REJECTED:
58 return -EINVAL;
59
60 case INSN_GOOD_NO_SLOT:
61 auprobe->simulate = true;
62 break;
63
64 default:
65 break;
66 }
67
68 return 0;
69}
70
71int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
72{
73 struct uprobe_task *utask = current->utask;
74
75 /* Initialize with an invalid fault code to detect if ol insn trapped */
76 current->thread.fault_code = UPROBE_INV_FAULT_CODE;
77
78 /* Instruction points to execute ol */
79 instruction_pointer_set(regs, val: utask->xol_vaddr);
80
81 user_enable_single_step(current);
82
83 return 0;
84}
85
86int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
87{
88 struct uprobe_task *utask = current->utask;
89
90 WARN_ON_ONCE(current->thread.fault_code != UPROBE_INV_FAULT_CODE);
91
92 /* Instruction points to execute next to breakpoint address */
93 instruction_pointer_set(regs, val: utask->vaddr + 4);
94
95 user_disable_single_step(current);
96
97 return 0;
98}
99bool arch_uprobe_xol_was_trapped(struct task_struct *t)
100{
101 /*
102 * Between arch_uprobe_pre_xol and arch_uprobe_post_xol, if an xol
103 * insn itself is trapped, then detect the case with the help of
104 * invalid fault code which is being set in arch_uprobe_pre_xol
105 */
106 if (t->thread.fault_code != UPROBE_INV_FAULT_CODE)
107 return true;
108
109 return false;
110}
111
112bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
113{
114 u32 insn;
115 unsigned long addr;
116
117 if (!auprobe->simulate)
118 return false;
119
120 insn = le32_to_cpu(auprobe->insn);
121 addr = instruction_pointer(regs);
122
123 if (auprobe->api.handler)
124 auprobe->api.handler(insn, addr, regs);
125
126 return true;
127}
128
129void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
130{
131 struct uprobe_task *utask = current->utask;
132
133 /*
134 * Task has received a fatal signal, so reset back to probed
135 * address.
136 */
137 instruction_pointer_set(regs, val: utask->vaddr);
138
139 user_disable_single_step(current);
140}
141
142bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
143 struct pt_regs *regs)
144{
145 /*
146 * If a simple branch instruction (B) was called for retprobed
147 * assembly label then return true even when regs->sp and ret->stack
148 * are same. It will ensure that cleanup and reporting of return
149 * instances corresponding to callee label is done when
150 * handle_trampoline for called function is executed.
151 */
152 if (ctx == RP_CHECK_CHAIN_CALL)
153 return regs->sp <= ret->stack;
154 else
155 return regs->sp < ret->stack;
156}
157
158unsigned long
159arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
160 struct pt_regs *regs)
161{
162 unsigned long orig_ret_vaddr;
163 unsigned long gcs_ret_vaddr;
164 int err = 0;
165 u64 gcspr;
166
167 orig_ret_vaddr = procedure_link_pointer(regs);
168
169 if (task_gcs_el0_enabled(current)) {
170 gcspr = read_sysreg_s(SYS_GCSPR_EL0);
171 gcs_ret_vaddr = get_user_gcs((__force unsigned long __user *)gcspr, &err);
172 if (err) {
173 force_sig(SIGSEGV);
174 goto out;
175 }
176
177 /*
178 * If the LR and GCS return addr don't match, then some kind of PAC
179 * signing or control flow occurred since entering the probed function.
180 * Likely because the user is attempting to retprobe on an instruction
181 * that isn't a function boundary or inside a leaf function. Explicitly
182 * abort this retprobe because it will generate a GCS exception.
183 */
184 if (gcs_ret_vaddr != orig_ret_vaddr) {
185 orig_ret_vaddr = -1;
186 goto out;
187 }
188
189 put_user_gcs(trampoline_vaddr, (__force unsigned long __user *)gcspr, &err);
190 if (err) {
191 force_sig(SIGSEGV);
192 goto out;
193 }
194 }
195
196 /* Replace the return addr with trampoline addr */
197 procedure_link_pointer_set(regs, trampoline_vaddr);
198
199out:
200 return orig_ret_vaddr;
201}
202
203int arch_uprobe_exception_notify(struct notifier_block *self,
204 unsigned long val, void *data)
205{
206 return NOTIFY_DONE;
207}
208
209int uprobe_brk_handler(struct pt_regs *regs,
210 unsigned long esr)
211{
212 if (uprobe_pre_sstep_notifier(regs))
213 return DBG_HOOK_HANDLED;
214
215 return DBG_HOOK_ERROR;
216}
217
218int uprobe_single_step_handler(struct pt_regs *regs,
219 unsigned long esr)
220{
221 struct uprobe_task *utask = current->utask;
222
223 WARN_ON(utask && (instruction_pointer(regs) != utask->xol_vaddr + 4));
224 if (uprobe_post_sstep_notifier(regs))
225 return DBG_HOOK_HANDLED;
226
227 return DBG_HOOK_ERROR;
228}
229
230

source code of linux/arch/arm64/kernel/probes/uprobes.c