The branch main has been updated by kib:

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

commit e8c313204887e7ba47b5c349acbe37d64a3162a1
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2026-07-07 23:46:56 +0000
Commit:     Konstantin Belousov <[email protected]>
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_ */

Reply via email to