git: 1ad21a652182 - main - kern: add pddupfd(2)

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Tue, 07 Jul 2026 23:28:23 UTC
The branch main has been updated by kib:

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

commit 1ad21a6521827473dc6692646e9c760a5b0521cd
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-05-21 19:12:45 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-07-07 22:03:53 +0000

    kern: add pddupfd(2)
    
    Reviewed by:    markj
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D57163
---
 sys/kern/kern_descrip.c  |  8 +++--
 sys/kern/sys_procdesc.c  | 82 ++++++++++++++++++++++++++++++++++++++++++++++++
 sys/kern/syscalls.master |  7 +++++
 3 files changed, 95 insertions(+), 2 deletions(-)

diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 351cc1917b04..8272d6da9b0a 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -3162,6 +3162,7 @@ fget_remote(struct thread *td, struct proc *p, int fd, struct filecaps *fcaps,
 	struct filedesc *fdp;
 	struct file *fp;
 	int error;
+	bool copied __diagused;
 
 	/*
 	 * Both fcaps and fd_flags must be either requested together,
@@ -3186,8 +3187,11 @@ fget_remote(struct thread *td, struct proc *p, int fd, struct filecaps *fcaps,
 				*fd_flags = fde_to_fd_flags(fdp->fd_ofiles[fd].
 				    fde_flags);
 			}
-			if (fcaps != NULL)
-				*fcaps = fdp->fd_ofiles[fd].fde_caps;
+			if (fcaps != NULL) {
+				copied = filecaps_copy(
+				    &fdp->fd_ofiles[fd].fde_caps, fcaps, true);
+				MPASS(copied);
+			}
 			error = 0;
 		} else {
 			error = EBADF;
diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c
index 4749a9b8bf7e..7351df11c631 100644
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -67,6 +67,7 @@
 #include <sys/fcntl.h>
 #include <sys/file.h>
 #include <sys/filedesc.h>
+#include <sys/imgact.h>
 #include <sys/kernel.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
@@ -702,3 +703,84 @@ sys_pdopenpid(struct thread *td, struct pdopenpid_args *args)
 		return (EINVAL);
 	return (kern_pdopenpid(td, args->pid, args->flags));
 }
+
+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);
+		if ((p->p_flag & P_WEXIT) != 0) {
+			error = ESRCH;
+		} 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);
+		}
+		PROC_UNLOCK(p);
+		if (error != 0)
+			goto out;
+
+		error = fget_remote(td, p, fd, &fcaps, &fd_flags, &fp);
+		PROC_LOCK(p);
+		execve_unblock(td, p);
+		_PRELE(p);
+		PROC_UNLOCK(p);
+		if (error == 0) {
+			error = finstall_refed(td, fp, &fdr, O_CLOEXEC |
+			    ((fd_flags & FD_RESOLVE_BENEATH) != 0 ?
+			    O_RESOLVE_BENEATH : 0), &fcaps);
+			if (error != 0) {
+				fdrop(fp, td);
+				filecaps_free(&fcaps);
+			} else {
+				td->td_retval[0] = fdr;
+			}
+		}
+	} else {
+		sx_sunlock(&proctree_lock);
+		error = ESRCH;
+	}
+out:
+	fdrop(pfp, td);
+	return (error);
+}
+
+int
+sys_pddupfd(struct thread *td, struct pddupfd_args *args)
+{
+	if (args->flags != 0)
+		return (EINVAL);
+	return (kern_pddupfd(td, args->pd, args->fd, args->flags));
+}
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 8ea32a7b0058..4bc5385f76e7 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -3435,5 +3435,12 @@
 		    int flags
 		);
 	}
+604	AUE_NULL	STD {
+		int pddupfd(
+			int pd,
+			int fd,
+			int flags
+		);
+	}
 
 ; vim: syntax=off