1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/regset.h>
19#include <linux/tracehook.h>
20#include <linux/audit.h>
21#include <linux/context_tracking.h>
22#include <linux/syscalls.h>
23
24#include <asm/switch_to.h>
25#include <asm/asm-prototypes.h>
26#include <asm/debug.h>
27
28#define CREATE_TRACE_POINTS
29#include <trace/events/syscalls.h>
30
31#include "ptrace-decl.h"
32
33
34
35
36
37
38void ptrace_disable(struct task_struct *child)
39{
40
41 user_disable_single_step(child);
42}
43
44long arch_ptrace(struct task_struct *child, long request,
45 unsigned long addr, unsigned long data)
46{
47 int ret = -EPERM;
48 void __user *datavp = (void __user *) data;
49 unsigned long __user *datalp = datavp;
50
51 switch (request) {
52
53 case PTRACE_PEEKUSR: {
54 unsigned long index, tmp;
55
56 ret = -EIO;
57
58#ifdef CONFIG_PPC32
59 index = addr >> 2;
60 if ((addr & 3) || (index > PT_FPSCR)
61 || (child->thread.regs == NULL))
62#else
63 index = addr >> 3;
64 if ((addr & 7) || (index > PT_FPSCR))
65#endif
66 break;
67
68 CHECK_FULL_REGS(child->thread.regs);
69 if (index < PT_FPR0) {
70 ret = ptrace_get_reg(child, (int) index, &tmp);
71 if (ret)
72 break;
73 } else {
74 unsigned int fpidx = index - PT_FPR0;
75
76 flush_fp_to_thread(child);
77 if (fpidx < (PT_FPSCR - PT_FPR0))
78 memcpy(&tmp, &child->thread.TS_FPR(fpidx),
79 sizeof(long));
80 else
81 tmp = child->thread.fp_state.fpscr;
82 }
83 ret = put_user(tmp, datalp);
84 break;
85 }
86
87
88 case PTRACE_POKEUSR: {
89 unsigned long index;
90
91 ret = -EIO;
92
93#ifdef CONFIG_PPC32
94 index = addr >> 2;
95 if ((addr & 3) || (index > PT_FPSCR)
96 || (child->thread.regs == NULL))
97#else
98 index = addr >> 3;
99 if ((addr & 7) || (index > PT_FPSCR))
100#endif
101 break;
102
103 CHECK_FULL_REGS(child->thread.regs);
104 if (index < PT_FPR0) {
105 ret = ptrace_put_reg(child, index, data);
106 } else {
107 unsigned int fpidx = index - PT_FPR0;
108
109 flush_fp_to_thread(child);
110 if (fpidx < (PT_FPSCR - PT_FPR0))
111 memcpy(&child->thread.TS_FPR(fpidx), &data,
112 sizeof(long));
113 else
114 child->thread.fp_state.fpscr = data;
115 ret = 0;
116 }
117 break;
118 }
119
120 case PPC_PTRACE_GETHWDBGINFO: {
121 struct ppc_debug_info dbginfo;
122
123 ppc_gethwdinfo(&dbginfo);
124
125 if (copy_to_user(datavp, &dbginfo,
126 sizeof(struct ppc_debug_info)))
127 return -EFAULT;
128 return 0;
129 }
130
131 case PPC_PTRACE_SETHWDEBUG: {
132 struct ppc_hw_breakpoint bp_info;
133
134 if (copy_from_user(&bp_info, datavp,
135 sizeof(struct ppc_hw_breakpoint)))
136 return -EFAULT;
137 return ppc_set_hwdebug(child, &bp_info);
138 }
139
140 case PPC_PTRACE_DELHWDEBUG: {
141 ret = ppc_del_hwdebug(child, data);
142 break;
143 }
144
145 case PTRACE_GET_DEBUGREG:
146 ret = ptrace_get_debugreg(child, addr, datalp);
147 break;
148
149 case PTRACE_SET_DEBUGREG:
150 ret = ptrace_set_debugreg(child, addr, data);
151 break;
152
153#ifdef CONFIG_PPC64
154 case PTRACE_GETREGS64:
155#endif
156 case PTRACE_GETREGS:
157 return copy_regset_to_user(child, &user_ppc_native_view,
158 REGSET_GPR,
159 0, sizeof(struct user_pt_regs),
160 datavp);
161
162#ifdef CONFIG_PPC64
163 case PTRACE_SETREGS64:
164#endif
165 case PTRACE_SETREGS:
166 return copy_regset_from_user(child, &user_ppc_native_view,
167 REGSET_GPR,
168 0, sizeof(struct user_pt_regs),
169 datavp);
170
171 case PTRACE_GETFPREGS:
172 return copy_regset_to_user(child, &user_ppc_native_view,
173 REGSET_FPR,
174 0, sizeof(elf_fpregset_t),
175 datavp);
176
177 case PTRACE_SETFPREGS:
178 return copy_regset_from_user(child, &user_ppc_native_view,
179 REGSET_FPR,
180 0, sizeof(elf_fpregset_t),
181 datavp);
182
183#ifdef CONFIG_ALTIVEC
184 case PTRACE_GETVRREGS:
185 return copy_regset_to_user(child, &user_ppc_native_view,
186 REGSET_VMX,
187 0, (33 * sizeof(vector128) +
188 sizeof(u32)),
189 datavp);
190
191 case PTRACE_SETVRREGS:
192 return copy_regset_from_user(child, &user_ppc_native_view,
193 REGSET_VMX,
194 0, (33 * sizeof(vector128) +
195 sizeof(u32)),
196 datavp);
197#endif
198#ifdef CONFIG_VSX
199 case PTRACE_GETVSRREGS:
200 return copy_regset_to_user(child, &user_ppc_native_view,
201 REGSET_VSX,
202 0, 32 * sizeof(double),
203 datavp);
204
205 case PTRACE_SETVSRREGS:
206 return copy_regset_from_user(child, &user_ppc_native_view,
207 REGSET_VSX,
208 0, 32 * sizeof(double),
209 datavp);
210#endif
211#ifdef CONFIG_SPE
212 case PTRACE_GETEVRREGS:
213
214 return copy_regset_to_user(child, &user_ppc_native_view,
215 REGSET_SPE, 0, 35 * sizeof(u32),
216 datavp);
217
218 case PTRACE_SETEVRREGS:
219
220 return copy_regset_from_user(child, &user_ppc_native_view,
221 REGSET_SPE, 0, 35 * sizeof(u32),
222 datavp);
223#endif
224
225 default:
226 ret = ptrace_request(child, request, addr, data);
227 break;
228 }
229 return ret;
230}
231
232#ifdef CONFIG_SECCOMP
233static int do_seccomp(struct pt_regs *regs)
234{
235 if (!test_thread_flag(TIF_SECCOMP))
236 return 0;
237
238
239
240
241
242
243
244 regs->gpr[3] = -ENOSYS;
245
246
247
248
249
250
251
252 if (__secure_computing(NULL))
253 return -1;
254
255
256
257
258
259
260
261
262 regs->gpr[3] = regs->orig_gpr3;
263
264 return 0;
265}
266#else
267static inline int do_seccomp(struct pt_regs *regs) { return 0; }
268#endif
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289long do_syscall_trace_enter(struct pt_regs *regs)
290{
291 u32 flags;
292
293 user_exit();
294
295 flags = READ_ONCE(current_thread_info()->flags) &
296 (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE);
297
298 if (flags) {
299 int rc = tracehook_report_syscall_entry(regs);
300
301 if (unlikely(flags & _TIF_SYSCALL_EMU)) {
302
303
304
305
306
307
308
309
310
311
312 return -1;
313 }
314
315 if (rc) {
316
317
318
319
320
321
322 goto skip;
323 }
324 }
325
326
327 if (do_seccomp(regs))
328 return -1;
329
330
331 if (regs->gpr[0] >= NR_syscalls)
332 goto skip;
333
334 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
335 trace_sys_enter(regs, regs->gpr[0]);
336
337 if (!is_32bit_task())
338 audit_syscall_entry(regs->gpr[0], regs->gpr[3], regs->gpr[4],
339 regs->gpr[5], regs->gpr[6]);
340 else
341 audit_syscall_entry(regs->gpr[0],
342 regs->gpr[3] & 0xffffffff,
343 regs->gpr[4] & 0xffffffff,
344 regs->gpr[5] & 0xffffffff,
345 regs->gpr[6] & 0xffffffff);
346
347
348 return regs->gpr[0];
349
350skip:
351
352
353
354
355 regs->gpr[3] = -ENOSYS;
356 return -1;
357}
358
359void do_syscall_trace_leave(struct pt_regs *regs)
360{
361 int step;
362
363 audit_syscall_exit(regs);
364
365 if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
366 trace_sys_exit(regs, regs->result);
367
368 step = test_thread_flag(TIF_SINGLESTEP);
369 if (step || test_thread_flag(TIF_SYSCALL_TRACE))
370 tracehook_report_syscall_exit(regs, step);
371
372 user_enter();
373}
374
375void __init pt_regs_check(void);
376
377
378
379
380
381void __init pt_regs_check(void)
382{
383 BUILD_BUG_ON(offsetof(struct pt_regs, gpr) !=
384 offsetof(struct user_pt_regs, gpr));
385 BUILD_BUG_ON(offsetof(struct pt_regs, nip) !=
386 offsetof(struct user_pt_regs, nip));
387 BUILD_BUG_ON(offsetof(struct pt_regs, msr) !=
388 offsetof(struct user_pt_regs, msr));
389 BUILD_BUG_ON(offsetof(struct pt_regs, msr) !=
390 offsetof(struct user_pt_regs, msr));
391 BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
392 offsetof(struct user_pt_regs, orig_gpr3));
393 BUILD_BUG_ON(offsetof(struct pt_regs, ctr) !=
394 offsetof(struct user_pt_regs, ctr));
395 BUILD_BUG_ON(offsetof(struct pt_regs, link) !=
396 offsetof(struct user_pt_regs, link));
397 BUILD_BUG_ON(offsetof(struct pt_regs, xer) !=
398 offsetof(struct user_pt_regs, xer));
399 BUILD_BUG_ON(offsetof(struct pt_regs, ccr) !=
400 offsetof(struct user_pt_regs, ccr));
401#ifdef __powerpc64__
402 BUILD_BUG_ON(offsetof(struct pt_regs, softe) !=
403 offsetof(struct user_pt_regs, softe));
404#else
405 BUILD_BUG_ON(offsetof(struct pt_regs, mq) !=
406 offsetof(struct user_pt_regs, mq));
407#endif
408 BUILD_BUG_ON(offsetof(struct pt_regs, trap) !=
409 offsetof(struct user_pt_regs, trap));
410 BUILD_BUG_ON(offsetof(struct pt_regs, dar) !=
411 offsetof(struct user_pt_regs, dar));
412 BUILD_BUG_ON(offsetof(struct pt_regs, dsisr) !=
413 offsetof(struct user_pt_regs, dsisr));
414 BUILD_BUG_ON(offsetof(struct pt_regs, result) !=
415 offsetof(struct user_pt_regs, result));
416
417 BUILD_BUG_ON(sizeof(struct user_pt_regs) > sizeof(struct pt_regs));
418
419
420 #define CHECK_REG(_pt, _reg) \
421 BUILD_BUG_ON(_pt != (offsetof(struct user_pt_regs, _reg) / \
422 sizeof(unsigned long)));
423
424 CHECK_REG(PT_R0, gpr[0]);
425 CHECK_REG(PT_R1, gpr[1]);
426 CHECK_REG(PT_R2, gpr[2]);
427 CHECK_REG(PT_R3, gpr[3]);
428 CHECK_REG(PT_R4, gpr[4]);
429 CHECK_REG(PT_R5, gpr[5]);
430 CHECK_REG(PT_R6, gpr[6]);
431 CHECK_REG(PT_R7, gpr[7]);
432 CHECK_REG(PT_R8, gpr[8]);
433 CHECK_REG(PT_R9, gpr[9]);
434 CHECK_REG(PT_R10, gpr[10]);
435 CHECK_REG(PT_R11, gpr[11]);
436 CHECK_REG(PT_R12, gpr[12]);
437 CHECK_REG(PT_R13, gpr[13]);
438 CHECK_REG(PT_R14, gpr[14]);
439 CHECK_REG(PT_R15, gpr[15]);
440 CHECK_REG(PT_R16, gpr[16]);
441 CHECK_REG(PT_R17, gpr[17]);
442 CHECK_REG(PT_R18, gpr[18]);
443 CHECK_REG(PT_R19, gpr[19]);
444 CHECK_REG(PT_R20, gpr[20]);
445 CHECK_REG(PT_R21, gpr[21]);
446 CHECK_REG(PT_R22, gpr[22]);
447 CHECK_REG(PT_R23, gpr[23]);
448 CHECK_REG(PT_R24, gpr[24]);
449 CHECK_REG(PT_R25, gpr[25]);
450 CHECK_REG(PT_R26, gpr[26]);
451 CHECK_REG(PT_R27, gpr[27]);
452 CHECK_REG(PT_R28, gpr[28]);
453 CHECK_REG(PT_R29, gpr[29]);
454 CHECK_REG(PT_R30, gpr[30]);
455 CHECK_REG(PT_R31, gpr[31]);
456 CHECK_REG(PT_NIP, nip);
457 CHECK_REG(PT_MSR, msr);
458 CHECK_REG(PT_ORIG_R3, orig_gpr3);
459 CHECK_REG(PT_CTR, ctr);
460 CHECK_REG(PT_LNK, link);
461 CHECK_REG(PT_XER, xer);
462 CHECK_REG(PT_CCR, ccr);
463#ifdef CONFIG_PPC64
464 CHECK_REG(PT_SOFTE, softe);
465#else
466 CHECK_REG(PT_MQ, mq);
467#endif
468 CHECK_REG(PT_TRAP, trap);
469 CHECK_REG(PT_DAR, dar);
470 CHECK_REG(PT_DSISR, dsisr);
471 CHECK_REG(PT_RESULT, result);
472 #undef CHECK_REG
473
474 BUILD_BUG_ON(PT_REGS_COUNT != sizeof(struct user_pt_regs) / sizeof(unsigned long));
475
476
477
478
479
480 BUILD_BUG_ON(PT_DSCR < sizeof(struct user_pt_regs) / sizeof(unsigned long));
481}
482