// SPDX-License-Identifier: GPL-2.0-or-later /* * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * * Derived from "arch/m68k/kernel/ptrace.c" * Copyright (C) 1994 by Hamish Macdonald * Taken from linux/kernel/ptrace.c and modified for M680x0. * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds * * Modified by Cort Dougan (cort@hq.fsmlabs.com) * and Paul Mackerras (paulus@samba.org).
*/
/* * Called by kernel/ptrace.c when detaching.. * * Make sure single step bits etc are not set.
*/ void ptrace_disable(struct task_struct *child)
{ /* make sure the single step bit is not set. */
user_disable_single_step(child);
}
long arch_ptrace(struct task_struct *child, long request, unsignedlong addr, unsignedlong data)
{ int ret = -EPERM; void __user *datavp = (void __user *) data; unsignedlong __user *datalp = datavp;
switch (request) { /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: { unsignedlong index, tmp;
ret = -EIO; /* convert to index and check */
index = addr / sizeof(long); if ((addr & (sizeof(long) - 1)) || !child->thread.regs) break;
if (index < PT_FPR0)
ret = ptrace_get_reg(child, (int) index, &tmp); else
ret = ptrace_get_fpr(child, index, &tmp);
if (ret) break;
ret = put_user(tmp, datalp); break;
}
/* write the word at location addr in the USER area */ case PTRACE_POKEUSR: { unsignedlong index;
ret = -EIO; /* convert to index and check */
index = addr / sizeof(long); if ((addr & (sizeof(long) - 1)) || !child->thread.regs) break;
if (index < PT_FPR0)
ret = ptrace_put_reg(child, index, data); else
ret = ptrace_put_fpr(child, index, data); break;
}
case PPC_PTRACE_GETHWDBGINFO: { struct ppc_debug_info dbginfo;
ppc_gethwdinfo(&dbginfo);
if (copy_to_user(datavp, &dbginfo, sizeof(struct ppc_debug_info))) return -EFAULT; return 0;
}
case PPC_PTRACE_SETHWDEBUG: { struct ppc_hw_breakpoint bp_info;
case PPC_PTRACE_DELHWDEBUG: {
ret = ppc_del_hwdebug(child, data); break;
}
case PTRACE_GET_DEBUGREG:
ret = ptrace_get_debugreg(child, addr, datalp); break;
case PTRACE_SET_DEBUGREG:
ret = ptrace_set_debugreg(child, addr, data); break;
#ifdef CONFIG_PPC64 case PTRACE_GETREGS64: #endif case PTRACE_GETREGS: /* Get all pt_regs from the child. */ return copy_regset_to_user(child, &user_ppc_native_view,
REGSET_GPR,
0, sizeof(struct user_pt_regs),
datavp);
#ifdef CONFIG_PPC64 case PTRACE_SETREGS64: #endif case PTRACE_SETREGS: /* Set all gp regs in the child. */ return copy_regset_from_user(child, &user_ppc_native_view,
REGSET_GPR,
0, sizeof(struct user_pt_regs),
datavp);
case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */ return copy_regset_to_user(child, &user_ppc_native_view,
REGSET_FPR,
0, sizeof(elf_fpregset_t),
datavp);
case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */ return copy_regset_from_user(child, &user_ppc_native_view,
REGSET_FPR,
0, sizeof(elf_fpregset_t),
datavp);
/* * The ABI we present to seccomp tracers is that r3 contains * the syscall return value and orig_gpr3 contains the first * syscall parameter. This is different to the ptrace ABI where * both r3 and orig_gpr3 contain the first syscall parameter.
*/
regs->gpr[3] = -ENOSYS;
/* * We use the __ version here because we have already checked * TIF_SECCOMP. If this fails, there is nothing left to do, we * have already loaded -ENOSYS into r3, or seccomp has put * something else in r3 (via SECCOMP_RET_ERRNO/TRACE).
*/ if (__secure_computing()) return -1;
/* * The syscall was allowed by seccomp, restore the register * state to what audit expects. * Note that we use orig_gpr3, which means a seccomp tracer can * modify the first syscall parameter (in orig_gpr3) and also * allow the syscall to proceed.
*/
regs->gpr[3] = regs->orig_gpr3;
/** * do_syscall_trace_enter() - Do syscall tracing on kernel entry. * @regs: the pt_regs of the task to trace (current) * * Performs various types of tracing on syscall entry. This includes seccomp, * ptrace, syscall tracepoints and audit. * * The pt_regs are potentially visible to userspace via ptrace, so their * contents is ABI. * * One or more of the tracers may modify the contents of pt_regs, in particular * to modify arguments or even the syscall number itself. * * It's also possible that a tracer can choose to reject the system call. In * that case this function will return an illegal syscall number, and will put * an appropriate return value in regs->r3. * * Return: the (possibly changed) syscall number.
*/ long do_syscall_trace_enter(struct pt_regs *regs)
{
u32 flags;
if (flags) { int rc = ptrace_report_syscall_entry(regs);
if (unlikely(flags & _TIF_SYSCALL_EMU)) { /* * A nonzero return code from * ptrace_report_syscall_entry() tells us to prevent * the syscall execution, but we are not going to * execute it anyway. * * Returning -1 will skip the syscall execution. We want * to avoid clobbering any registers, so we don't goto * the skip label below.
*/ return -1;
}
if (rc) { /* * The tracer decided to abort the syscall. Note that * the tracer may also just change regs->gpr[0] to an * invalid syscall number, that is handled below on the * exit path.
*/ goto skip;
}
}
/* Run seccomp after ptrace; allow it to set gpr[3]. */ if (do_seccomp(regs)) return -1;
/* Avoid trace and audit when syscall is invalid. */ if (regs->gpr[0] >= NR_syscalls) goto skip;
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_enter(regs, regs->gpr[0]);
/* Return the possibly modified but valid syscall number */ return regs->gpr[0];
skip: /* * If we are aborting explicitly, or if the syscall number is * now invalid, set the return value to -ENOSYS.
*/
regs->gpr[3] = -ENOSYS; return -1;
}
void do_syscall_trace_leave(struct pt_regs *regs)
{ int step;
audit_syscall_exit(regs);
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
trace_sys_exit(regs, regs->result);
step = test_thread_flag(TIF_SINGLESTEP); if (step || test_thread_flag(TIF_SYSCALL_TRACE))
ptrace_report_syscall_exit(regs, step);
}
// Now check that the pt_regs offsets match the uapi #defines #define CHECK_REG(_pt, _reg) \
BUILD_BUG_ON(_pt != (offsetof(struct user_pt_regs, _reg) / \ sizeof(unsignedlong)));
/* * PT_DSCR isn't a real reg, but it's important that it doesn't overlap the * real registers.
*/
BUILD_BUG_ON(PT_DSCR < sizeof(struct user_pt_regs) / sizeof(unsignedlong));
// ptrace_get/put_fpr() rely on PPC32 and VSX being incompatible
BUILD_BUG_ON(IS_ENABLED(CONFIG_PPC32) && IS_ENABLED(CONFIG_VSX));
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.