git: 97de8330e168 - main - kern: add fget_procdesc()
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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>