The branch main has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=9cea869940f197d558f640b6851d44a213be9e8a

commit 9cea869940f197d558f640b6851d44a213be9e8a
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2026-07-19 21:33:54 +0000
Commit:     Konstantin Belousov <[email protected]>
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;
 

Reply via email to