The branch main has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=5c32aa785184bb1e646b0b4c73d3c5fd9a6b8951
commit 5c32aa785184bb1e646b0b4c73d3c5fd9a6b8951 Author: Konstantin Belousov <[email protected]> AuthorDate: 2026-05-20 02:04:02 +0000 Commit: Konstantin Belousov <[email protected]> CommitDate: 2026-07-07 01:24:51 +0000 kern: add pdopenpid(2) Reviewed by: markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D57124 --- sys/kern/sys_procdesc.c | 114 ++++++++++++++++++++++++++++++++++++++++++----- sys/kern/syscalls.master | 7 +++ sys/sys/procdesc.h | 2 + 3 files changed, 111 insertions(+), 12 deletions(-) diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c index 0d57a8cc7b2c..3fca3ea29b18 100644 --- a/sys/kern/sys_procdesc.c +++ b/sys/kern/sys_procdesc.c @@ -435,18 +435,22 @@ procdesc_close(struct file *fp, struct thread *td) pd->pd_pid = -1; procdesc_free(pd); - /* - * Next, reparent it to its reaper (usually init(8)) so - * that there's someone to pick up the pieces; finally, - * terminate with prejudice. - */ - p->p_sigparent = SIGCHLD; - if ((p->p_flag & P_TRACED) == 0) { - proc_reparent(p, p->p_reaper, true); - } else { - proc_clear_orphan(p); - p->p_oppid = p->p_reaper->p_pid; - proc_add_orphan(p, p->p_reaper); + /* Failed finstall() should not cause reaping. */ + if ((fp->f_pdflags & F_PD_NOFINSTALL) == 0) { + /* + * Next, reparent it to its reaper + * (usually init(8)) so that there's + * someone to pick up the pieces; + * finally, terminate with prejudice. + */ + p->p_sigparent = SIGCHLD; + if ((p->p_flag & P_TRACED) == 0) { + proc_reparent(p, p->p_reaper, true); + } else { + proc_clear_orphan(p); + p->p_oppid = p->p_reaper->p_pid; + proc_add_orphan(p, p->p_reaper); + } } procdesc_close_tail(fp, p); } else { @@ -609,3 +613,89 @@ procdesc_cmp(struct file *fp1, struct file *fp2, struct thread *td) pdp2 = fp2->f_data; return (kcmp_cmp((uintptr_t)pdp1->pd_pid, (uintptr_t)pdp2->pd_pid)); } + +static int +pdopenpid1(struct thread *td, pid_t pid, struct procdesc **pdf, struct file *fp) +{ + struct proc *p; + struct procdesc *pd; + int error; + + sx_assert(&proctree_lock, SX_XLOCKED); + + error = pget(pid, PGET_NOTID | PGET_CANDEBUG, &p); + if (error != 0) + return (error); + if ((p->p_flag & (P_SYSTEM | P_WEXIT)) != 0) { + PROC_UNLOCK(p); + return (EBUSY); + } + pd = p->p_procdesc; + if (pd != NULL) { + refcount_acquire(&pd->pd_refcount); + PROCDESC_LOCK(pd); + MPASS(pd->pd_fpcount > 0); + pd->pd_fpcount++; + PROCDESC_UNLOCK(pd); + } else { + pd = *pdf; + *pdf = NULL; + pd->pd_proc = p; + pd->pd_pid = p->p_pid; + p->p_procdesc = pd; + } + procdesc_finit(pd, fp); + PROC_UNLOCK(p); + return (0); +} + +static int +kern_pdopenpid(struct thread *td, pid_t pid, int flags) +{ + struct file *fp; + struct procdesc *pdf; + int error, fd, fflags; + + error = falloc_noinstall(td, &fp); + if (error != 0) + return (error); + fflags = pdtofdflags(flags); + pdf = procdesc_alloc(flags); + if ((flags & PD_DAEMON) != 0) + fp->f_pdflags |= F_PD_NOKILL; + + sx_xlock(&proctree_lock); + error = pdopenpid1(td, pid, &pdf, fp); + sx_xunlock(&proctree_lock); + + if (error == 0) { + error = finstall(td, fp, &fd, fflags, NULL); + if (error == 0) { + td->td_retval[0] = fd; + } else { + /* + * Not killing the target process if cannot + * return file descriptor to userspace. + */ + fp->f_pdflags |= F_PD_NOKILL | F_PD_NOFINSTALL; + } + } + fdrop(fp, td); + + if (pdf != NULL) { + MPASS(pdf->pd_refcount == 2); + MPASS(pdf->pd_fpcount == 1); + MPASS(pdf->pd_proc == NULL); + MPASS(pdf->pd_pid == -1); + procdesc_destroy(pdf); + } + return (error); +} + +int +sys_pdopenpid(struct thread *td, struct pdopenpid_args *args) +{ + if ((args->flags & ~(PD_ALLOWED_AT_FORK)) != 0) + return (EINVAL); + return (kern_pdopenpid(td, args->pid, args->flags)); +} diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 1032f6cd1bf0..41580d0c4595 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -3429,4 +3429,11 @@ int flags ); } +603 AUE_NULL STD { + int pdopenpid( + pid_t pid, + int flags + ); + } + ; vim: syntax=off diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h index 5fbd43f1ac84..9eb64525e430 100644 --- a/sys/sys/procdesc.h +++ b/sys/sys/procdesc.h @@ -95,6 +95,8 @@ struct procdesc { */ #define F_PD_NOKILL 0x00000001 /* Opened with PD_DAEMON. Don't send SIGKILL when file closes. */ +#define F_PD_NOFINSTALL 0x00000002 /* Procdesc file is closing because + finstall() failed */ /* * In-kernel interfaces to process descriptors.
