1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * PowerPC version |
4 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) |
5 | * |
6 | * Derived from "arch/m68k/kernel/ptrace.c" |
7 | * Copyright (C) 1994 by Hamish Macdonald |
8 | * Taken from linux/kernel/ptrace.c and modified for M680x0. |
9 | * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds |
10 | * |
11 | * Modified by Cort Dougan (cort@hq.fsmlabs.com) |
12 | * and Paul Mackerras (paulus@samba.org). |
13 | */ |
14 | |
15 | #include <linux/regset.h> |
16 | #include <linux/ptrace.h> |
17 | #include <linux/audit.h> |
18 | #include <linux/context_tracking.h> |
19 | #include <linux/syscalls.h> |
20 | |
21 | #include <asm/switch_to.h> |
22 | #include <asm/debug.h> |
23 | |
24 | #define CREATE_TRACE_POINTS |
25 | #include <trace/events/syscalls.h> |
26 | |
27 | #include "ptrace-decl.h" |
28 | |
29 | /* |
30 | * Called by kernel/ptrace.c when detaching.. |
31 | * |
32 | * Make sure single step bits etc are not set. |
33 | */ |
34 | void ptrace_disable(struct task_struct *child) |
35 | { |
36 | /* make sure the single step bit is not set. */ |
37 | user_disable_single_step(child); |
38 | } |
39 | |
40 | long arch_ptrace(struct task_struct *child, long request, |
41 | unsigned long addr, unsigned long data) |
42 | { |
43 | int ret = -EPERM; |
44 | void __user *datavp = (void __user *) data; |
45 | unsigned long __user *datalp = datavp; |
46 | |
47 | switch (request) { |
48 | /* read the word at location addr in the USER area. */ |
49 | case PTRACE_PEEKUSR: { |
50 | unsigned long index, tmp; |
51 | |
52 | ret = -EIO; |
53 | /* convert to index and check */ |
54 | index = addr / sizeof(long); |
55 | if ((addr & (sizeof(long) - 1)) || !child->thread.regs) |
56 | break; |
57 | |
58 | if (index < PT_FPR0) |
59 | ret = ptrace_get_reg(task: child, regno: (int) index, data: &tmp); |
60 | else |
61 | ret = ptrace_get_fpr(child, index, data: &tmp); |
62 | |
63 | if (ret) |
64 | break; |
65 | ret = put_user(tmp, datalp); |
66 | break; |
67 | } |
68 | |
69 | /* write the word at location addr in the USER area */ |
70 | case PTRACE_POKEUSR: { |
71 | unsigned long index; |
72 | |
73 | ret = -EIO; |
74 | /* convert to index and check */ |
75 | index = addr / sizeof(long); |
76 | if ((addr & (sizeof(long) - 1)) || !child->thread.regs) |
77 | break; |
78 | |
79 | if (index < PT_FPR0) |
80 | ret = ptrace_put_reg(task: child, regno: index, data); |
81 | else |
82 | ret = ptrace_put_fpr(child, index, data); |
83 | break; |
84 | } |
85 | |
86 | case PPC_PTRACE_GETHWDBGINFO: { |
87 | struct ppc_debug_info dbginfo; |
88 | |
89 | ppc_gethwdinfo(dbginfo: &dbginfo); |
90 | |
91 | if (copy_to_user(datavp, &dbginfo, |
92 | sizeof(struct ppc_debug_info))) |
93 | return -EFAULT; |
94 | return 0; |
95 | } |
96 | |
97 | case PPC_PTRACE_SETHWDEBUG: { |
98 | struct ppc_hw_breakpoint bp_info; |
99 | |
100 | if (copy_from_user(&bp_info, datavp, |
101 | sizeof(struct ppc_hw_breakpoint))) |
102 | return -EFAULT; |
103 | return ppc_set_hwdebug(child, bp_info: &bp_info); |
104 | } |
105 | |
106 | case PPC_PTRACE_DELHWDEBUG: { |
107 | ret = ppc_del_hwdebug(child, data); |
108 | break; |
109 | } |
110 | |
111 | case PTRACE_GET_DEBUGREG: |
112 | ret = ptrace_get_debugreg(child, addr, datalp); |
113 | break; |
114 | |
115 | case PTRACE_SET_DEBUGREG: |
116 | ret = ptrace_set_debugreg(task: child, addr, data); |
117 | break; |
118 | |
119 | #ifdef CONFIG_PPC64 |
120 | case PTRACE_GETREGS64: |
121 | #endif |
122 | case PTRACE_GETREGS: /* Get all pt_regs from the child. */ |
123 | return copy_regset_to_user(child, &user_ppc_native_view, |
124 | REGSET_GPR, |
125 | 0, sizeof(struct user_pt_regs), |
126 | datavp); |
127 | |
128 | #ifdef CONFIG_PPC64 |
129 | case PTRACE_SETREGS64: |
130 | #endif |
131 | case PTRACE_SETREGS: /* Set all gp regs in the child. */ |
132 | return copy_regset_from_user(child, &user_ppc_native_view, |
133 | REGSET_GPR, |
134 | 0, sizeof(struct user_pt_regs), |
135 | datavp); |
136 | |
137 | case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */ |
138 | return copy_regset_to_user(target: child, view: &user_ppc_native_view, |
139 | setno: REGSET_FPR, |
140 | offset: 0, size: sizeof(elf_fpregset_t), |
141 | data: datavp); |
142 | |
143 | case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */ |
144 | return copy_regset_from_user(target: child, view: &user_ppc_native_view, |
145 | setno: REGSET_FPR, |
146 | offset: 0, size: sizeof(elf_fpregset_t), |
147 | data: datavp); |
148 | |
149 | #ifdef CONFIG_ALTIVEC |
150 | case PTRACE_GETVRREGS: |
151 | return copy_regset_to_user(child, &user_ppc_native_view, |
152 | REGSET_VMX, |
153 | 0, (33 * sizeof(vector128) + |
154 | sizeof(u32)), |
155 | datavp); |
156 | |
157 | case PTRACE_SETVRREGS: |
158 | return copy_regset_from_user(child, &user_ppc_native_view, |
159 | REGSET_VMX, |
160 | 0, (33 * sizeof(vector128) + |
161 | sizeof(u32)), |
162 | datavp); |
163 | #endif |
164 | #ifdef CONFIG_VSX |
165 | case PTRACE_GETVSRREGS: |
166 | return copy_regset_to_user(child, &user_ppc_native_view, |
167 | REGSET_VSX, |
168 | 0, 32 * sizeof(double), |
169 | datavp); |
170 | |
171 | case PTRACE_SETVSRREGS: |
172 | return copy_regset_from_user(child, &user_ppc_native_view, |
173 | REGSET_VSX, |
174 | 0, 32 * sizeof(double), |
175 | datavp); |
176 | #endif |
177 | #ifdef CONFIG_SPE |
178 | case PTRACE_GETEVRREGS: |
179 | /* Get the child spe register state. */ |
180 | return copy_regset_to_user(child, &user_ppc_native_view, |
181 | REGSET_SPE, 0, 35 * sizeof(u32), |
182 | datavp); |
183 | |
184 | case PTRACE_SETEVRREGS: |
185 | /* Set the child spe register state. */ |
186 | return copy_regset_from_user(child, &user_ppc_native_view, |
187 | REGSET_SPE, 0, 35 * sizeof(u32), |
188 | datavp); |
189 | #endif |
190 | |
191 | default: |
192 | ret = ptrace_request(child, request, addr, data); |
193 | break; |
194 | } |
195 | return ret; |
196 | } |
197 | |
198 | #ifdef CONFIG_SECCOMP |
199 | static int do_seccomp(struct pt_regs *regs) |
200 | { |
201 | if (!test_thread_flag(TIF_SECCOMP)) |
202 | return 0; |
203 | |
204 | /* |
205 | * The ABI we present to seccomp tracers is that r3 contains |
206 | * the syscall return value and orig_gpr3 contains the first |
207 | * syscall parameter. This is different to the ptrace ABI where |
208 | * both r3 and orig_gpr3 contain the first syscall parameter. |
209 | */ |
210 | regs->gpr[3] = -ENOSYS; |
211 | |
212 | /* |
213 | * We use the __ version here because we have already checked |
214 | * TIF_SECCOMP. If this fails, there is nothing left to do, we |
215 | * have already loaded -ENOSYS into r3, or seccomp has put |
216 | * something else in r3 (via SECCOMP_RET_ERRNO/TRACE). |
217 | */ |
218 | if (__secure_computing(NULL)) |
219 | return -1; |
220 | |
221 | /* |
222 | * The syscall was allowed by seccomp, restore the register |
223 | * state to what audit expects. |
224 | * Note that we use orig_gpr3, which means a seccomp tracer can |
225 | * modify the first syscall parameter (in orig_gpr3) and also |
226 | * allow the syscall to proceed. |
227 | */ |
228 | regs->gpr[3] = regs->orig_gpr3; |
229 | |
230 | return 0; |
231 | } |
232 | #else |
233 | static inline int do_seccomp(struct pt_regs *regs) { return 0; } |
234 | #endif /* CONFIG_SECCOMP */ |
235 | |
236 | /** |
237 | * do_syscall_trace_enter() - Do syscall tracing on kernel entry. |
238 | * @regs: the pt_regs of the task to trace (current) |
239 | * |
240 | * Performs various types of tracing on syscall entry. This includes seccomp, |
241 | * ptrace, syscall tracepoints and audit. |
242 | * |
243 | * The pt_regs are potentially visible to userspace via ptrace, so their |
244 | * contents is ABI. |
245 | * |
246 | * One or more of the tracers may modify the contents of pt_regs, in particular |
247 | * to modify arguments or even the syscall number itself. |
248 | * |
249 | * It's also possible that a tracer can choose to reject the system call. In |
250 | * that case this function will return an illegal syscall number, and will put |
251 | * an appropriate return value in regs->r3. |
252 | * |
253 | * Return: the (possibly changed) syscall number. |
254 | */ |
255 | long do_syscall_trace_enter(struct pt_regs *regs) |
256 | { |
257 | u32 flags; |
258 | |
259 | flags = read_thread_flags() & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE); |
260 | |
261 | if (flags) { |
262 | int rc = ptrace_report_syscall_entry(regs); |
263 | |
264 | if (unlikely(flags & _TIF_SYSCALL_EMU)) { |
265 | /* |
266 | * A nonzero return code from |
267 | * ptrace_report_syscall_entry() tells us to prevent |
268 | * the syscall execution, but we are not going to |
269 | * execute it anyway. |
270 | * |
271 | * Returning -1 will skip the syscall execution. We want |
272 | * to avoid clobbering any registers, so we don't goto |
273 | * the skip label below. |
274 | */ |
275 | return -1; |
276 | } |
277 | |
278 | if (rc) { |
279 | /* |
280 | * The tracer decided to abort the syscall. Note that |
281 | * the tracer may also just change regs->gpr[0] to an |
282 | * invalid syscall number, that is handled below on the |
283 | * exit path. |
284 | */ |
285 | goto skip; |
286 | } |
287 | } |
288 | |
289 | /* Run seccomp after ptrace; allow it to set gpr[3]. */ |
290 | if (do_seccomp(regs)) |
291 | return -1; |
292 | |
293 | /* Avoid trace and audit when syscall is invalid. */ |
294 | if (regs->gpr[0] >= NR_syscalls) |
295 | goto skip; |
296 | |
297 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
298 | trace_sys_enter(regs, id: regs->gpr[0]); |
299 | |
300 | if (!is_32bit_task()) |
301 | audit_syscall_entry(major: regs->gpr[0], a0: regs->gpr[3], a1: regs->gpr[4], |
302 | a2: regs->gpr[5], a3: regs->gpr[6]); |
303 | else |
304 | audit_syscall_entry(major: regs->gpr[0], |
305 | a0: regs->gpr[3] & 0xffffffff, |
306 | a1: regs->gpr[4] & 0xffffffff, |
307 | a2: regs->gpr[5] & 0xffffffff, |
308 | a3: regs->gpr[6] & 0xffffffff); |
309 | |
310 | /* Return the possibly modified but valid syscall number */ |
311 | return regs->gpr[0]; |
312 | |
313 | skip: |
314 | /* |
315 | * If we are aborting explicitly, or if the syscall number is |
316 | * now invalid, set the return value to -ENOSYS. |
317 | */ |
318 | regs->gpr[3] = -ENOSYS; |
319 | return -1; |
320 | } |
321 | |
322 | void do_syscall_trace_leave(struct pt_regs *regs) |
323 | { |
324 | int step; |
325 | |
326 | audit_syscall_exit(pt_regs: regs); |
327 | |
328 | if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT))) |
329 | trace_sys_exit(regs, ret: regs->result); |
330 | |
331 | step = test_thread_flag(TIF_SINGLESTEP); |
332 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) |
333 | ptrace_report_syscall_exit(regs, step); |
334 | } |
335 | |
336 | void __init pt_regs_check(void); |
337 | |
338 | /* |
339 | * Dummy function, its purpose is to break the build if struct pt_regs and |
340 | * struct user_pt_regs don't match. |
341 | */ |
342 | void __init pt_regs_check(void) |
343 | { |
344 | BUILD_BUG_ON(offsetof(struct pt_regs, gpr) != |
345 | offsetof(struct user_pt_regs, gpr)); |
346 | BUILD_BUG_ON(offsetof(struct pt_regs, nip) != |
347 | offsetof(struct user_pt_regs, nip)); |
348 | BUILD_BUG_ON(offsetof(struct pt_regs, msr) != |
349 | offsetof(struct user_pt_regs, msr)); |
350 | BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) != |
351 | offsetof(struct user_pt_regs, orig_gpr3)); |
352 | BUILD_BUG_ON(offsetof(struct pt_regs, ctr) != |
353 | offsetof(struct user_pt_regs, ctr)); |
354 | BUILD_BUG_ON(offsetof(struct pt_regs, link) != |
355 | offsetof(struct user_pt_regs, link)); |
356 | BUILD_BUG_ON(offsetof(struct pt_regs, xer) != |
357 | offsetof(struct user_pt_regs, xer)); |
358 | BUILD_BUG_ON(offsetof(struct pt_regs, ccr) != |
359 | offsetof(struct user_pt_regs, ccr)); |
360 | #ifdef __powerpc64__ |
361 | BUILD_BUG_ON(offsetof(struct pt_regs, softe) != |
362 | offsetof(struct user_pt_regs, softe)); |
363 | #else |
364 | BUILD_BUG_ON(offsetof(struct pt_regs, mq) != |
365 | offsetof(struct user_pt_regs, mq)); |
366 | #endif |
367 | BUILD_BUG_ON(offsetof(struct pt_regs, trap) != |
368 | offsetof(struct user_pt_regs, trap)); |
369 | BUILD_BUG_ON(offsetof(struct pt_regs, dar) != |
370 | offsetof(struct user_pt_regs, dar)); |
371 | BUILD_BUG_ON(offsetof(struct pt_regs, dear) != |
372 | offsetof(struct user_pt_regs, dar)); |
373 | BUILD_BUG_ON(offsetof(struct pt_regs, dsisr) != |
374 | offsetof(struct user_pt_regs, dsisr)); |
375 | BUILD_BUG_ON(offsetof(struct pt_regs, esr) != |
376 | offsetof(struct user_pt_regs, dsisr)); |
377 | BUILD_BUG_ON(offsetof(struct pt_regs, result) != |
378 | offsetof(struct user_pt_regs, result)); |
379 | |
380 | BUILD_BUG_ON(sizeof(struct user_pt_regs) > sizeof(struct pt_regs)); |
381 | |
382 | // Now check that the pt_regs offsets match the uapi #defines |
383 | #define CHECK_REG(_pt, _reg) \ |
384 | BUILD_BUG_ON(_pt != (offsetof(struct user_pt_regs, _reg) / \ |
385 | sizeof(unsigned long))); |
386 | |
387 | CHECK_REG(PT_R0, gpr[0]); |
388 | CHECK_REG(PT_R1, gpr[1]); |
389 | CHECK_REG(PT_R2, gpr[2]); |
390 | CHECK_REG(PT_R3, gpr[3]); |
391 | CHECK_REG(PT_R4, gpr[4]); |
392 | CHECK_REG(PT_R5, gpr[5]); |
393 | CHECK_REG(PT_R6, gpr[6]); |
394 | CHECK_REG(PT_R7, gpr[7]); |
395 | CHECK_REG(PT_R8, gpr[8]); |
396 | CHECK_REG(PT_R9, gpr[9]); |
397 | CHECK_REG(PT_R10, gpr[10]); |
398 | CHECK_REG(PT_R11, gpr[11]); |
399 | CHECK_REG(PT_R12, gpr[12]); |
400 | CHECK_REG(PT_R13, gpr[13]); |
401 | CHECK_REG(PT_R14, gpr[14]); |
402 | CHECK_REG(PT_R15, gpr[15]); |
403 | CHECK_REG(PT_R16, gpr[16]); |
404 | CHECK_REG(PT_R17, gpr[17]); |
405 | CHECK_REG(PT_R18, gpr[18]); |
406 | CHECK_REG(PT_R19, gpr[19]); |
407 | CHECK_REG(PT_R20, gpr[20]); |
408 | CHECK_REG(PT_R21, gpr[21]); |
409 | CHECK_REG(PT_R22, gpr[22]); |
410 | CHECK_REG(PT_R23, gpr[23]); |
411 | CHECK_REG(PT_R24, gpr[24]); |
412 | CHECK_REG(PT_R25, gpr[25]); |
413 | CHECK_REG(PT_R26, gpr[26]); |
414 | CHECK_REG(PT_R27, gpr[27]); |
415 | CHECK_REG(PT_R28, gpr[28]); |
416 | CHECK_REG(PT_R29, gpr[29]); |
417 | CHECK_REG(PT_R30, gpr[30]); |
418 | CHECK_REG(PT_R31, gpr[31]); |
419 | CHECK_REG(PT_NIP, nip); |
420 | CHECK_REG(PT_MSR, msr); |
421 | CHECK_REG(PT_ORIG_R3, orig_gpr3); |
422 | CHECK_REG(PT_CTR, ctr); |
423 | CHECK_REG(PT_LNK, link); |
424 | CHECK_REG(PT_XER, xer); |
425 | CHECK_REG(PT_CCR, ccr); |
426 | #ifdef CONFIG_PPC64 |
427 | CHECK_REG(PT_SOFTE, softe); |
428 | #else |
429 | CHECK_REG(PT_MQ, mq); |
430 | #endif |
431 | CHECK_REG(PT_TRAP, trap); |
432 | CHECK_REG(PT_DAR, dar); |
433 | CHECK_REG(PT_DSISR, dsisr); |
434 | CHECK_REG(PT_RESULT, result); |
435 | #undef CHECK_REG |
436 | |
437 | BUILD_BUG_ON(PT_REGS_COUNT != sizeof(struct user_pt_regs) / sizeof(unsigned long)); |
438 | |
439 | /* |
440 | * PT_DSCR isn't a real reg, but it's important that it doesn't overlap the |
441 | * real registers. |
442 | */ |
443 | BUILD_BUG_ON(PT_DSCR < sizeof(struct user_pt_regs) / sizeof(unsigned long)); |
444 | |
445 | // ptrace_get/put_fpr() rely on PPC32 and VSX being incompatible |
446 | BUILD_BUG_ON(IS_ENABLED(CONFIG_PPC32) && IS_ENABLED(CONFIG_VSX)); |
447 | } |
448 | |