From 56f82a540724523352f2f940069e26a514cec125 Mon Sep 17 00:00:00 2001 From: Chris Hanson Date: Sat, 18 Apr 2026 16:30:18 -0700 Subject: [PATCH] Add posix_spawn_file_actions_addclosefrom_np Add support for a closefrom(3) action to posix_spawn_file_actions_t. This can be used to ensure all but specific low-numbered descriptors are closed in the child process. Rationale: In a large or complex application or one using many libraries, the caller of posix_spawn(3) can't necessarily have complete knowledge of the state of all descriptors that could potentially be inherited by the child process. --- distrib/sets/lists/base/shl.mi | 4 +- distrib/sets/lists/debug/shl.mi | 4 +- doc/CHANGES | 2 + include/spawn.h | 4 ++ lib/libc/gen/posix_spawn.3 | 1 + .../gen/posix_spawn_file_actions_addopen.3 | 39 +++++++++++++++++-- lib/libc/gen/posix_spawn_file_actions_init.3 | 1 + lib/libc/gen/posix_spawn_fileactions.c | 26 +++++++++++++ lib/libc/include/namespace.h | 4 ++ lib/libc/shlib_version | 2 +- sys/kern/kern_exec.c | 10 ++++- sys/sys/spawn.h | 10 ++++- .../lib/libc/gen/posix_spawn/h_fileactions.c | 11 ++++++ .../lib/libc/gen/posix_spawn/t_fileactions.c | 25 +++++++++++- 14 files changed, 131 insertions(+), 12 deletions(-) diff --git distrib/sets/lists/base/shl.mi distrib/sets/lists/base/shl.mi index dc61b3a5efa9..1655e5c40147 100644 --- distrib/sets/lists/base/shl.mi +++ distrib/sets/lists/base/shl.mi @@ -22,7 +22,7 @@ ./lib/libblocklist.so.0.1 base-sys-shlib dynamicroot ./lib/libc.so base-sys-shlib dynamicroot ./lib/libc.so.12 base-sys-shlib dynamicroot -./lib/libc.so.12.224 base-sys-shlib dynamicroot +./lib/libc.so.12.225 base-sys-shlib dynamicroot ./lib/libcrypt.so base-sys-shlib dynamicroot ./lib/libcrypt.so.1 base-sys-shlib dynamicroot ./lib/libcrypt.so.1.0 base-sys-shlib dynamicroot @@ -267,7 +267,7 @@ ./usr/lib/libc++.so.1.0 base-sys-shlib compatfile,libcxx ./usr/lib/libc.so base-sys-shlib compatfile ./usr/lib/libc.so.12 base-sys-shlib compatfile -./usr/lib/libc.so.12.224 base-sys-shlib compatfile +./usr/lib/libc.so.12.225 base-sys-shlib compatfile ./usr/lib/libcbor.so base-sys-shlib compatfile ./usr/lib/libcbor.so.0 base-sys-shlib compatfile ./usr/lib/libcbor.so.0.5 base-sys-shlib compatfile diff --git distrib/sets/lists/debug/shl.mi distrib/sets/lists/debug/shl.mi index f29c98ef9319..b27607ae7876 100644 --- distrib/sets/lists/debug/shl.mi +++ distrib/sets/lists/debug/shl.mi @@ -3,7 +3,7 @@ ./usr/libdata/debug/lib base-sys-usr debug,dynamicroot,compatdir ./usr/libdata/debug/lib/libavl.so.0.0.debug comp-zfs-debug debug,dynamicroot,zfs ./usr/libdata/debug/lib/libblocklist.so.0.1.debug comp-sys-debug debug,dynamicroot -./usr/libdata/debug/lib/libc.so.12.224.debug comp-sys-debug debug,dynamicroot +./usr/libdata/debug/lib/libc.so.12.225.debug comp-sys-debug debug,dynamicroot ./usr/libdata/debug/lib/libcrypt.so.1.0.debug comp-sys-debug debug,dynamicroot ./usr/libdata/debug/lib/libcrypto.so.12.0.debug comp-sys-debug debug,dynamicroot,openssl=10 ./usr/libdata/debug/lib/libcrypto.so.14.1.debug comp-sys-debug debug,dynamicroot,openssl=11 @@ -89,7 +89,7 @@ ./usr/libdata/debug/usr/lib/libbsdmalloc.so.0.1.debug comp-sys-debug debug,compatfile ./usr/libdata/debug/usr/lib/libbz2.so.1.1.debug comp-sys-debug debug,compatfile ./usr/libdata/debug/usr/lib/libc++.so.1.0.debug comp-sys-debug debug,compatfile,libcxx -./usr/libdata/debug/usr/lib/libc.so.12.224.debug comp-sys-debug debug,compatfile +./usr/libdata/debug/usr/lib/libc.so.12.225.debug comp-sys-debug debug,compatfile ./usr/libdata/debug/usr/lib/libcbor.so.0.5.debug comp-sys-debug debug,compatfile ./usr/libdata/debug/usr/lib/libcom_err.so.8.0.debug comp-krb5-debug debug,compatfile,kerberos ./usr/libdata/debug/usr/lib/libcrypt.so.1.0.debug comp-sys-debug debug,compatfile diff --git doc/CHANGES doc/CHANGES index 5678c01952ad..d93db8886d5d 100644 --- doc/CHANGES +++ doc/CHANGES @@ -238,6 +238,8 @@ Changes from NetBSD 11.0 to NetBSD 12.0: tzdata: Updated to 2026b (using 2026bgtz) [kre 20260429] pthread(3): add pthread_main_np(3) [wiz 20260501] zstd(1): import 1.5.7 [christos 20260501] + posix_spawn(3): Add posix_spawn_file_actions_addclosefrom_np + function from FreeBSD. [cmh 20260418] libarchive: Import libarchive-3.8.7. [christos 20260503] acpi(4): Updated ACPICA to 20260408. [christos 20260503] byacc: Update to 20260126. [christos 20260503] diff --git include/spawn.h include/spawn.h index 32cdd85ca27f..d5963cdb1942 100644 --- include/spawn.h +++ include/spawn.h @@ -60,6 +60,10 @@ int posix_spawn_file_actions_addchdir(posix_spawn_file_actions_t * __restrict, const char * __restrict); int posix_spawn_file_actions_addfchdir(posix_spawn_file_actions_t *, int); +#if defined(_NETBSD_SOURCE) +int posix_spawn_file_actions_addclosefrom_np(posix_spawn_file_actions_t *, int); +#endif + /* * Spawn attributes */ diff --git lib/libc/gen/posix_spawn.3 lib/libc/gen/posix_spawn.3 index 6ca4a59a0810..379da1708fd6 100644 --- lib/libc/gen/posix_spawn.3 +++ lib/libc/gen/posix_spawn.3 @@ -444,6 +444,7 @@ is returned. .Xr vfork 2 , .Xr posix_spawn_file_actions_addchdir 3 , .Xr posix_spawn_file_actions_addclose 3 , +.Xr posix_spawn_file_actions_addclosefrom_np 3 , .Xr posix_spawn_file_actions_adddup2 3 , .Xr posix_spawn_file_actions_addfchdir 3 , .Xr posix_spawn_file_actions_addopen 3 , diff --git lib/libc/gen/posix_spawn_file_actions_addopen.3 lib/libc/gen/posix_spawn_file_actions_addopen.3 index 9a23d6f9e899..1f9fc26a8790 100644 --- lib/libc/gen/posix_spawn_file_actions_addopen.3 +++ lib/libc/gen/posix_spawn_file_actions_addopen.3 @@ -36,14 +36,15 @@ .\" .\" $FreeBSD: src/lib/libc/gen/posix_spawn_file_actions_addopen.3,v 1.2.2.1.4.1 2010/06/14 02:09:06 kensmith Exp $ .\" -.Dd February 2, 2014 +.Dd April 18, 2026 .Dt POSIX_SPAWN_FILE_ACTIONS_ADDOPEN 3 .Os .Sh NAME .Nm posix_spawn_file_actions_addopen , .Nm posix_spawn_file_actions_adddup2 , -.Nm posix_spawn_file_actions_addclose -.Nd "add open, dup2 or close action to spawn file actions object" +.Nm posix_spawn_file_actions_addclose , +.Nm posix_spawn_file_actions_addclosefrom_np +.Nd "add open, dup2, close, or closefrom action to spawn file actions object" .Sh LIBRARY .Lb libc .Sh SYNOPSIS @@ -54,8 +55,10 @@ .Fn posix_spawn_file_actions_adddup2 "posix_spawn_file_actions_t * file_actions" "int fildes" "int newfildes" .Ft int .Fn posix_spawn_file_actions_addclose "posix_spawn_file_actions_t * file_actions" "int fildes" +.Ft int +.Fn posix_spawn_file_actions_addclosefrom_np "posix_spawn_file_actions_t * file_actions" "int fildes" .Sh DESCRIPTION -These functions add an open, dup2 or close action to a spawn +These functions add an open, dup2, close, or closefrom action to a spawn file actions object. .Pp A spawn file actions object is of type @@ -140,6 +143,21 @@ close(fildes) .Pp had been called) when a new process is spawned using this file actions object. +.Pp +The +.Fn posix_spawn_file_actions_addclosefrom_np +function adds a closefrom action to the object +referenced by +.Fa file_actions +that causes the file descriptor +.Fa filedes +and all higher file descriptors to be closed (as if +.Bd -literal -offset indent +closefrom(filedes) +.Ed +.Pp +had been called) when a new process is spawned using this file actions +object. .Sh RETURN VALUES Upon successful completion, these functions return zero; otherwise, an error number is returned to indicate the error. @@ -164,6 +182,7 @@ Insufficient memory exists to add to the spawn file actions object. .Xr close 2 , .Xr dup2 2 , .Xr open 2 , +.Xr closefrom 3 , .Xr posix_spawn 3 , .Xr posix_spawn_file_actions_destroy 3 , .Xr posix_spawn_file_actions_init 3 , @@ -176,6 +195,10 @@ and .Fn posix_spawn_file_actions_addclose functions conform to .St -p1003.1-2001 . +.Pp +The +.Fn posix_spawn_file_actions_addclosefrom_np +function is a non-standard extension. .Sh HISTORY The .Fn posix_spawn_file_actions_addopen , @@ -186,5 +209,13 @@ functions first appeared in .Fx 8.0 and imported for .Nx 6.0 . +.Pp +The implementation of +.Fn posix_spawn_file_actions_addclosefrom_np +is inspired by FreeBSD's +.Fn posix_spawn_file_actions_addclosefrom_np +and first appeared in +.Nx 12.0 . .Sh AUTHORS .An Ed Schouten Aq Mt ed@FreeBSD.org +.An Chris Hanson Aq Mt cmhanson@eschatologist.net diff --git lib/libc/gen/posix_spawn_file_actions_init.3 lib/libc/gen/posix_spawn_file_actions_init.3 index d33a09c267b3..366a68d45d16 100644 --- lib/libc/gen/posix_spawn_file_actions_init.3 +++ lib/libc/gen/posix_spawn_file_actions_init.3 @@ -89,6 +89,7 @@ Insufficient memory exists to initialize the spawn file actions object. .Sh SEE ALSO .Xr posix_spawn 3 , .Xr posix_spawn_file_actions_addclose 3 , +.Xr posix_spawn_file_actions_addclosefrom_np 3 , .Xr posix_spawn_file_actions_adddup2 3 , .Xr posix_spawn_file_actions_addopen 3 , .Xr posix_spawnp 3 diff --git lib/libc/gen/posix_spawn_fileactions.c lib/libc/gen/posix_spawn_fileactions.c index 1ff45c97faa5..a9335013d9e8 100644 --- lib/libc/gen/posix_spawn_fileactions.c +++ lib/libc/gen/posix_spawn_fileactions.c @@ -40,6 +40,11 @@ __RCSID("$NetBSD: posix_spawn_fileactions.c,v 1.5 2021/11/07 14:34:30 christos E #define MIN_SIZE 16 +#ifdef __weak_alias +__weak_alias(posix_spawn_file_actions_addclosefrom_np, + _posix_spawn_file_actions_addclosefrom_np) +#endif + /* * File descriptor actions */ @@ -215,3 +220,24 @@ posix_spawn_file_actions_addfchdir(posix_spawn_file_actions_t *fa, int fildes) return 0; } + +int +posix_spawn_file_actions_addclosefrom_np(posix_spawn_file_actions_t *fa, + int fildes) +{ + unsigned int i; + int error; + + if (fildes < 0) + return EBADF; + + error = posix_spawn_file_actions_getentry(fa, &i); + if (error) + return error; + + fa->fae[i].fae_action = FAE_CLOSEFROM; + fa->fae[i].fae_fildes = fildes; + fa->len++; + + return 0; +} diff --git lib/libc/include/namespace.h lib/libc/include/namespace.h index 6ac8288b9123..424a7779ea22 100644 --- lib/libc/include/namespace.h +++ lib/libc/include/namespace.h @@ -935,6 +935,10 @@ #define dladdr __dladdr #define fmtcheck __fmtcheck +/* posix_spawn */ +#define posix_spawn_file_actions_addclosefrom_np \ + _posix_spawn_file_actions_addclosefrom_np + /* RB trees */ #define rb_tree_init _rb_tree_init #define rb_tree_find_node _rb_tree_find_node diff --git lib/libc/shlib_version lib/libc/shlib_version index 7bcdd8dcbcb5..ad43eb5ef62d 100644 --- lib/libc/shlib_version +++ lib/libc/shlib_version @@ -55,4 +55,4 @@ # - remove tzsetwall(3), upstream has removed it # - move *rand48* to libcompat major=12 -minor=224 +minor=225 diff --git sys/kern/kern_exec.c sys/kern/kern_exec.c index 0d1b498ab303..0621f4d66ea8 100644 --- sys/kern/kern_exec.c +++ sys/kern/kern_exec.c @@ -2154,7 +2154,7 @@ handle_posix_spawn_file_actions(struct posix_spawn_file_actions *actions) { struct lwp *l = curlwp; register_t retval; - int error = 0, newfd; + int error = 0, newfd, fd; if (actions == NULL) return 0; @@ -2201,6 +2201,14 @@ handle_posix_spawn_file_actions(struct posix_spawn_file_actions *actions) case FAE_FCHDIR: error = do_sys_fchdir(l, fae->fae_fildes, &retval); break; + case FAE_CLOSEFROM: + /* + * as above, ignore failures from close(). + */ + for (fd = fae->fae_fildes; fd <= l->l_fd->fd_lastfile; fd++) + if (fd_getfile(fd) != NULL) + fd_close(fd); + break; } if (error) return error; diff --git sys/sys/spawn.h sys/sys/spawn.h index b04db01bd03c..ecca5c9ad541 100644 --- sys/sys/spawn.h +++ sys/sys/spawn.h @@ -47,7 +47,15 @@ struct posix_spawnattr { sigset_t sa_sigmask; }; -enum fae_action { FAE_OPEN, FAE_DUP2, FAE_CLOSE, FAE_CHDIR, FAE_FCHDIR }; +enum fae_action { + FAE_OPEN, + FAE_DUP2, + FAE_CLOSE, + FAE_CHDIR, + FAE_FCHDIR, + FAE_CLOSEFROM, +}; + typedef struct posix_spawn_file_actions_entry { enum fae_action fae_action; diff --git tests/lib/libc/gen/posix_spawn/h_fileactions.c tests/lib/libc/gen/posix_spawn/h_fileactions.c index c658600bbf1c..0d9637b7d1ec 100644 --- tests/lib/libc/gen/posix_spawn/h_fileactions.c +++ tests/lib/libc/gen/posix_spawn/h_fileactions.c @@ -100,6 +100,17 @@ main(int argc, char **argv) fprintf(stderr, "%s: stat results differ\n", getprogname()); res = EXIT_FAILURE; } + /* file descs 8 and 9 should be closed (via addclosefrom_np) */ + if (read(8, buf, BUFSIZE) != -1 || errno != EBADF) { + fprintf(stderr, "%s: filedesc 8 is not closed\n", + getprogname()); + res = EXIT_FAILURE; + } + if (read(9, buf, BUFSIZE) != -1 || errno != EBADF) { + fprintf(stderr, "%s: filedesc 9 is not closed\n", + getprogname()); + res = EXIT_FAILURE; + } return res; } diff --git tests/lib/libc/gen/posix_spawn/t_fileactions.c tests/lib/libc/gen/posix_spawn/t_fileactions.c index 57e27a0ada46..c8763ebcc42d 100644 --- tests/lib/libc/gen/posix_spawn/t_fileactions.c +++ tests/lib/libc/gen/posix_spawn/t_fileactions.c @@ -274,7 +274,7 @@ ATF_TC_HEAD(t_spawn_fileactions, tc) } ATF_TC_BODY(t_spawn_fileactions, tc) { - int fd1, fd2, fd3, status; + int fd1, fd2, fd3, fd4, fd5, fd6, fd7, status; pid_t pid; char * const args[2] = { __UNCONST("h_fileactions"), NULL }; char helper[FILENAME_MAX]; @@ -297,6 +297,29 @@ ATF_TC_BODY(t_spawn_fileactions, tc) RZ(posix_spawn_file_actions_addopen(&fa, 6, "/dev/null", O_RDWR, 0)); RZ(posix_spawn_file_actions_adddup2(&fa, 1, 7)); + /* + * Open descriptors 6 & 7 so we can get to 8 & 9 for testing + * closefrom_np, but close 6 & 7 before the spawn since the + * child process will get them via the open and dup2 actions + * above. + */ + RL(fd4 = open("/dev/null", O_RDONLY)); + ATF_REQUIRE(fd4 == 6); + + RL(fd5 = open("/dev/null", O_RDONLY)); + ATF_REQUIRE(fd5 == 7); + + RL(fd6 = open("/dev/null", O_RDONLY)); + ATF_REQUIRE(fd6 == 8); + + RL(fd7 = open("/dev/null", O_RDONLY)); + ATF_REQUIRE(fd7 == 9); + + close(fd4); + close(fd5); + + RZ(posix_spawn_file_actions_addclosefrom_np(&fa, 8)); + snprintf(helper, sizeof helper, "%s/h_fileactions", atf_tc_get_config_var(tc, "srcdir")); RZ(posix_spawn(&pid, helper, &fa, NULL, args, NULL)); -- 2.54.0