The branch main has been updated by kib:

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

commit 97de8330e1683e41883887d19ea489bda90e5c61
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2026-07-08 14:21:58 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2026-07-13 13:28:59 +0000

    kern: add fget_procdesc()
    
    Convert several callers to use fget_procdesc().
    Eliminate procdesc_find() and directly use fget_procdesc() in
    sys_pdkill().  Previous code structure required to fdrop() procdesc
    while the process is locked.
    
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D58117
---
 sys/kern/kern_exit.c    |  10 +--
 sys/kern/kern_sig.c     |  14 +++--
 sys/kern/sys_procdesc.c | 160 +++++++++++++++++++++++-------------------------
 sys/sys/procdesc.h      |   6 +-
 4 files changed, 93 insertions(+), 97 deletions(-)

diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index db8882d70041..7879a9b68ba0 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -1562,14 +1562,9 @@ kern_pdwait(struct thread *td, int fd, int *status,
        if (error != 0)
                return (error);
 
-       error = fget(td, fd, &cap_pdwait_rights, &fp);
+       error = fget_procdesc(td, fd, &cap_pdwait_rights, &fp, &pd, NULL);
        if (error != 0)
-               return (error);
-       if (fp->f_type != DTYPE_PROCDESC) {
-               error = EINVAL;
                goto exit_unlocked;
-       }
-       pd = fp->f_data;
 
        for (;;) {
                /* We own a reference on the procdesc file. */
@@ -1620,7 +1615,8 @@ kern_pdwait(struct thread *td, int fd, int *status,
 exit_tree_locked:
        sx_xunlock(&proctree_lock);
 exit_unlocked:
-       fdrop(fp, td);
+       if (fp != NULL)
+               fdrop(fp, td);
        return (error);
 }
 
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 30f6b69da9ef..23e71aef80db 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1956,6 +1956,7 @@ int
 sys_pdkill(struct thread *td, struct pdkill_args *uap)
 {
        struct proc *p;
+       struct file *fp;
        int error;
 
        AUDIT_ARG_SIGNUM(uap->signum);
@@ -1963,14 +1964,19 @@ sys_pdkill(struct thread *td, struct pdkill_args *uap)
        if ((u_int)uap->signum > _SIG_MAXSIG)
                return (EINVAL);
 
-       error = procdesc_find(td, uap->fd, &cap_pdkill_rights, &p);
-       if (error)
-               return (error);
+       sx_slock(&proctree_lock);
+       error = fget_procdesc(td, uap->fd, &cap_pdkill_rights, &fp, NULL, &p);
+       sx_sunlock(&proctree_lock);
+       if (error != 0)
+               goto out;
        AUDIT_ARG_PROCESS(p);
        error = p_cansignal(td, p, uap->signum);
-       if (error == 0 && uap->signum)
+       if (error == 0 && uap->signum != 0)
                kern_psignal(p, uap->signum);
        PROC_UNLOCK(p);
+out:
+       if (fp != NULL)
+               fdrop(fp, td);
        return (error);
 }
 
diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c
index 710d4d5aea5a..fddeb115fd2b 100644
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -116,38 +116,6 @@ static const struct fileops procdesc_ops = {
        .fo_flags = DFLAG_PASSABLE,
 };
 
-/*
- * Return a locked process given a process descriptor, or ESRCH if it has
- * died.
- */
-int
-procdesc_find(struct thread *td, int fd, const cap_rights_t *rightsp,
-    struct proc **p)
-{
-       struct procdesc *pd;
-       struct file *fp;
-       int error;
-
-       error = fget(td, fd, rightsp, &fp);
-       if (error)
-               return (error);
-       if (fp->f_type != DTYPE_PROCDESC) {
-               error = EINVAL;
-               goto out;
-       }
-       pd = fp->f_data;
-       sx_slock(&proctree_lock);
-       if (pd->pd_proc != NULL) {
-               *p = pd->pd_proc;
-               PROC_LOCK(*p);
-       } else
-               error = ESRCH;
-       sx_sunlock(&proctree_lock);
-out:
-       fdrop(fp, td);
-       return (error);
-}
-
 /*
  * Function to be used by procstat(1) sysctls when returning procdesc
  * information.
@@ -174,16 +142,11 @@ kern_pdgetpid(struct thread *td, int fd, const 
cap_rights_t *rightsp,
        struct file *fp;
        int error;
 
-       error = fget(td, fd, rightsp, &fp);
-       if (error)
-               return (error);
-       if (fp->f_type != DTYPE_PROCDESC) {
-               error = EBADF;
-               goto out;
-       }
-       *pidp = procdesc_pid(fp);
-out:
-       fdrop(fp, td);
+       error = fget_procdesc(td, fd, rightsp, &fp, NULL, NULL);
+       if (error == 0)
+               *pidp = procdesc_pid(fp);
+       if (fp != NULL)
+               fdrop(fp, td);
        return (error);
 }
 
@@ -722,59 +685,88 @@ sys_pdopenpid(struct thread *td, struct pdopenpid_args 
*args)
        return (kern_pdopenpid(td, args->pid, args->flags));
 }
 
+/*
+ * Get the file/process descriptor/process from the procdesc file
+ * descriptor.  The process descriptor and process returns are
+ * optional.  If requested to return the process, the proctree lock
+ * must be held, and the process will be returned locked.
+ *
+ * The caller must fdrop(*pfp) if *pfp != NULL, regardless of the
+ * error returned, after the proctree_lock is unlocked.
+ * procdesc_close() takes the proctree_lock.
+ */
+int
+fget_procdesc(struct thread *td, int pdfd, const cap_rights_t *cap_rights,
+    struct file **pfp, struct procdesc **pdp, struct proc **pp)
+{
+       struct file *fp;
+       struct procdesc *pd;
+       struct proc *p;
+       int error;
+
+       if (pp != NULL)
+               sx_assert(&proctree_lock, SX_LOCKED);
+
+       *pfp = NULL;
+       error = fget(td, pdfd, cap_rights, &fp);
+       if (error != 0)
+               return (error);
+       *pfp = fp;
+       if (fp->f_type != DTYPE_PROCDESC)
+               return (EBADF);
+       pd = fp->f_data;
+       if (pp != NULL) {
+               p = pd->pd_proc;
+               if (p == NULL) {
+                       return (ESRCH);
+               } else {
+                       *pp = p;
+                       PROC_LOCK(p);
+               }
+       }
+       if (pdp != NULL)
+               *pdp = pd;
+       return (0);
+}
+
 static int
 kern_pddupfd(struct thread *td, int pdfd, int fd, int flags)
 {
        struct proc *p;
        struct file *fp, *pfp;
-       struct procdesc *pd;
        struct filecaps fcaps;
        uint8_t fd_flags;
        int error, fdr;
 
-       error = fget(td, pdfd, &cap_pddupfd_rights, &pfp);
-       if (error != 0)
-               return (error);
-       if (pfp->f_type != DTYPE_PROCDESC) {
-               error = EBADF;
-               goto out;
-       }
-       pd = pfp->f_data;
-again:
        sx_slock(&proctree_lock);
-       p = pd->pd_proc;
-       if (p != NULL) {
-               AUDIT_ARG_PROCESS(p);
-               PROC_LOCK(p);
-               sx_sunlock(&proctree_lock);
+       error = fget_procdesc(td, pdfd, &cap_pddupfd_rights, &pfp, NULL, &p);
+       if (error == 0) {
                if ((p->p_flag & P_WEXIT) != 0) {
                        error = ESRCH;
+                       PROC_UNLOCK(p);
                } else {
-                       /*
-                        * Block the target process from entering
-                        * execve().  We need to ensure that the
-                        * p_candebug() predicate is stable until the
-                        * fget_remote() call ends even after the
-                        * process lock is dropped.  For that, the
-                        * process must not change uid/suid.
-                        */
-                       if (!execve_block(td, p))
-                               goto again;
-                       error = p_candebug(td, p);
-                       if (error == 0)
-                               _PHOLD(p);
-                       else
-                               execve_unblock(td, p);
+                       _PHOLD(p);
                }
-               PROC_UNLOCK(p);
-               if (error != 0)
-                       goto out;
+       }
+       sx_sunlock(&proctree_lock);
+       if (error != 0)
+               goto out;
+       AUDIT_ARG_PROCESS(p);
+       PROC_LOCK_ASSERT(p, MA_OWNED);
 
-               error = fget_remote(td, p, fd, &fcaps, &fd_flags, &fp);
-               PROC_LOCK(p);
-               execve_unblock(td, p);
-               _PRELE(p);
+       /*
+        * Block the target process from entering execve().
+        * We need to ensure that the p_candebug() predicate
+        * is stable until the fget_remote() call ends even
+        * after the process lock is dropped.  For that, the
+        * process must not change uid/suid.
+        */
+       execve_block_wait(td, p);
+       error = p_candebug(td, p);
+
+       if (error == 0) {
                PROC_UNLOCK(p);
+               error = fget_remote(td, p, fd, &fcaps, &fd_flags, &fp);
                if (error == 0) {
                        error = finstall_refed(td, fp, &fdr, O_CLOEXEC |
                            ((fd_flags & FD_RESOLVE_BENEATH) != 0 ?
@@ -786,12 +778,14 @@ again:
                                td->td_retval[0] = fdr;
                        }
                }
-       } else {
-               sx_sunlock(&proctree_lock);
-               error = ESRCH;
+               PROC_LOCK(p);
        }
+       execve_unblock(td, p);
+       _PRELE(p);
+       PROC_UNLOCK(p);
 out:
-       fdrop(pfp, td);
+       if (pfp != NULL)
+               fdrop(pfp, td);
        return (error);
 }
 
diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h
index dafa3326384d..715232d5a00e 100644
--- a/sys/sys/procdesc.h
+++ b/sys/sys/procdesc.h
@@ -102,8 +102,6 @@ struct procdesc {
  * In-kernel interfaces to process descriptors.
  */
 int     procdesc_exit(struct proc *);
-int     procdesc_find(struct thread *, int fd, const cap_rights_t *,
-           struct proc **);
 void    procdesc_jobstate(struct proc *p);
 int     kern_pdgetpid(struct thread *, int fd, const cap_rights_t *,
            pid_t *pidp);
@@ -114,7 +112,9 @@ void         procdesc_reap(struct proc *);
 
 int     procdesc_falloc(struct thread *, struct file **, int *, int,
            struct filecaps *);
-
+int     fget_procdesc(struct thread *td, int pfd,
+           const cap_rights_t *cap_rights, struct file **pfp,
+           struct procdesc **pdp, struct proc **pp);
 #else /* !_KERNEL */
 
 #include <sys/cdefs.h>

Reply via email to