git: 9cea869940f1 - main - ptrace: split sys_ptrace()/freebsd32_ptrace()
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 28 Aug 2026 12:05:06 UTC
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=9cea869940f197d558f640b6851d44a213be9e8a
commit 9cea869940f197d558f640b6851d44a213be9e8a
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-07-19 21:33:54 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-08-28 11:52:32 +0000
ptrace: split sys_ptrace()/freebsd32_ptrace()
The code to handle copyin and copyout of the structured parameters is
moved into the helpers.
Reviewed by: markj
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Differential revision: https://reviews.freebsd.org/D58586
---
sys/compat/freebsd32/freebsd32_misc.c | 129 +++++++++++++++++-----------------
sys/kern/sys_process.c | 114 ++++++++++++++++--------------
sys/sys/ptrace.h | 2 +
3 files changed, 128 insertions(+), 117 deletions(-)
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index 08e15140317d..5b5a13a16de1 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -1015,8 +1015,9 @@ ptrace_sc_ret32_to_ret(const struct ptrace_sc_ret32 *psr32,
psr->sr_error = psr32->sr_error;
}
-int
-freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
+static int
+freebsd32_ptrace_useraction(struct thread *td, int req, pid_t pid,
+ void *uaddr, int udata)
{
union {
struct ptrace_io_desc piod;
@@ -1050,39 +1051,32 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
if (!allow_ptrace)
return (ENOSYS);
- error = 0;
- AUDIT_ARG_PID(uap->pid);
- AUDIT_ARG_CMD(uap->req);
- AUDIT_ARG_VALUE(uap->data);
+ error = 0;
addr = &r;
- data = uap->data;
- switch (uap->req) {
+ data = udata;
+
+ switch (req) {
case PT_GET_EVENT_MASK:
case PT_GET_SC_ARGS:
case PT_GET_SC_RET:
break;
case PT_SET_SC_RET:
- if (uap->data != sizeof(r32.psr)) {
- error = EINVAL;
- } else {
- error = copyin(uap->addr, &r32.psr, sizeof(r32.psr));
- if (error == 0)
- ptrace_sc_ret32_to_ret(&r32.psr, &r.psr);
- }
+ error = udata != sizeof(r32.psr) ? EINVAL :
+ copyin(uaddr, &r32.psr, sizeof(r32.psr));
+ if (error == 0)
+ ptrace_sc_ret32_to_ret(&r32.psr, &r.psr);
break;
case PT_LWPINFO:
- if (uap->data > sizeof(r32.pl))
+ if (udata > sizeof(r32.pl))
return (EINVAL);
-
/*
* Pass size of native structure in 'data'. Truncate
* if necessary to avoid siginfo.
*/
- data = sizeof(r.pl);
- if (uap->data < offsetof(struct ptrace_lwpinfo32, pl_siginfo) +
- sizeof(struct __siginfo32))
- data = offsetof(struct ptrace_lwpinfo, pl_siginfo);
+ data = udata < offsetof(struct ptrace_lwpinfo32,
+ pl_siginfo) + sizeof(struct __siginfo32) ?
+ offsetof(struct ptrace_lwpinfo, pl_siginfo) : sizeof(r.pl);
break;
case PT_GETREGS:
bzero(&r.reg, sizeof(r.reg));
@@ -1094,17 +1088,17 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
bzero(&r.dbreg, sizeof(r.dbreg));
break;
case PT_SETREGS:
- error = copyin(uap->addr, &r.reg, sizeof(r.reg));
+ error = copyin(uaddr, &r.reg, sizeof(r.reg));
break;
case PT_SETFPREGS:
- error = copyin(uap->addr, &r.fpreg, sizeof(r.fpreg));
+ error = copyin(uaddr, &r.fpreg, sizeof(r.fpreg));
break;
case PT_SETDBREGS:
- error = copyin(uap->addr, &r.dbreg, sizeof(r.dbreg));
+ error = copyin(uaddr, &r.dbreg, sizeof(r.dbreg));
break;
case PT_GETREGSET:
case PT_SETREGSET:
- error = copyin(uap->addr, &r32.vec, sizeof(r32.vec));
+ error = copyin(uaddr, &r32.vec, sizeof(r32.vec));
if (error != 0)
break;
@@ -1112,14 +1106,12 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
r.vec.iov_base = PTRIN(r32.vec.iov_base);
break;
case PT_SET_EVENT_MASK:
- if (uap->data != sizeof(r.ptevents))
- error = EINVAL;
- else
- error = copyin(uap->addr, &r.ptevents, uap->data);
+ error = udata != sizeof(r.ptevents) ? EINVAL :
+ copyin(uaddr, &r.ptevents, udata);
break;
case PT_IO:
- error = copyin(uap->addr, &r32.piod, sizeof(r32.piod));
- if (error)
+ error = copyin(uaddr, &r32.piod, sizeof(r32.piod));
+ if (error != 0)
break;
CP(r32.piod, r.piod, piod_op);
PTRIN_CP(r32.piod, r.piod, piod_offs);
@@ -1127,8 +1119,8 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
CP(r32.piod, r.piod, piod_len);
break;
case PT_VM_ENTRY:
- error = copyin(uap->addr, &r32.pve, sizeof(r32.pve));
- if (error)
+ error = copyin(uaddr, &r32.pve, sizeof(r32.pve));
+ if (error != 0)
break;
CP(r32.pve, r.pve, pve_entry);
@@ -1143,21 +1135,18 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
PTRIN_CP(r32.pve, r.pve, pve_path);
break;
case PT_COREDUMP:
- if (uap->data != sizeof(r32.pc))
- error = EINVAL;
- else
- error = copyin(uap->addr, &r32.pc, uap->data);
+ error = udata != sizeof(r32.pc) ? EINVAL :
+ copyin(uaddr, &r32.pc, udata);
+ if (error != 0)
+ break;
CP(r32.pc, r.pc, pc_fd);
CP(r32.pc, r.pc, pc_flags);
r.pc.pc_limit = PAIR32TO64(off_t, r32.pc.pc_limit);
data = sizeof(r.pc);
break;
case PT_SC_REMOTE:
- if (uap->data != sizeof(r32.sr)) {
- error = EINVAL;
- break;
- }
- error = copyin(uap->addr, &r32.sr, uap->data);
+ error = udata != sizeof(r32.sr) ? EINVAL :
+ copyin(uaddr, &r32.sr, udata);
if (error != 0)
break;
CP(r32.sr, r.sr, pscr_syscall);
@@ -1175,9 +1164,9 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
r.sr.pscr_args = pscr_args;
break;
case PT_GET_CHILDREN:
- if (uap->addr == NULL)
+ if (uaddr == NULL)
addr = NULL;
- else if (uap->data < 0)
+ else if (udata < 0)
error = EINVAL;
else
addr = &r.children;
@@ -1186,17 +1175,17 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
error = EINVAL;
break;
default:
- addr = uap->addr;
+ addr = uaddr;
break;
}
- if (error)
+ if (error != 0)
return (error);
- error = kern_ptrace(td, uap->req, uap->pid, addr, data);
- if (error)
+ error = ptrace_action(td, req, pid, addr, data);
+ if (error != 0)
return (error);
- switch (uap->req) {
+ switch (req) {
case PT_VM_ENTRY:
CP(r.pve, r32.pve, pve_entry);
CP(r.pve, r32.pve, pve_timestamp);
@@ -1207,53 +1196,51 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
CP(r.pve, r32.pve, pve_pathlen);
CP(r.pve, r32.pve, pve_fileid);
CP(r.pve, r32.pve, pve_fsid);
- error = copyout(&r32.pve, uap->addr, sizeof(r32.pve));
+ error = copyout(&r32.pve, uaddr, sizeof(r32.pve));
break;
case PT_IO:
CP(r.piod, r32.piod, piod_len);
- error = copyout(&r32.piod, uap->addr, sizeof(r32.piod));
+ error = copyout(&r32.piod, uaddr, sizeof(r32.piod));
break;
case PT_GETREGS:
- error = copyout(&r.reg, uap->addr, sizeof(r.reg));
+ error = copyout(&r.reg, uaddr, sizeof(r.reg));
break;
case PT_GETFPREGS:
- error = copyout(&r.fpreg, uap->addr, sizeof(r.fpreg));
+ error = copyout(&r.fpreg, uaddr, sizeof(r.fpreg));
break;
case PT_GETDBREGS:
- error = copyout(&r.dbreg, uap->addr, sizeof(r.dbreg));
+ error = copyout(&r.dbreg, uaddr, sizeof(r.dbreg));
break;
case PT_GETREGSET:
r32.vec.iov_len = r.vec.iov_len;
- error = copyout(&r32.vec, uap->addr, sizeof(r32.vec));
+ error = copyout(&r32.vec, uaddr, sizeof(r32.vec));
break;
case PT_GET_EVENT_MASK:
/* NB: The size in uap->data is validated in kern_ptrace(). */
- error = copyout(&r.ptevents, uap->addr, uap->data);
+ error = copyout(&r.ptevents, uaddr, udata);
break;
case PT_LWPINFO:
ptrace_lwpinfo_to32(&r.pl, &r32.pl);
- error = copyout(&r32.pl, uap->addr, uap->data);
+ error = copyout(&r32.pl, uaddr, udata);
break;
case PT_GET_SC_ARGS:
for (i = 0; i < nitems(r.args); i++)
r32.args[i] = (uint32_t)r.args[i];
- error = copyout(r32.args, uap->addr, MIN(uap->data,
- sizeof(r32.args)));
+ error = copyout(r32.args, uaddr, MIN(udata, sizeof(r32.args)));
break;
case PT_GET_SC_RET:
ptrace_sc_ret_to32(&r.psr, &r32.psr);
- error = copyout(&r32.psr, uap->addr, MIN(uap->data,
- sizeof(r32.psr)));
+ error = copyout(&r32.psr, uaddr, MIN(udata, sizeof(r32.psr)));
break;
case PT_SC_REMOTE:
ptrace_sc_ret_to32(&r.sr.pscr_ret, &r32.sr.pscr_ret);
- error = copyout(&r32.sr.pscr_ret, uap->addr +
+ error = copyout(&r32.sr.pscr_ret, (char *)uaddr +
offsetof(struct ptrace_sc_remote32, pscr_ret),
sizeof(r32.psr));
break;
case PT_GET_CHILDREN:
- if (uap->addr != 0) {
- error = copyout(r.children, uap->addr,
+ if (uaddr != NULL) {
+ error = copyout(r.children, uaddr,
td->td_retval[0] * sizeof(struct ptrace_child));
free(r.children, M_TEMP);
}
@@ -1263,6 +1250,20 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
return (error);
}
+int
+freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
+{
+ int error;
+
+ AUDIT_ARG_PID(uap->pid);
+ AUDIT_ARG_CMD(uap->req);
+ AUDIT_ARG_VALUE(uap->data);
+
+ error = freebsd32_ptrace_useraction(td, uap->req, uap->pid,
+ uap->addr, uap->data);
+ return (error);
+}
+
int
freebsd32_copyinuio(const struct iovec32 *iovp, u_int iovcnt, struct uio **uiop)
{
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 46848ca150c0..39196561928c 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -714,8 +714,9 @@ struct ptrace_args {
};
#endif
-int
-sys_ptrace(struct thread *td, struct ptrace_args *uap)
+static int
+ptrace_useraction(struct thread *td, int req, pid_t pid, void *uaddr,
+ int udata)
{
/*
* XXX this obfuscation is to reduce stack usage, but the register
@@ -742,23 +743,19 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
if (!allow_ptrace)
return (ENOSYS);
- error = 0;
- AUDIT_ARG_PID(uap->pid);
- AUDIT_ARG_CMD(uap->req);
- AUDIT_ARG_VALUE(uap->data);
+ error = 0;
addr = &r;
- switch (uap->req) {
+
+ switch (req) {
case PT_GET_EVENT_MASK:
case PT_LWPINFO:
case PT_GET_SC_ARGS:
case PT_GET_SC_RET:
break;
case PT_SET_SC_RET:
- if (uap->data != sizeof(r.psr))
- error = EINVAL;
- else
- error = copyin(uap->addr, &r.psr, sizeof(r.psr));
+ error = udata != sizeof(r.psr) ? EINVAL :
+ copyin(uaddr, &r.psr, sizeof(r.psr));
break;
case PT_GETREGS:
bzero(&r.reg, sizeof(r.reg));
@@ -771,41 +768,34 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
break;
case PT_GETREGSET:
case PT_SETREGSET:
- error = copyin(uap->addr, &r.vec, sizeof(r.vec));
+ error = copyin(uaddr, &r.vec, sizeof(r.vec));
break;
case PT_SETREGS:
- error = copyin(uap->addr, &r.reg, sizeof(r.reg));
+ error = copyin(uaddr, &r.reg, sizeof(r.reg));
break;
case PT_SETFPREGS:
- error = copyin(uap->addr, &r.fpreg, sizeof(r.fpreg));
+ error = copyin(uaddr, &r.fpreg, sizeof(r.fpreg));
break;
case PT_SETDBREGS:
- error = copyin(uap->addr, &r.dbreg, sizeof(r.dbreg));
+ error = copyin(uaddr, &r.dbreg, sizeof(r.dbreg));
break;
case PT_SET_EVENT_MASK:
- if (uap->data != sizeof(r.ptevents))
- error = EINVAL;
- else
- error = copyin(uap->addr, &r.ptevents, uap->data);
+ error = udata != sizeof(r.ptevents) ? EINVAL :
+ copyin(uaddr, &r.ptevents, udata);
break;
case PT_IO:
- error = copyin(uap->addr, &r.piod, sizeof(r.piod));
+ error = copyin(uaddr, &r.piod, sizeof(r.piod));
break;
case PT_VM_ENTRY:
- error = copyin(uap->addr, &r.pve, sizeof(r.pve));
+ error = copyin(uaddr, &r.pve, sizeof(r.pve));
break;
case PT_COREDUMP:
- if (uap->data != sizeof(r.pc))
- error = EINVAL;
- else
- error = copyin(uap->addr, &r.pc, uap->data);
+ error = udata != sizeof(r.pc) ? EINVAL :
+ copyin(uaddr, &r.pc, udata);
break;
case PT_SC_REMOTE:
- if (uap->data != sizeof(r.sr)) {
- error = EINVAL;
- break;
- }
- error = copyin(uap->addr, &r.sr, uap->data);
+ error = udata != sizeof(r.sr) ? EINVAL :
+ copyin(uaddr, &r.sr, udata);
if (error != 0)
break;
if (r.sr.pscr_nargs > nitems(td->td_sa.args)) {
@@ -819,9 +809,9 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
r.sr.pscr_args = pscr_args;
break;
case PT_GET_CHILDREN:
- if (uap->addr == NULL)
+ if (uaddr == NULL)
addr = NULL;
- else if (uap->data < 0)
+ else if (udata < 0)
error = EINVAL;
else
addr = &r.children;
@@ -830,59 +820,57 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
error = EINVAL;
break;
default:
- addr = uap->addr;
+ addr = uaddr;
break;
}
if (error != 0)
return (error);
- error = kern_ptrace(td, uap->req, uap->pid, addr, uap->data);
+ error = ptrace_action(td, req, pid, addr, udata);
if (error != 0)
return (error);
- switch (uap->req) {
+ switch (req) {
case PT_VM_ENTRY:
- error = copyout(&r.pve, uap->addr, sizeof(r.pve));
+ error = copyout(&r.pve, uaddr, sizeof(r.pve));
break;
case PT_IO:
- error = copyout(&r.piod, uap->addr, sizeof(r.piod));
+ error = copyout(&r.piod, uaddr, sizeof(r.piod));
break;
case PT_GETREGS:
- error = copyout(&r.reg, uap->addr, sizeof(r.reg));
+ error = copyout(&r.reg, uaddr, sizeof(r.reg));
break;
case PT_GETFPREGS:
- error = copyout(&r.fpreg, uap->addr, sizeof(r.fpreg));
+ error = copyout(&r.fpreg, uaddr, sizeof(r.fpreg));
break;
case PT_GETDBREGS:
- error = copyout(&r.dbreg, uap->addr, sizeof(r.dbreg));
+ error = copyout(&r.dbreg, uaddr, sizeof(r.dbreg));
break;
case PT_GETREGSET:
- error = copyout(&r.vec, uap->addr, sizeof(r.vec));
+ error = copyout(&r.vec, uaddr, sizeof(r.vec));
break;
case PT_GET_EVENT_MASK:
- /* NB: The size in uap->data is validated in kern_ptrace(). */
- error = copyout(&r.ptevents, uap->addr, uap->data);
+ /* NB: The size in uap->data is validated in ptraceimpl(). */
+ error = copyout(&r.ptevents, uaddr, udata);
break;
case PT_LWPINFO:
- /* NB: The size in uap->data is validated in kern_ptrace(). */
- error = copyout(&r.pl, uap->addr, uap->data);
+ /* NB: The size in uap->data is validated in ptraceimpl(). */
+ error = copyout(&r.pl, uaddr, udata);
break;
case PT_GET_SC_ARGS:
- error = copyout(r.args, uap->addr, MIN(uap->data,
- sizeof(r.args)));
+ error = copyout(r.args, uaddr, MIN(udata, sizeof(r.args)));
break;
case PT_GET_SC_RET:
- error = copyout(&r.psr, uap->addr, MIN(uap->data,
- sizeof(r.psr)));
+ error = copyout(&r.psr, uaddr, MIN(udata, sizeof(r.psr)));
break;
case PT_SC_REMOTE:
- error = copyout(&r.sr.pscr_ret, uap->addr +
+ error = copyout(&r.sr.pscr_ret, (char *)uaddr +
offsetof(struct ptrace_sc_remote, pscr_ret),
sizeof(r.sr.pscr_ret));
break;
case PT_GET_CHILDREN:
- if (uap->addr != NULL) {
- error = copyout(r.children, uap->addr,
+ if (uaddr != NULL) {
+ error = copyout(r.children, uaddr,
td->td_retval[0] * sizeof(struct ptrace_child));
free(r.children, M_TEMP);
}
@@ -1056,7 +1044,7 @@ ptrace_sel_coredump_thread(struct proc *p)
}
int
-kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
+ptrace_action(struct thread *td, int req, pid_t pid, void *addr, int data)
{
struct iovec iov;
struct uio uio;
@@ -2027,3 +2015,23 @@ fail:
}
#undef PROC_READ
#undef PROC_WRITE
+
+int
+kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
+{
+ return (ptrace_action(td, req, pid, addr, data));
+}
+
+int
+sys_ptrace(struct thread *td, struct ptrace_args *uap)
+{
+ int error;
+
+ AUDIT_ARG_PID(uap->pid);
+ AUDIT_ARG_CMD(uap->req);
+ AUDIT_ARG_VALUE(uap->data);
+
+ error = ptrace_useraction(td, uap->req, uap->pid, uap->addr,
+ uap->data);
+ return (error);
+}
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index 54669493ca75..50e7dba5c946 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -291,6 +291,8 @@ int proc_write_dbregs32(struct thread *_td, struct dbreg32 *_dbreg32);
#endif
void ptrace_unsuspend(struct proc *p);
+int ptrace_action(struct thread *td, int req, pid_t pid, void *addr,
+ int data);
extern bool allow_ptrace;