git: e8c313204887 - main - pdfork(2): add PD_PTRACE_CAP flag

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

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

commit e8c313204887e7ba47b5c349acbe37d64a3162a1
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-07-07 23:46:56 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-08-28 11:52:31 +0000

    pdfork(2): add PD_PTRACE_CAP flag
    
    If the flag is not specified, the process descriptor returned by either
    pdfork(2) or pdopenpid(2) has the CAP_PTRACE capability disabled.
    
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D58586
---
 sys/kern/kern_fork.c    | 14 ++++++++++++++
 sys/kern/sys_procdesc.c |  7 ++++++-
 sys/sys/procdesc.h      |  6 ++++--
 3 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 7d2535de987f..182d5ec68b20 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -41,6 +41,7 @@
 #include <sys/systm.h>
 #include <sys/acct.h>
 #include <sys/bitstring.h>
+#include <sys/capsicum.h>
 #include <sys/eventhandler.h>
 #include <sys/exterrvar.h>
 #include <sys/fcntl.h>
@@ -119,6 +120,7 @@ int
 sys_pdfork(struct thread *td, struct pdfork_args *uap)
 {
 	struct fork_req fr;
+	struct filecaps fcaps;
 	int error, fd, pid;
 
 	bzero(&fr, sizeof(fr));
@@ -126,6 +128,10 @@ sys_pdfork(struct thread *td, struct pdfork_args *uap)
 	fr.fr_pidp = &pid;
 	fr.fr_pd_fd = &fd;
 	fr.fr_pd_flags = uap->flags;
+	filecaps_fill(&fcaps);
+	if ((uap->flags & PD_PTRACE_CAP) == 0)
+		cap_rights_clear(&fcaps.fc_rights, CAP_PTRACE);
+	fr.fr_pd_fcaps = &fcaps;
 	AUDIT_ARG_FFLAGS(uap->flags);
 	/*
 	 * It is necessary to return fd by reference because 0 is a valid file
@@ -194,6 +200,7 @@ int
 sys_pdrfork(struct thread *td, struct pdrfork_args *uap)
 {
 	struct fork_req fr;
+	struct filecaps fcaps;
 	int error, fd, pid;
 
 	bzero(&fr, sizeof(fr));
@@ -226,6 +233,10 @@ sys_pdrfork(struct thread *td, struct pdrfork_args *uap)
 	fr.fr_pidp = &pid;
 	fr.fr_pd_fd = &fd;
 	fr.fr_pd_flags = uap->pdflags;
+	filecaps_fill(&fcaps);
+	if ((uap->pdflags & PD_PTRACE_CAP) == 0)
+		cap_rights_clear(&fcaps.fc_rights, CAP_PTRACE);
+	fr.fr_pd_fcaps = &fcaps;
 	error = fork1(td, &fr);
 	if (error == 0) {
 		td->td_retval[0] = pid;
@@ -1068,6 +1079,7 @@ fork1(struct thread *td, struct fork_req *fr)
 		    fr->fr_pd_flags, fr->fr_pd_fcaps);
 		if (error != 0)
 			goto fail2;
+		fr->fr_pd_fcaps = NULL;
 		AUDIT_ARG_FD(*fr->fr_pd_fd);
 	}
 
@@ -1163,6 +1175,8 @@ fail2:
 		fdclose(td, fp_procdesc, *fr->fr_pd_fd);
 		fdrop(fp_procdesc, td);
 	}
+	if (fr->fr_pd_fcaps != NULL)
+		filecaps_free(fr->fr_pd_fcaps);
 	atomic_add_int(&nprocs, -1);
 cleanup:
 	if (killsx_locked)
diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c
index 0d0ca7b6871c..5ee8a4734248 100644
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -692,6 +692,7 @@ kern_pdopenpid(struct thread *td, pid_t pid, int flags)
 {
 	struct file *fp;
 	struct procdesc *pdf;
+	struct filecaps fcaps;
 	int error, fd, fflags;
 
 	error = falloc_noinstall(td, &fp);
@@ -701,13 +702,16 @@ kern_pdopenpid(struct thread *td, pid_t pid, int flags)
 	pdf = procdesc_alloc(flags);
 	if ((flags & PD_DAEMON) != 0)
 		fp->f_pdflags |= F_PD_NOKILL;
+	filecaps_fill(&fcaps);
+	if ((flags & PD_PTRACE_CAP) == 0)
+		cap_rights_clear(&fcaps.fc_rights, CAP_PTRACE);
 
 	sx_xlock(&proctree_lock);
 	error = pdopenpid1(td, pid, &pdf, fp);
 	sx_xunlock(&proctree_lock);
 
 	if (error == 0) {
-		error = finstall(td, fp, &fd, fflags, NULL);
+		error = finstall(td, fp, &fd, fflags, &fcaps);
 		if (error == 0) {
 			td->td_retval[0] = fd;
 		} else {
@@ -716,6 +720,7 @@ kern_pdopenpid(struct thread *td, pid_t pid, int flags)
 			 * return file descriptor to userspace.
 			 */
 			fp->f_pdflags |= F_PD_NOKILL | F_PD_NOFINSTALL;
+			filecaps_free(&fcaps);
 		}
 	}
 	fdrop(fp, td);
diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h
index 6cb837af2d3b..f4cba787db01 100644
--- a/sys/sys/procdesc.h
+++ b/sys/sys/procdesc.h
@@ -161,8 +161,10 @@ __END_DECLS
 #define	PD_DAEMON	0x00000001	/* Don't exit when procdesc closes. */
 #define	PD_CLOEXEC	0x00000002	/* Close file descriptor on exec. */
 #define	PD_NOWAITPID	0x00000004	/* Reap without waitpid(). */
+#define	PD_PTRACE_CAP	0x00000008	/* Allow PT_PROCDESC in cap mode. */
 
-#define	PD_ALLOWED_AT_FORK	(PD_DAEMON | PD_CLOEXEC | PD_NOWAITPID)
-#define	PD_ALLOWED_AT_OPENPID	(PD_DAEMON | PD_CLOEXEC)
+#define	PD_ALLOWED_AT_FORK	\
+    (PD_DAEMON | PD_CLOEXEC | PD_NOWAITPID | PD_PTRACE_CAP)
+#define	PD_ALLOWED_AT_OPENPID	(PD_DAEMON | PD_CLOEXEC | PD_PTRACE_CAP)
 
 #endif /* !_SYS_PROCDESC_H_ */