| 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()) |
| 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 | |