git: c66b6867d4b9 - stable/15 - kern: add fget_procdesc()

Konstantin Belousov <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a8124a2.436e0.2ca628a7__42229.3734665558$1786848738$gmane$org@gitrepo.freebsd.org>
The branch stable/15 has been updated by kib:

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

commit c66b6867d4b90b12e1cd0789cb60ec0959d99a05
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2026-07-08 14:21:58 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2026-08-16 02:41:30 +0000

    kern: add fget_procdesc()
    
    (cherry picked from commit 97de8330e1683e41883887d19ea489bda90e5c61)
---
 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 73c5a6f9f224..8fcbea8f8cf8 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -1566,14 +1566,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. */
@@ -1624,7 +1619,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 c2561b490f78..27ab109d2ac5 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 dd8119296930..ad2003051fd8 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);
 }
 
@@ -725,59 +688,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 ?
@@ -789,12 +781,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>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.