The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=02ffca404e65b2058720e1e9d5a5bc8bb2867113
commit 02ffca404e65b2058720e1e9d5a5bc8bb2867113 Author: Ricardo Branco <rbra...@suse.de> AuthorDate: 2025-06-20 12:06:48 +0000 Commit: Mark Johnston <ma...@freebsd.org> CommitDate: 2025-07-06 23:08:19 +0000 kern: Add support for POSIX O_CLOFORK flag Reviewed by: kib MFC after: 1 month Pull Request: https://github.com/freebsd/freebsd-src/pull/1698 --- sys/kern/kern_descrip.c | 28 ++++++++++++++++++++++------ sys/kern/sys_pipe.c | 2 +- sys/sys/fcntl.h | 13 +++++++++++++ sys/sys/filedesc.h | 2 ++ 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index ac4b6ac3f457..bd6fa0c14075 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -511,6 +511,11 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) error = kern_dup(td, FDDUP_FCNTL, FDDUP_FLAG_CLOEXEC, fd, tmp); break; + case F_DUPFD_CLOFORK: + tmp = arg; + error = kern_dup(td, FDDUP_FCNTL, FDDUP_FLAG_CLOFORK, fd, tmp); + break; + case F_DUP2FD: tmp = arg; error = kern_dup(td, FDDUP_FIXED, 0, fd, tmp); @@ -528,6 +533,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) if (fde != NULL) { td->td_retval[0] = ((fde->fde_flags & UF_EXCLOSE) ? FD_CLOEXEC : 0) | + ((fde->fde_flags & UF_FOCLOSE) ? FD_CLOFORK : 0) | ((fde->fde_flags & UF_RESOLVE_BENEATH) ? FD_RESOLVE_BENEATH : 0); error = 0; @@ -545,6 +551,7 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) */ fde->fde_flags = (fde->fde_flags & ~UF_EXCLOSE) | ((arg & FD_CLOEXEC) != 0 ? UF_EXCLOSE : 0) | + ((arg & FD_CLOFORK) != 0 ? UF_FOCLOSE : 0) | ((arg & FD_RESOLVE_BENEATH) != 0 ? UF_RESOLVE_BENEATH : 0); error = 0; @@ -946,7 +953,7 @@ kern_dup(struct thread *td, u_int mode, int flags, int old, int new) fdp = p->p_fd; oioctls = NULL; - MPASS((flags & ~(FDDUP_FLAG_CLOEXEC)) == 0); + MPASS((flags & ~(FDDUP_FLAG_CLOEXEC | FDDUP_FLAG_CLOFORK)) == 0); MPASS(mode < FDDUP_LASTMODE); AUDIT_ARG_FD(old); @@ -971,8 +978,10 @@ kern_dup(struct thread *td, u_int mode, int flags, int old, int new) goto unlock; if (mode == FDDUP_FIXED && old == new) { td->td_retval[0] = new; - if (flags & FDDUP_FLAG_CLOEXEC) + if ((flags & FDDUP_FLAG_CLOEXEC) != 0) fdp->fd_ofiles[new].fde_flags |= UF_EXCLOSE; + if ((flags & FDDUP_FLAG_CLOFORK) != 0) + fdp->fd_ofiles[new].fde_flags |= UF_FOCLOSE; error = 0; goto unlock; } @@ -1047,10 +1056,9 @@ kern_dup(struct thread *td, u_int mode, int flags, int old, int new) fde_copy(oldfde, newfde); filecaps_copy_finish(&oldfde->fde_caps, &newfde->fde_caps, nioctls); - if ((flags & FDDUP_FLAG_CLOEXEC) != 0) - newfde->fde_flags = oldfde->fde_flags | UF_EXCLOSE; - else - newfde->fde_flags = oldfde->fde_flags & ~UF_EXCLOSE; + newfde->fde_flags = (oldfde->fde_flags & ~(UF_EXCLOSE | UF_FOCLOSE)) | + ((flags & FDDUP_FLAG_CLOEXEC) != 0 ? UF_EXCLOSE : 0) | + ((flags & FDDUP_FLAG_CLOFORK) != 0 ? UF_FOCLOSE : 0); #ifdef CAPABILITIES seqc_write_end(&newfde->fde_seqc); #endif @@ -2172,6 +2180,7 @@ _finstall(struct filedesc *fdp, struct file *fp, int fd, int flags, #endif fde->fde_file = fp; fde->fde_flags = ((flags & O_CLOEXEC) != 0 ? UF_EXCLOSE : 0) | + ((flags & O_CLOFORK) != 0 ? UF_FOCLOSE : 0) | ((flags & O_RESOLVE_BENEATH) != 0 ? UF_RESOLVE_BENEATH : 0); if (fcaps != NULL) filecaps_move(fcaps, &fde->fde_caps); @@ -2432,6 +2441,7 @@ fdcopy(struct filedesc *fdp) newfdp->fd_freefile = fdp->fd_freefile; FILEDESC_FOREACH_FDE(fdp, i, ofde) { if ((ofde->fde_file->f_ops->fo_flags & DFLAG_PASSABLE) == 0 || + (ofde->fde_flags & UF_FOCLOSE) != 0 || !fhold(ofde->fde_file)) { if (newfdp->fd_freefile == fdp->fd_freefile) newfdp->fd_freefile = i; @@ -2729,6 +2739,12 @@ fdcloseexec(struct thread *td) fdfree(fdp, i); (void) closefp(fdp, i, fp, td, false, false); FILEDESC_UNLOCK_ASSERT(fdp); + } else if (fde->fde_flags & UF_FOCLOSE) { + /* + * https://austingroupbugs.net/view.php?id=1851 + * FD_CLOFORK should not be preserved across exec + */ + fde->fde_flags &= ~UF_FOCLOSE; } } } diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c index 9340779918a2..ed651da96b14 100644 --- a/sys/kern/sys_pipe.c +++ b/sys/kern/sys_pipe.c @@ -548,7 +548,7 @@ sys_pipe2(struct thread *td, struct pipe2_args *uap) { int error, fildes[2]; - if (uap->flags & ~(O_CLOEXEC | O_NONBLOCK)) + if ((uap->flags & ~(O_CLOEXEC | O_CLOFORK | O_NONBLOCK)) != 0) return (EINVAL); error = kern_pipe(td, fildes, uap->flags, NULL, NULL); if (error) diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h index dd9fccf5cf38..7234c9240c84 100644 --- a/sys/sys/fcntl.h +++ b/sys/sys/fcntl.h @@ -144,6 +144,10 @@ typedef __pid_t pid_t; #define O_XATTR O_NAMEDATTR /* Solaris compatibility */ #endif +#if __POSIX_VISIBLE >= 202405 +#define O_CLOFORK 0x08000000 +#endif + /* * !!! DANGER !!! * @@ -280,7 +284,13 @@ typedef __pid_t pid_t; #define F_GET_SEALS 20 #define F_ISUNIONSTACK 21 /* Kludge for libc, don't use it. */ #define F_KINFO 22 /* Return kinfo_file for this fd */ +#endif /* __BSD_VISIBLE */ +#if __POSIX_VISIBLE >= 202405 +#define F_DUPFD_CLOFORK 23 /* Like F_DUPFD, but FD_CLOFORK is set */ +#endif + +#if __BSD_VISIBLE /* Seals (F_ADD_SEALS, F_GET_SEALS). */ #define F_SEAL_SEAL 0x0001 /* Prevent adding sealings */ #define F_SEAL_SHRINK 0x0002 /* May not shrink */ @@ -292,6 +302,9 @@ typedef __pid_t pid_t; #define FD_CLOEXEC 1 /* close-on-exec flag */ #define FD_RESOLVE_BENEATH 2 /* all lookups relative to fd have O_RESOLVE_BENEATH semantics */ +#if __POSIX_VISIBLE >= 202405 +#define FD_CLOFORK 4 /* close-on-fork flag */ +#endif /* record locking flags (F_GETLK, F_SETLK, F_SETLKW) */ #define F_RDLCK 1 /* shared or read lock */ diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h index 55969b2ff4b3..0a388c90de26 100644 --- a/sys/sys/filedesc.h +++ b/sys/sys/filedesc.h @@ -149,6 +149,7 @@ struct filedesc_to_leader { */ #define UF_EXCLOSE 0x01 /* auto-close on exec */ #define UF_RESOLVE_BENEATH 0x02 /* lookups must be beneath this dir */ +#define UF_FOCLOSE 0x04 /* auto-close on fork */ #ifdef _KERNEL @@ -221,6 +222,7 @@ enum { /* Flags for kern_dup(). */ #define FDDUP_FLAG_CLOEXEC 0x1 /* Atomically set UF_EXCLOSE. */ +#define FDDUP_FLAG_CLOFORK 0x2 /* Atomically set UF_FOCLOSE. */ /* For backward compatibility. */ #define falloc(td, resultfp, resultfd, flags) \