git: f8c0616052e2 - main - Add pdptrace(2)

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Fri, 28 Aug 2026 12:05:08 UTC
The branch main has been updated by kib:

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

commit f8c0616052e2befaf7271fa82b212ff34a7913af
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

    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;