This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH v2 2/5] posix: Add posix_spawn_file_actions_closefrom
- From: Adhemerval Zanella <adhemerval dot zanella at linaro dot org>
- To: libc-alpha at sourceware dot org
- Date: Wed, 28 Aug 2019 11:09:39 -0300
- Subject: Re: [PATCH v2 2/5] posix: Add posix_spawn_file_actions_closefrom
- References: <20190731183136.21545-1-adhemerval.zanella@linaro.org> <20190731183136.21545-2-adhemerval.zanella@linaro.org>
Ping.
On 31/07/2019 15:31, Adhemerval Zanella wrote:
> Changes from previous version:
>
> - Remove __spawn_valid_fd check on posix_spawn_file_actions_addclosefrom.
>
> - Rename __SUPPORT_SPAWN_CLOSEFROM macro to __SPAWN_SUPPORT_CLOSEFROM.
>
> - Use getdents64 instead of changing add internal __opendir_inplace.
>
> Regarding the lseek to reset the descriptor offset after each file removal,
> I think that by iteracting the descriptor based on getdents64 results there
> is no real need for it. The kernel returns the fds sequentially and there
> is no open operations done concurrently, so both my expectations and the
> tests result is getdents returns an updated version after a close() call.
>
> --
>
> This patch adds a way to close a range of file descriptors on posix_spawn
> as a new file action. The API is similar to the one provided by Solaris
> 11 [1], where the file action causes the all open file descriptors greater
> than or equal to input on to be closed when the new process is spawned.
>
> There are some discussions on BZ#10353 [2], although the bug itself asks
> for a generic solution (similar to the closeall provided by some BSD).
> The posix_spawn is safe to be implemented by interacting over /proc/self/fd,
> the Linux spawni.c does not use CLONE_FILES, so the helper process has its
> own file descriptor table and any failure (in /proc operation) aborts the
> process creation and returns an error to the caller.
>
> I am aware that this file action might be redundant to the current approach
> of POSIX in promoting O_CLOEXEC in more interfaces. However O_CLOEXEC is still
> not the default and for some specific usages, the caller needs to close all
> possible file descriptors to avoid them leaking. Some examples are CPython
> (discussed in BZ#10353) and OpenJDK jspawnhelper [3] (where OpenJDK spawns a
> helper process to exactly closes all file descriptors). Most likely any
> environment which calls functions that might open file descriptor under the
> hood and aim to use posix_spawn might face the same requirement.
>
> Checked on x86_64-linux-gnu, i686-linux-gnu, powerpc64le-linux-gnu, and
> aarch64-linux-gnu.
>
> * posix/Makefile (routines): Add spawn_faction_addclosefrom.
> (tests): Add tst-spawn5.
> (tst-spawn5-ARGS): New rule.
> * posix/Versions [GLIBC_2.30] (libc): Add
> posix_spawn_file_actions_addclosefrom_np.
> * posix/spawn.h (posix_spawn_file_actions_addclosefrom_np): New
> prototype.
> * posix/spawn_faction_addclosefrom.c: New file
> * posix/spawn_faction_destroy.c (__posix_spawn_file_actions_destroy):
> Handle spawn_do_closefrom.
> * posix/spawn_int.h (__spawn_action): Add closefrom_action and
> spawn_do_closefrom.
> * posix/spawn_int_abi.h: New file.
> * sysdeps/unix/sysv/linux/spawn_int_abi.h: Likewise.
> * posix/tst-spawn5.c: Likewise.
> * sysdeps/mach/hurd/spawni.c (__spawni, __spawni_child): Handle
> spawn_do_closefrom.
> * sysdeps/posix/spawni.c (__spawni_child): Likewise.
> * sysdeps/unix/sysv/linux/spawni.c (__spawni_child, __spawnix):
> Likewise.
> (spawn_closefrom): New function.
> * sysdeps/mach/hurd/i386/libc.abilist (2.30): Add
> posix_spawn_file_actions_addclosefrom_np.
> * sysdeps/unix/sysv/linux/aarch64/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/alpha/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/arm/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/csky/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/hppa/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/i386/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/ia64/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/microblaze/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/nios2/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist:
> Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/sh/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist: Likewise.
> * sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist: Likewise.
> * sysdeps/unix/sysv/unix/sysv/linux/x86_64/64/libc.abilist: Likewise.
> * sysdeps/unix/sysv/unix/sysv/linux/x86_64/x32/libc.abilist: Likewise.
> ---
> posix/Makefile | 5 +-
> posix/Versions | 1 +
> posix/spawn.h | 7 +
> posix/spawn_faction_addclosefrom.c | 58 +++++
> posix/spawn_faction_destroy.c | 1 +
> posix/spawn_int.h | 6 +
> posix/spawn_int_abi.h | 27 +++
> posix/tst-spawn5.c | 210 ++++++++++++++++++
> sysdeps/mach/hurd/i386/libc.abilist | 1 +
> sysdeps/mach/hurd/spawni.c | 4 +
> sysdeps/posix/spawni.c | 4 +
> sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/arm/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/csky/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/i386/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/ia64/libc.abilist | 1 +
> .../sysv/linux/m68k/coldfire/libc.abilist | 1 +
> .../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 +
> .../unix/sysv/linux/microblaze/libc.abilist | 1 +
> .../sysv/linux/mips/mips32/fpu/libc.abilist | 1 +
> .../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 +
> .../sysv/linux/mips/mips64/n32/libc.abilist | 1 +
> .../sysv/linux/mips/mips64/n64/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/nios2/libc.abilist | 1 +
> .../linux/powerpc/powerpc32/fpu/libc.abilist | 1 +
> .../linux/powerpc/powerpc64/be/libc.abilist | 1 +
> .../linux/powerpc/powerpc64/le/libc.abilist | 1 +
> .../unix/sysv/linux/riscv/rv64/libc.abilist | 1 +
> .../unix/sysv/linux/s390/s390-32/libc.abilist | 1 +
> .../unix/sysv/linux/s390/s390-64/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/sh/libc.abilist | 1 +
> .../sysv/linux/sparc/sparc32/libc.abilist | 1 +
> .../sysv/linux/sparc/sparc64/libc.abilist | 1 +
> sysdeps/unix/sysv/linux/spawn_int_abi.h | 25 +++
> sysdeps/unix/sysv/linux/spawni.c | 62 +++++-
> .../unix/sysv/linux/x86_64/64/libc.abilist | 1 +
> .../unix/sysv/linux/x86_64/x32/libc.abilist | 1 +
> 39 files changed, 425 insertions(+), 12 deletions(-)
> create mode 100644 posix/spawn_faction_addclosefrom.c
> create mode 100644 posix/spawn_int_abi.h
> create mode 100644 posix/tst-spawn5.c
> create mode 100644 sysdeps/unix/sysv/linux/spawn_int_abi.h
>
> diff --git a/posix/Makefile b/posix/Makefile
> index 8ac6743ad7..1ac41ad85a 100644
> --- a/posix/Makefile
> +++ b/posix/Makefile
> @@ -57,6 +57,7 @@ routines := \
> spawn_faction_init spawn_faction_destroy spawn_faction_addclose \
> spawn_faction_addopen spawn_faction_adddup2 spawn_valid_fd \
> spawn_faction_addchdir spawn_faction_addfchdir \
> + spawn_faction_addclosefrom \
> spawnattr_init spawnattr_destroy \
> spawnattr_getdefault spawnattr_setdefault \
> spawnattr_getflags spawnattr_setflags \
> @@ -100,7 +101,8 @@ tests := test-errno tstgetopt testfnm runtests runptests \
> tst-posix_fadvise tst-posix_fadvise64 \
> tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \
> tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \
> - bug-regex38 tst-regcomp-truncated tst-spawn-chdir
> + bug-regex38 tst-regcomp-truncated tst-spawn-chdir \
> + tst-spawn5
> tests-internal := bug-regex5 bug-regex20 bug-regex33 \
> tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \
> tst-glob_lstat_compat tst-spawn4-compat
> @@ -254,6 +256,7 @@ tst-exec-static-ARGS = $(tst-exec-ARGS)
> tst-execvpe5-ARGS = -- $(host-test-program-cmd)
> tst-spawn-ARGS = -- $(host-test-program-cmd)
> tst-spawn-static-ARGS = $(tst-spawn-ARGS)
> +tst-spawn5-ARGS = -- $(host-test-program-cmd)
> tst-dir-ARGS = `pwd` `cd $(common-objdir)/$(subdir); pwd` `cd $(common-objdir); pwd` $(objpfx)tst-dir
> tst-chmod-ARGS = $(objdir)
> tst-vfork3-ARGS = --test-dir=$(objpfx)
> diff --git a/posix/Versions b/posix/Versions
> index 7d06a6d0c0..c8268e5996 100644
> --- a/posix/Versions
> +++ b/posix/Versions
> @@ -146,6 +146,7 @@ libc {
> posix_spawn_file_actions_addfchdir_np;
> }
> GLIBC_2.30 {
> + posix_spawn_file_actions_addclosefrom_np;
> }
> GLIBC_PRIVATE {
> __libc_fork; __libc_pread; __libc_pwrite;
> diff --git a/posix/spawn.h b/posix/spawn.h
> index 471dbea022..773f416b2e 100644
> --- a/posix/spawn.h
> +++ b/posix/spawn.h
> @@ -213,6 +213,13 @@ extern int posix_spawn_file_actions_addchdir_np (posix_spawn_file_actions_t *
> extern int posix_spawn_file_actions_addfchdir_np (posix_spawn_file_actions_t *,
> int __fd)
> __THROW __nonnull ((1));
> +
> +/* Add an action to close all file descriptor greater than FROM during
> + spawn. This affects the subsequent file actions. */
> +extern int posix_spawn_file_actions_addclosefrom_np (posix_spawn_file_actions_t *,
> + int __from)
> + __THROW __nonnull ((1));
> +
> #endif
>
> __END_DECLS
> diff --git a/posix/spawn_faction_addclosefrom.c b/posix/spawn_faction_addclosefrom.c
> new file mode 100644
> index 0000000000..52e949c8b3
> --- /dev/null
> +++ b/posix/spawn_faction_addclosefrom.c
> @@ -0,0 +1,58 @@
> +/* Add a closefrom to a file action list for posix_spawn.
> + Copyright (C) 2019 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <http://www.gnu.org/licenses/>. */
> +
> +#include <errno.h>
> +#include <spawn.h>
> +#include <unistd.h>
> +#include <spawn_int.h>
> +
> +int
> +__posix_spawn_file_actions_addclosefrom (posix_spawn_file_actions_t
> + *file_actions, int from)
> +{
> +#if __SPAWN_SUPPORT_CLOSEFROM
> + struct __spawn_action *rec;
> +
> + if (fd < 0)
> + return EBADF;
> +
> + /* Allocate more memory if needed. */
> + if (file_actions->__used == file_actions->__allocated
> + && __posix_spawn_file_actions_realloc (file_actions) != 0)
> + /* This can only mean we ran out of memory. */
> + return ENOMEM;
> +
> + /* Add the new value. */
> + rec = &file_actions->__actions[file_actions->__used];
> + rec->tag = spawn_do_closefrom;
> + rec->action.closefrom_action.from = from;
> +
> + /* Account for the new entry. */
> + ++file_actions->__used;
> +
> + return 0;
> +#else
> + __set_errno (EINVAL);
> + return -1;
> +#endif
> +}
> +weak_alias (__posix_spawn_file_actions_addclosefrom,
> + posix_spawn_file_actions_addclosefrom_np)
> +#if !__SPAWN_SUPPORT_CLOSEFROM
> +stub_warning (posix_spawn_file_actions_addclosefrom_np)
> +#endif
> diff --git a/posix/spawn_faction_destroy.c b/posix/spawn_faction_destroy.c
> index 51fab13585..b45d1cd889 100644
> --- a/posix/spawn_faction_destroy.c
> +++ b/posix/spawn_faction_destroy.c
> @@ -39,6 +39,7 @@ __posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions)
> case spawn_do_close:
> case spawn_do_dup2:
> case spawn_do_fchdir:
> + case spawn_do_closefrom:
> /* No cleanup required. */
> break;
> }
> diff --git a/posix/spawn_int.h b/posix/spawn_int.h
> index 93b7597f90..0bc29226e4 100644
> --- a/posix/spawn_int.h
> +++ b/posix/spawn_int.h
> @@ -20,6 +20,7 @@
> #define _SPAWN_INT_H
>
> #include <spawn.h>
> +#include <spawn_int_abi.h>
> #include <stdbool.h>
>
> /* Data structure to contain the action information. */
> @@ -32,6 +33,7 @@ struct __spawn_action
> spawn_do_open,
> spawn_do_chdir,
> spawn_do_fchdir,
> + spawn_do_closefrom,
> } tag;
>
> union
> @@ -60,6 +62,10 @@ struct __spawn_action
> {
> int fd;
> } fchdir_action;
> + struct
> + {
> + int from;
> + } closefrom_action;
> } action;
> };
>
> diff --git a/posix/spawn_int_abi.h b/posix/spawn_int_abi.h
> new file mode 100644
> index 0000000000..142efed339
> --- /dev/null
> +++ b/posix/spawn_int_abi.h
> @@ -0,0 +1,27 @@
> +/* Internal ABI specific for posix_spawn functionality. Generic version.
> + Copyright (C) 2019 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <http://www.gnu.org/licenses/>. */
> +
> +#ifndef _SPAWN_INT_ABI_H
> +#define _SPAWN_INT_ABI_H
> +
> +/* The closefrom file actions requires either a syscall or an arch-specific
> + way to interact over all file descriptors and act uppon them (such
> + /proc/self/fd on Linux). */
> +#define __SPAWN_SUPPOR_CLOSEFROM 0
> +
> +#endif /* _SPAWN_INT_H */
> diff --git a/posix/tst-spawn5.c b/posix/tst-spawn5.c
> new file mode 100644
> index 0000000000..7af33a4dbe
> --- /dev/null
> +++ b/posix/tst-spawn5.c
> @@ -0,0 +1,210 @@
> +/* Tests for posix_spawn signal handling.
> + Copyright (C) 2019 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <http://www.gnu.org/licenses/>. */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <getopt.h>
> +#include <spawn.h>
> +#include <fcntl.h>
> +#include <sys/wait.h>
> +#include <dirent.h>
> +#include <stdbool.h>
> +#include <errno.h>
> +#include <limits.h>
> +
> +#include <support/check.h>
> +#include <support/xunistd.h>
> +#include <support/support.h>
> +#include <array_length.h>
> +
> +/* Nonzero if the program gets called via `exec'. */
> +static int restart;
> +#define CMDLINE_OPTIONS \
> + { "restart", no_argument, &restart, 1 },
> +
> +/* Called on process re-execution. */
> +static int
> +handle_restart (int from)
> +{
> + DIR *fds = opendir ("/proc/self/fd");
> + if (fds == NULL)
> + FAIL_EXIT1 ("opendir (\"/proc/self/fd\"): %m");
> +
> + while (true)
> + {
> + errno = 0;
> + struct dirent64 *e = readdir64 (fds);
> + if (e == NULL)
> + {
> + if (errno != 0)
> + FAIL_EXIT1 ("readdir: %m");
> + break;
> + }
> +
> + if (e->d_name[0] == '.')
> + continue;
> +
> + char *endptr;
> + long int fd = strtol (e->d_name, &endptr, 10);
> + if (*endptr != '\0' || fd < 0 || fd > INT_MAX)
> + FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s",
> + e->d_name);
> +
> + /* Skip the descriptor which is used to enumerate the
> + descriptors. */
> + if (fd == dirfd (fds))
> + continue;
> +
> + struct stat64 st;
> + if (fstat64 (fd, &st) != 0)
> + FAIL_EXIT1 ("readdir: fstat64 (%ld) failed: %m", fd);
> +
> + if (fd >= from)
> + FAIL_EXIT1 ("error: fd (%ld) greater than from (%d)", fd, from);
> + }
> +
> + closedir (fds);
> +
> + return 0;
> +}
> +
> +/* Common argument used for process re-execution. */
> +static char *initial_spargv[5];
> +static size_t initial_spargv_size;
> +
> +/* Re-execute the test process with both '--direct', '--restart', and the
> + TEST (as integer value) as arguments. */
> +static void
> +reexecute (int fd, const posix_spawn_file_actions_t *fa)
> +{
> + char *spargv[8];
> + int i;
> +
> + for (i = 0; i < initial_spargv_size; i++)
> + spargv[i] = initial_spargv[i];
> + /* Three digits per byte plus null terminator. */
> + char teststr[3 * sizeof (fd) + 1];
> + snprintf (teststr, array_length (teststr), "%d", fd);
> + spargv[i++] = teststr;
> + spargv[i] = NULL;
> + TEST_VERIFY (i < 8);
> +
> + pid_t pid;
> + int status;
> +
> + TEST_COMPARE (posix_spawn (&pid, spargv[0], fa, NULL, spargv, environ),
> + 0);
> + TEST_COMPARE (xwaitpid (pid, &status, 0), pid);
> + TEST_VERIFY (WIFEXITED (status));
> + TEST_VERIFY (!WIFSIGNALED (status));
> + TEST_COMPARE (WEXITSTATUS (status), 0);
> +}
> +
> +static void
> +do_test_closefrom (int num_fd_to_open)
> +{
> + int *fds = xmalloc (num_fd_to_open * sizeof (int));
> + for (int i = 0; i < num_fd_to_open; i++)
> + fds[i] = xopen ("/dev/null", O_WRONLY, 0);
> +
> + posix_spawn_file_actions_t fa;
> + /* posix_spawn_file_actions_init does not fail. */
> + posix_spawn_file_actions_init (&fa);
> +
> + {
> + int ret = posix_spawn_file_actions_addclosefrom_np (&fa, fds[0]);
> + if (ret == -1)
> + {
> + if (errno == ENOSYS)
> + /* Hurd currently does not support closefrom fileaction. */
> + FAIL_UNSUPPORTED ("posix_spawn_file_actions_addclosefrom_np unsupported");
> + else
> + FAIL_EXIT1 ("posix_spawn_file_actions_addclosefrom_np failed");
> + }
> + }
> +
> + /* Default check, all file descriptor from [fd[0], fd[1]) are opened. */
> + reexecute (fds[0], &fa);
> +
> + /* Add a gap in the range. */
> + xclose (fds[num_fd_to_open/2]);
> + xclose (fds[num_fd_to_open/2 + 1]);
> + reexecute (fds[0], &fa);
> +
> + /* Add another gap, at the beginning. */
> + xclose (fds[0]);
> + xclose (fds[1]);
> + reexecute (fds[0], &fa);
> +
> + /* Add another gap, now at the end. */
> + xclose (fds[num_fd_to_open-1]);
> + xclose (fds[num_fd_to_open-2]);
> + reexecute (fds[0], &fa);
> +
> + /* Open some more files, filling the gaps. */
> + for (int i = 0; i < 6; i++)
> + xopen ("/dev/null", O_WRONLY, 0);
> + reexecute (fds[0], &fa);
> +
> + /* Open some more, but with O_CLOEXEC. */
> + for (int i = 0; i < num_fd_to_open/2; i++)
> + xopen ("/dev/null", O_WRONLY | O_CLOEXEC, 0);
> +
> + free (fds);
> +}
> +
> +
> +static int
> +do_test (int argc, char *argv[])
> +{
> + /* We must have one or four parameters left if called initially:
> + + path for ld.so optional
> + + "--library-path" optional
> + + the library path optional
> + + the application name
> +
> + Plus one parameter to indicate which test to execute through
> + re-execution.
> +
> + So for default usage without --enable-hardcoded-path-in-tests, it
> + will be called initially with 5 arguments and later with 2. For
> + --enable-hardcoded-path-in-tests it will be called with 2 arguments
> + regardless. */
> +
> + if (argc != (restart ? 2 : 5) && argc != 2)
> + FAIL_EXIT1 ("wrong number of arguments (%d)", argc);
> +
> + if (restart)
> + return handle_restart (atoi (argv[1]));
> +
> + /* Respawn using the same arguments. */
> + for (initial_spargv_size = 0;
> + initial_spargv_size < (argc == 5 ? 4 : 1);
> + initial_spargv_size++)
> + initial_spargv[initial_spargv_size] = argv[initial_spargv_size + 1];
> + initial_spargv[initial_spargv_size++] = (char *) "--direct";
> + initial_spargv[initial_spargv_size++] = (char *) "--restart";
> +
> + do_test_closefrom (10);
> + do_test_closefrom (100);
> +
> + return 0;
> +}
> +
> +#define TEST_FUNCTION_ARGV do_test
> +#include <support/test-driver.c>
> diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
> index 1fc7ab2433..fcf957cfc6 100644
> --- a/sysdeps/mach/hurd/i386/libc.abilist
> +++ b/sysdeps/mach/hurd/i386/libc.abilist
> @@ -2175,6 +2175,7 @@ GLIBC_2.3.4 setipv4sourcefilter F
> GLIBC_2.3.4 setsourcefilter F
> GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> GLIBC_2.4 __fgets_chk F
> diff --git a/sysdeps/mach/hurd/spawni.c b/sysdeps/mach/hurd/spawni.c
> index e8024a2679..720e56ffb3 100644
> --- a/sysdeps/mach/hurd/spawni.c
> +++ b/sysdeps/mach/hurd/spawni.c
> @@ -597,6 +597,10 @@ __spawni (pid_t *pid, const char *file,
> case spawn_do_fchdir:
> err = child_fchdir (action->action.fchdir_action.fd);
> break;
> +
> + case spawn_do_closefrom:
> + err = EINVAL;
> + break;
> }
>
> if (err)
> diff --git a/sysdeps/posix/spawni.c b/sysdeps/posix/spawni.c
> index a5913feb14..3beaba91db 100644
> --- a/sysdeps/posix/spawni.c
> +++ b/sysdeps/posix/spawni.c
> @@ -231,6 +231,10 @@ __spawni_child (void *arguments)
> if (__fchdir (action->action.fchdir_action.fd) != 0)
> goto fail;
> break;
> +
> + case spawn_do_closefrom:
> + __set_errno (EINVAL);
> + goto fail;
> }
> }
> }
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index a4c31932cb..e1e793b348 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2143,5 +2143,6 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index fe85a35620..735e54f433 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -2218,6 +2218,7 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
> index bc3df8dcea..a3b9db6efa 100644
> --- a/sysdeps/unix/sysv/linux/arm/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
> @@ -128,6 +128,7 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _Exit F
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 9b3cee65bb..88d112b9b1 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2087,5 +2087,6 @@ GLIBC_2.29 xprt_register F
> GLIBC_2.29 xprt_unregister F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index 75edece94a..2925c96183 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2039,6 +2039,7 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index edeaf8e722..9fd8ceb639 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2205,6 +2205,7 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> index b5d460eeb2..37d817eeb3 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> @@ -2071,6 +2071,7 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index 05633b3cb8..e81ab1f0bf 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -129,6 +129,7 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _Exit F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index 47eb7b4608..cd5742bf63 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2148,6 +2148,7 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> index f7ced487f7..957b14d992 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> @@ -2135,5 +2135,6 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index e49dc4272e..b8ffdea448 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2122,6 +2122,7 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index daa3b60c5b..e1c861720a 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2120,6 +2120,7 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 457ce0b6f2..88fe3f4d26 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2128,6 +2128,7 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 63d5c03bfb..7c6dafa818 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2122,6 +2122,7 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index 7fec0c9670..487b005070 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -2176,5 +2176,6 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index 9200a54309..db81db978a 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -2178,6 +2178,7 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index 2860df8ebc..06dfdf1fed 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2041,6 +2041,7 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index 2229a1dcc0..eb0532937e 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2245,5 +2245,6 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index 31010e6cf7..4985fa93e3 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2105,5 +2105,6 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 576295deff..1ef1b9d4cc 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -2173,6 +2173,7 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index abf0473683..f9d9fe68ca 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2077,6 +2077,7 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
> index 41977f6e9c..1b12384dd1 100644
> --- a/sysdeps/unix/sysv/linux/sh/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
> @@ -2043,6 +2043,7 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index 3d2f00ca52..a7c244cb56 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -2167,6 +2167,7 @@ GLIBC_2.30 __nldbl_warn F
> GLIBC_2.30 __nldbl_warnx F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index 2f20643e8e..a71facfb43 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2094,6 +2094,7 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/spawn_int_abi.h b/sysdeps/unix/sysv/linux/spawn_int_abi.h
> new file mode 100644
> index 0000000000..9c4b31ccae
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/spawn_int_abi.h
> @@ -0,0 +1,25 @@
> +/* Internal ABI specific for posix_spawn functionality. Linux version.
> + Copyright (C) 2019 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <http://www.gnu.org/licenses/>. */
> +
> +#ifndef _SPAWN_INT_ABI_H
> +#define _SPAWN_INT_ABI_H
> +
> +/* spawni.c implements closefrom by interacting over /proc/self/fd. */
> +#define __SPAWN_SUPPORT_CLOSEFROM 1
> +
> +#endif /* _SPAWN_INT_H */
> diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
> index c1abf3f960..ca7bf99825 100644
> --- a/sysdeps/unix/sysv/linux/spawni.c
> +++ b/sysdeps/unix/sysv/linux/spawni.c
> @@ -17,20 +17,16 @@
> <http://www.gnu.org/licenses/>. */
>
> #include <spawn.h>
> -#include <fcntl.h>
> #include <paths.h>
> -#include <string.h>
> +#include <dirent.h>
> #include <sys/resource.h>
> -#include <sys/wait.h>
> -#include <sys/param.h>
> -#include <sys/mman.h>
> #include <not-cancel.h>
> #include <local-setxid.h>
> #include <shlib-compat.h>
> -#include <nptl/pthreadP.h>
> -#include <dl-sysdep.h>
> -#include <libc-pointer-arith.h>
> +#include <sigsetops.h>
> +#include <internal-signals.h>
> #include <ldsodefs.h>
> +#include <ctype.h>
> #include "spawn_int.h"
>
> /* The Linux implementation of posix_spawn{p} uses the clone syscall directly
> @@ -114,6 +110,44 @@ maybe_script_execute (struct posix_spawn_args *args)
> }
> }
>
> +/* Close all file descriptor up to FROM by interacting /proc/self/fd. */
> +static bool
> +spawn_closefrom (int from)
> +{
> + struct dirent64 entries[1024 / sizeof (struct dirent64)];
> +
> + int dirfd = __open ("/proc/self/fd", O_RDONLY | O_DIRECTORY, 0);
> + if (dirfd == -1)
> + return false;
> +
> + ssize_t r;
> + while ((r = __getdents64 (dirfd, entries, sizeof (entries))) > 0)
> + {
> + struct dirent64 *dp = entries;
> + struct dirent64 *edp = (void *)((uintptr_t) dp + r);
> +
> + for (struct dirent64 *dp = entries; dp < edp;
> + dp = (void *)((uintptr_t) dp + dp->d_reclen))
> + {
> + int fd = 0;
> +
> + if (dp->d_name[0] == '.')
> + continue;
> +
> + for (const char *s = dp->d_name; isdigit (*s); s++)
> + fd = 10 * fd + (*s - '0');
> +
> + if (fd == dirfd || fd < from)
> + continue;
> +
> + __close_nocancel (fd);
> + }
> + }
> +
> + __close_nocancel (dirfd);
> + return true;
> +}
> +
> /* Function used in the clone call to setup the signals mask, posix_spawn
> attributes, and file actions. It run on its own stack (provided by the
> posix_spawn call). */
> @@ -280,6 +314,11 @@ __spawni_child (void *arguments)
> if (__fchdir (action->action.fchdir_action.fd) != 0)
> goto fail;
> break;
> +
> + case spawn_do_closefrom:
> + if (!spawn_closefrom (action->action.closefrom_action.from))
> + goto fail;
> + break;
> }
> }
> }
> @@ -339,12 +378,13 @@ __spawnix (pid_t * pid, const char *file,
> int prot = (PROT_READ | PROT_WRITE
> | ((GL (dl_stack_flags) & PF_X) ? PROT_EXEC : 0));
>
> - /* Add a slack area for child's stack. */
> - size_t argv_size = (argc * sizeof (void *)) + 512;
> + size_t argv_size = (argc * sizeof (void *));
> /* We need at least a few pages in case the compiler's stack checking is
> enabled. In some configs, it is known to use at least 24KiB. We use
> 32KiB to be "safe" from anything the compiler might do. Besides, the
> - extra pages won't actually be allocated unless they get used. */
> + extra pages won't actually be allocated unless they get used.
> + It also acts the slack for spawn_closefrom (including MIPS64 getdents64
> + where it might use about 1k extra stack space. */
> argv_size += (32 * 1024);
> size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize));
> void *stack = __mmap (NULL, stack_size, prot,
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index 59f85d9373..78a43f5851 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2052,6 +2052,7 @@ GLIBC_2.3.4 xdr_quad_t F
> GLIBC_2.3.4 xdr_u_quad_t F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
> GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index 67a4e238d6..b83897ddbf 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2151,5 +2151,6 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
> GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
> GLIBC_2.30 getdents64 F
> GLIBC_2.30 gettid F
> +GLIBC_2.30 posix_spawn_file_actions_addclosefrom_np F
> GLIBC_2.30 tgkill F
> GLIBC_2.30 twalk_r F
>