~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/kernel/ptrace/ptrace.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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(child, (int) index, &tmp);
 60                 else
 61                         ret = ptrace_get_fpr(child, index, &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(child, 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);
 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);
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(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(child, &user_ppc_native_view,
139                                            REGSET_FPR,
140                                            0, sizeof(elf_fpregset_t),
141                                            datavp);
142 
143         case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */
144                 return copy_regset_from_user(child, &user_ppc_native_view,
145                                              REGSET_FPR,
146                                              0, sizeof(elf_fpregset_t),
147                                              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, regs->gpr[0]);
299 
300         if (!is_32bit_task())
301                 audit_syscall_entry(regs->gpr[0], regs->gpr[3], regs->gpr[4],
302                                     regs->gpr[5], regs->gpr[6]);
303         else
304                 audit_syscall_entry(regs->gpr[0],
305                                     regs->gpr[3] & 0xffffffff,
306                                     regs->gpr[4] & 0xffffffff,
307                                     regs->gpr[5] & 0xffffffff,
308                                     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(regs);
327 
328         if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
329                 trace_sys_exit(regs, 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php