git: 97de8330e168 - main - kern: add fget_procdesc()

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Mon, 13 Jul 2026 13:42:32 UTC
The branch main has been updated by kib:

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

commit 97de8330e1683e41883887d19ea489bda90e5c61
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-07-08 14:21:58 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
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>