The branch main has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=f8c0616052e2befaf7271fa82b212ff34a7913af
commit f8c0616052e2befaf7271fa82b212ff34a7913af 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 Add pdptrace(2) 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 | 24 +++++++--- sys/kern/sys_process.c | 83 +++++++++++++++++++++++++---------- sys/kern/syscalls.master | 9 ++++ sys/sys/ptrace.h | 4 +- 4 files changed, 91 insertions(+), 29 deletions(-) diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index 5b5a13a16de1..103a40f221ac 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -1016,8 +1016,8 @@ ptrace_sc_ret32_to_ret(const struct ptrace_sc_ret32 *psr32, } static int -freebsd32_ptrace_useraction(struct thread *td, int req, pid_t pid, - void *uaddr, int udata) +freebsd32_ptrace_useraction(struct thread *td, int req, bool pd_mode, pid_t pid, + int pfd, lwpid_t lwpid, void *uaddr, int udata) { union { struct ptrace_io_desc piod; @@ -1181,7 +1181,7 @@ freebsd32_ptrace_useraction(struct thread *td, int req, pid_t pid, if (error != 0) return (error); - error = ptrace_action(td, req, pid, addr, data); + error = ptrace_action(td, req, pd_mode, pid, pfd, lwpid, addr, data); if (error != 0) return (error); @@ -1259,8 +1259,22 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap) AUDIT_ARG_CMD(uap->req); AUDIT_ARG_VALUE(uap->data); - error = freebsd32_ptrace_useraction(td, uap->req, uap->pid, - uap->addr, uap->data); + error = freebsd32_ptrace_useraction(td, uap->req, false, uap->pid, + -1, -1, uap->addr, uap->data); + return (error); +} + +int +freebsd32_pdptrace(struct thread *td, struct freebsd32_pdptrace_args *uap) +{ + int error; + + AUDIT_ARG_FD(uap->pfd); + AUDIT_ARG_CMD(uap->req); + AUDIT_ARG_VALUE(uap->data); + + error = freebsd32_ptrace_useraction(td, uap->req, true, -1, + uap->pfd, uap->lwpid, uap->addr, uap->data); return (error); } diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index 39196561928c..94dbb8215a1e 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -32,7 +32,7 @@ */ #include <sys/systm.h> -#include <sys/caprights.h> +#include <sys/capsicum.h> #include <sys/filedesc.h> #include <sys/imgact.h> #include <sys/ktr.h> @@ -43,6 +43,7 @@ #include <sys/mutex.h> #include <sys/priv.h> #include <sys/proc.h> +#include <sys/procdesc.h> #include <sys/ptrace.h> #include <sys/reg.h> #include <sys/rwlock.h> @@ -715,8 +716,8 @@ struct ptrace_args { #endif static int -ptrace_useraction(struct thread *td, int req, pid_t pid, void *uaddr, - int udata) +ptrace_useraction(struct thread *td, int req, bool pd_mode, pid_t pid, int pfd, + lwpid_t lwpid, void *uaddr, int udata) { /* * XXX this obfuscation is to reduce stack usage, but the register @@ -826,7 +827,7 @@ ptrace_useraction(struct thread *td, int req, pid_t pid, void *uaddr, if (error != 0) return (error); - error = ptrace_action(td, req, pid, addr, udata); + error = ptrace_action(td, req, pd_mode, pid, pfd, lwpid, addr, udata); if (error != 0) return (error); @@ -1044,7 +1045,8 @@ ptrace_sel_coredump_thread(struct proc *p) } int -ptrace_action(struct thread *td, int req, pid_t pid, void *addr, int data) +ptrace_action(struct thread *td, int req, bool pd_mode, pid_t pid, int pfd, + lwpid_t lwpid, void *addr, int data) { struct iovec iov; struct uio uio; @@ -1058,6 +1060,7 @@ ptrace_action(struct thread *td, int req, pid_t pid, void *addr, int data) struct ptrace_coredump *pc; struct thr_coredump_req *tcq; struct thr_syscall_req *tsr; + struct file *pfp; struct ptrace_child *children, *ptc; int error, num, num1, tmp; lwpid_t tid = 0, *buf; @@ -1069,6 +1072,7 @@ ptrace_action(struct thread *td, int req, pid_t pid, void *addr, int data) curp = td->td_proc; proctree_locked = false; p2_req_set = false; + pfp = NULL; /* Lock proctree before locking the process. */ switch (req) { @@ -1096,24 +1100,42 @@ ptrace_action(struct thread *td, int req, pid_t pid, void *addr, int data) if (req == PT_TRACE_ME) { p = td->td_proc; PROC_LOCK(p); - } else { - if (pid <= PID_MAX) { - if ((p = pfind(pid)) == NULL) { - if (proctree_locked) - sx_xunlock(&proctree_lock); - return (ESRCH); + } else if (pd_mode) { + if (!proctree_locked) + sx_slock(&proctree_lock); + error = fget_procdesc(td, pfd, &cap_ptrace_rights, EINVAL, + &pfp, NULL, &p); + if (!proctree_locked) + sx_sunlock(&proctree_lock); + if (error != 0) + goto fail_proctree; + pid = p->p_pid; + if (lwpid != -1) { + FOREACH_THREAD_IN_PROC(p, td2) { + if (td2->td_tid == lwpid) + break; } - } else { - td2 = tdfind(pid, -1); if (td2 == NULL) { - if (proctree_locked) - sx_xunlock(&proctree_lock); - return (ESRCH); + PROC_UNLOCK(p); + error = ESRCH; + goto fail_proctree; } - p = td2->td_proc; - tid = pid; - pid = p->p_pid; + tid = td2->td_tid; + } + } else if (pid <= PID_MAX) { + if ((p = pfind(pid)) == NULL) { + error = ESRCH; + goto fail_proctree; + } + } else { + td2 = tdfind(pid, -1); + if (td2 == NULL) { + error = ESRCH; + goto fail_proctree; } + p = td2->td_proc; + tid = pid; + pid = p->p_pid; } AUDIT_ARG_PROCESS(p); @@ -2009,8 +2031,11 @@ fail: p->p_flag2 &= ~P2_PTRACEREQ; } PROC_UNLOCK(p); +fail_proctree: if (proctree_locked) sx_xunlock(&proctree_lock); + if (pfp != NULL) + fdrop(pfp, td); return (error); } #undef PROC_READ @@ -2019,7 +2044,7 @@ fail: int kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data) { - return (ptrace_action(td, req, pid, addr, data)); + return (ptrace_action(td, req, false, pid, -1, -1, addr, data)); } int @@ -2031,7 +2056,21 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap) AUDIT_ARG_CMD(uap->req); AUDIT_ARG_VALUE(uap->data); - error = ptrace_useraction(td, uap->req, uap->pid, uap->addr, - uap->data); + error = ptrace_useraction(td, uap->req, false, uap->pid, -1, -1, + uap->addr, uap->data); + return (error); +} + +int +sys_pdptrace(struct thread *td, struct pdptrace_args *uap) +{ + int error; + + AUDIT_ARG_FD(uap->pfd); + AUDIT_ARG_CMD(uap->req); + AUDIT_ARG_VALUE(uap->data); + + error = ptrace_useraction(td, uap->req, true, -1, uap->pfd, uap->lwpid, + uap->addr, uap->data); return (error); } diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 64145f2c3e57..7050e564903e 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -3442,5 +3442,14 @@ int flags ); } +605 AUE_PDPTRACE STD { + int pdptrace( + int req, + int pfd, + int lwpid, + _Inout_opt_ _Contains_long_ptr_ void *addr, + int data + ); + } ; vim: syntax=off diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h index 50e7dba5c946..52f13d4d6790 100644 --- a/sys/sys/ptrace.h +++ b/sys/sys/ptrace.h @@ -291,8 +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); +int ptrace_action(struct thread *td, int req, bool pd_mode, pid_t pid, + int pfd, lwpid_t lwpid, void *addr, int data); extern bool allow_ptrace;
