git: 43c9d80a4443 - stable/15 - kern: add pdopenpid(2)

Konstantin Belousov <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a81248c.447b3.6057fec7__6361.50971274532$1786848537$gmane$org@gitrepo.freebsd.org>
The branch stable/15 has been updated by kib:

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

commit 43c9d80a4443c2497d663d0b050375253e39e966
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2026-05-20 02:04:02 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2026-08-16 02:41:21 +0000

    kern: add pdopenpid(2)
    
    (cherry picked from commit 5c32aa785184bb1e646b0b4c73d3c5fd9a6b8951)
---
 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 c4df1f30989b..ec9d3ee9aa37 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 {
@@ -612,3 +616,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 4c7de9d59ded..bc81f22d3cb4 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -3422,4 +3422,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.
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.