public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 1/4] support: Add xclone
@ 2020-12-22 21:27 Adhemerval Zanella
  2020-12-22 21:27 ` [PATCH v2 2/4] Linux: Add close_range Adhemerval Zanella
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Adhemerval Zanella @ 2020-12-22 21:27 UTC (permalink / raw)
  To: libc-alpha; +Cc: Florian Weimer

It is a wrapper for Linux close syscall, to simplify the call to the
use only the most common arguments and remove architecture specific
handling (such as ia64 different name and signature).
---
 support/Makefile |  1 +
 support/xclone.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 support/xsched.h | 36 ++++++++++++++++++++++++++++++++++++
 3 files changed, 83 insertions(+)
 create mode 100644 support/xclone.c
 create mode 100644 support/xsched.h

diff --git a/support/Makefile b/support/Makefile
index 3198eb5022..aecd27316e 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -89,6 +89,7 @@ libsupport-routines = \
   xcalloc \
   xchroot \
   xclock_gettime \
+  xclone \
   xclose \
   xconnect \
   xcopy_file_range \
diff --git a/support/xclone.c b/support/xclone.c
new file mode 100644
index 0000000000..e7efffb82b
--- /dev/null
+++ b/support/xclone.c
@@ -0,0 +1,46 @@
+/* Auxiliary wrapper to issue the clone symbol.
+   Copyright (C) 2020 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stackinfo.h>  /* For _STACK_GROWS_{UP,DOWN}.  */
+#include <xsched.h>
+
+pid_t
+xclone (int (*fn) (void *arg), void *arg, void *stack, size_t stack_size,
+	int flags)
+{
+  pid_t r = -1;
+
+#ifdef __linux__
+# ifdef __ia64__
+  extern int __clone2 (int (*fn) (void *arg), void *stack, size_t stack_size,
+		       int flags, void *arg, ...);
+  r = __clone2 (f, stack, stack_size, flags, arg, /* ptid */ NULL,
+		/* tls */ NULL, /* ctid  */ ctid);
+# else
+#  if _STACK_GROWS_DOWN
+  r = clone (fn, stack + stack_size, flags, arg, /* ptid */ NULL,
+	     /* tls */ NULL, /* ctid */  NULL);
+#  elif _STACK_GROWS_UP
+  r = clone (fn, stack, flags, arg, /* ptid */ NULL, /* tls */ NULL,
+	     &ctid);
+#  endif
+# endif
+#endif
+
+  return r;
+}
diff --git a/support/xsched.h b/support/xsched.h
new file mode 100644
index 0000000000..8523f03f82
--- /dev/null
+++ b/support/xsched.h
@@ -0,0 +1,36 @@
+/* Wrapper for sched.h functions.
+   Copyright (C) 2020 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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef SUPPORT_XSCHED_H
+#define SUPPORT_XSCHED_H
+
+__BEGIN_DECLS
+
+#include <sched.h>
+#include <sys/types.h>
+
+#define DEFINE_STACK(name, size) \
+  char name[size] __attribute__ ((aligned))
+
+pid_t
+xclone (int (*fn) (void *arg), void *arg, void *stack, size_t stack_size,
+	int flags);
+
+__END_DECLS
+
+#endif
-- 
2.25.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 2/4] Linux: Add close_range
  2020-12-22 21:27 [PATCH 1/4] support: Add xclone Adhemerval Zanella
@ 2020-12-22 21:27 ` Adhemerval Zanella
  2020-12-23 12:22   ` Florian Weimer
  2020-12-22 21:27 ` [PATCH v2 3/4] io: Add closefrom [BZ #10353] Adhemerval Zanella
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Adhemerval Zanella @ 2020-12-22 21:27 UTC (permalink / raw)
  To: libc-alpha; +Cc: Florian Weimer

Changes from previous version [1]:

  - Make the syscall not a cancellation entrypoint.
  - Move tst-clone.h to libsupport
  - Fixed typos.
  - Add clone (CLONE_FILES) and check if the close_range closes
    the parent table as well.
  - Remove file descriptors array
  - Add manual entry

[1] https://patchwork.sourceware.org/project/glibc/patch/20201221215027.2176966-1-adhemerval.zanella@linaro.org/
--

It was added on Linux 5.9 (278a5fbaed89).  Although FreeBSD has added
the same syscall, this only adds the symbol on Linux ports.  This
syscall is required to provided a fail-safe way to implement the
closefrom symbol (BZ #10353).

The tst-close_range-consts.py requires a toolchain with an updated
kernel headers that provides the close_range.h UAPI kernel header.

Checked on x86_64-linux-gnu on kernel v5.9 and v5.4.
---
 NEWS                                          |   2 +
 include/bits/unistd_ext.h                     |   6 +
 manual/llio.texi                              |  31 +++
 sysdeps/unix/sysv/linux/Makefile              |  13 +-
 sysdeps/unix/sysv/linux/Versions              |   3 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/bits/unistd_ext.h     |  11 +
 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 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
 .../sysv/linux/microblaze/be/libc.abilist     |   1 +
 .../sysv/linux/mips/mips32/fpu/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/rv32/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/le/libc.abilist    |   1 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/syscalls.list         |   1 +
 .../unix/sysv/linux/tst-close_range-consts.py |  49 +++++
 sysdeps/unix/sysv/linux/tst-close_range.c     | 198 ++++++++++++++++++
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
 35 files changed, 338 insertions(+), 2 deletions(-)
 create mode 100644 include/bits/unistd_ext.h
 create mode 100644 sysdeps/unix/sysv/linux/tst-close_range-consts.py
 create mode 100644 sysdeps/unix/sysv/linux/tst-close_range.c

diff --git a/NEWS b/NEWS
index 0820984547..9e829841f6 100644
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,8 @@ Major new features:
   The 32-bit RISC-V port requires at least Linux 5.4, GCC 7.1 and binutils
   2.28.
 
+* On Linux, the close_range function has been added.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * The mallinfo function is marked deprecated.  Callers should call
diff --git a/include/bits/unistd_ext.h b/include/bits/unistd_ext.h
new file mode 100644
index 0000000000..277be05746
--- /dev/null
+++ b/include/bits/unistd_ext.h
@@ -0,0 +1,6 @@
+#include_next <bits/unistd_ext.h>
+
+#ifndef _ISOMAC
+extern int __close_range (unsigned int lowfd, unsigned int highfd, int flags);
+libc_hidden_proto (__close_range);
+#endif
diff --git a/manual/llio.texi b/manual/llio.texi
index c0a53e1a6e..018e7933de 100644
--- a/manual/llio.texi
+++ b/manual/llio.texi
@@ -284,6 +284,37 @@ of trying to close its underlying file descriptor with @code{close}.
 This flushes any buffered output and updates the stream object to
 indicate that it is closed.
 
+@deftypefun int close_range (unsigned int @var{lowfd}, unsigned int @var{maxfd}, int @var{flags})
+@standards{Linux, unistd.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
+@c This is a syscall for Linux v5.9.  There is no fallback emultation for
+@c older kernels.
+
+The function @code{clode_range} closes the file descriptor from @var{lowfd}
+to @var{maxfd} (included).  This function is similar to call @code{close} in
+specified file descriptor range.
+
+The @var{flags} add options on how the files are closes.  Linux currently
+supports.
+
+@vtable @code
+@item CLOSE_RANGE_UNSHARE
+It unshare the range of file descriptors from any other processes, instead
+of closing them.
+@end vtable
+
+The normal return value from @code{close} is @math{0}; a value of @math{-1}
+is returned in case of failure.  The following @code{errno} error
+conditions are defined for this function:
+
+@table @code
+@item EINVAL
+The @var{lowfd} value is larger than @var{maxfd} or an unsupported @var{flag}
+is used.
+@end table
+@end deftypefun
+
+
 @node I/O Primitives
 @section Input and Output Primitives
 
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 09604e128b..e06c2a1f0d 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -61,7 +61,7 @@ sysdep_routines += adjtimex clone umount umount2 readahead sysctl \
 		   open_by_handle_at mlock2 pkey_mprotect pkey_set pkey_get \
 		   timerfd_gettime timerfd_settime prctl \
 		   process_vm_readv process_vm_writev clock_adjtime \
-		   time64-support pselect32
+		   time64-support pselect32 close_range
 
 CFLAGS-gethostid.c = -fexceptions
 CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables
@@ -103,7 +103,8 @@ tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \
 	 tst-quota tst-sync_file_range tst-sysconf-iov_max tst-ttyname \
 	 test-errno-linux tst-memfd_create tst-mlock2 tst-pkey \
 	 tst-rlimit-infinity tst-ofdlocks tst-gettid tst-gettid-kill \
-	 tst-tgkill tst-sysvsem-linux tst-sysvmsg-linux tst-sysvshm-linux
+	 tst-tgkill tst-sysvsem-linux tst-sysvmsg-linux tst-sysvshm-linux \
+	 tst-close_range
 tests-internal += tst-ofdlocks-compat tst-sigcontext-get_pc
 
 CFLAGS-tst-sigcontext-get_pc.c = -fasynchronous-unwind-tables
@@ -177,6 +178,14 @@ $(objpfx)tst-mman-consts.out: ../sysdeps/unix/sysv/linux/tst-mman-consts.py
 	  < /dev/null > $@ 2>&1; $(evaluate-test)
 $(objpfx)tst-mman-consts.out: $(sysdeps-linux-python-deps)
 
+tests-special += $(objpfx)tst-close_range-consts.out
+$(objpfx)tst-close_range-consts.out: ../sysdeps/unix/sysv/linux/tst-close_range-consts.py
+	$(sysdeps-linux-python) \
+	../sysdeps/unix/sysv/linux/tst-close_range-consts.py \
+	    $(sysdeps-linux-python-cc) \
+	< /dev/null > $@ 2>&1; $(evaluate-test)
+$(objpfx)tst-close_range-consts.out: $(sysdeps-linux-python-deps)
+
 $(objpfx)tst-gettid: $(shared-thread-library)
 $(objpfx)tst-gettid-kill: $(shared-thread-library)
 $(objpfx)tst-tgkill: $(shared-thread-library)
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index c35f783e2a..e2a6fa763f 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -169,6 +169,9 @@ libc {
   }
   GLIBC_2.32 {
   }
+  GLIBC_2.33 {
+    close_range;
+  }
   GLIBC_PRIVATE {
     # functions used in other libraries
     __syscall_rt_sigqueueinfo;
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 4cc1c6a591..a52decb822 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2160,6 +2160,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 26ad9845e4..ed085c9b3c 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2242,6 +2242,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index bb9dfd4daf..88a17c2fdf 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1920,6 +1920,7 @@ GLIBC_2.32 wprintf F
 GLIBC_2.32 write F
 GLIBC_2.32 writev F
 GLIBC_2.32 wscanf F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 9ab3924888..a690962068 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -141,6 +141,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/bits/unistd_ext.h b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
index c315cc5cb8..799c59512c 100644
--- a/sysdeps/unix/sysv/linux/bits/unistd_ext.h
+++ b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
@@ -33,4 +33,15 @@
    not detached and has not been joined.  */
 extern __pid_t gettid (void) __THROW;
 
+/* Unshare the file descriptor table before closing file descriptors.  */
+#define CLOSE_RANGE_UNSHARE     (1U << 1)
+
+/* Close all file descriptors in the range FD up to MAX_FD.  The flag FLAGS
+   are define by the CLOSE_RANGE prefix.  This function behaves like close
+   on the range, but in a fail-safe where it will either fail and not close
+   any file descriptor or close all of them.  Returns 0 on successor or -1
+   for failure (and sets errno accordingly).  */
+extern int close_range (unsigned int __fd, unsigned int __max_fd,
+			int __flags) __THROW;
+
 #endif
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 14a84dac8f..d37882413c 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2104,6 +2104,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 5c8502f3d3..61450e47d5 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2063,6 +2063,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 4f0d3c1eb5..672ff8a002 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2229,6 +2229,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index e3b345b803..53e53005e9 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2095,6 +2095,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index c4891479d3..cc0d93b381 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2175,6 +2175,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 143b0163b4..b4acf52c41 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2155,6 +2155,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index b2295f1937..fadbf99d4b 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2146,6 +2146,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index aa9c6a4dca..c456ebcea3 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2152,6 +2152,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 5939588ad5..5ed54e7c94 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2146,6 +2146,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 92556c4237..67b611ef6d 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2193,6 +2193,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 26c93dff05..ed0f239cd5 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2202,6 +2202,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index c2ca00709e..a4b9900036 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2065,6 +2065,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 0ea50dc851..e5d666dab3 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2355,6 +2355,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 0263e284d4..f8c34aca7c 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -595,6 +595,7 @@ GLIBC_2.33 clock_nanosleep F
 GLIBC_2.33 clock_settime F
 GLIBC_2.33 clone F
 GLIBC_2.33 close F
+GLIBC_2.33 close_range F
 GLIBC_2.33 closedir F
 GLIBC_2.33 closelog F
 GLIBC_2.33 confstr F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 1626c5351f..6042d42aba 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2122,6 +2122,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index a66426eb4d..46d2de3030 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2200,6 +2200,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index ab351873ae..9fda4babba 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2101,6 +2101,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index d36f228192..110f7ebf22 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2067,6 +2067,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 59b4313280..1b31685a24 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2191,6 +2191,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 266dcdfa08..9ad88bf7b3 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2118,6 +2118,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list
index 01ec2bfa95..53575669c7 100644
--- a/sysdeps/unix/sysv/linux/syscalls.list
+++ b/sysdeps/unix/sysv/linux/syscalls.list
@@ -101,3 +101,4 @@ pkey_alloc	EXTRA	pkey_alloc	i:ii	pkey_alloc
 pkey_free	EXTRA	pkey_free	i:i	pkey_free
 gettid          EXTRA   gettid          Ei:     __gettid	gettid
 tgkill          EXTRA   tgkill          i:iii   __tgkill	tgkill
+close_range     EXTRA   close_range     i:iii   __close_range   close_range
diff --git a/sysdeps/unix/sysv/linux/tst-close_range-consts.py b/sysdeps/unix/sysv/linux/tst-close_range-consts.py
new file mode 100644
index 0000000000..3a0d4423e8
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-close_range-consts.py
@@ -0,0 +1,49 @@
+#!/usr/bin/python3
+# Test that glibc's unistd_ext.h constants match the kernel's.
+# Copyright (C) 2020 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
+# <https://www.gnu.org/licenses/>.
+
+import argparse
+import sys
+
+import glibcextract
+import glibcsyscalls
+
+
+def main():
+    """The main entry point."""
+    parser = argparse.ArgumentParser(
+        description="Test that glibc's unistd_ext.h constants match "
+                    "the kernel's.")
+    parser.add_argument('--cc', metavar='CC',
+                        help='C compiler (including options) to use')
+    args = parser.parse_args()
+    linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
+    linux_version_glibc = (5, 9)
+    sys.exit(glibcextract.compare_macro_consts(
+        '#define _GNU_SOURCE 1\n'
+        '#include <unistd.h>\n',
+        '#define _GNU_SOURCE 1\n'
+        '#include <linux/close_range.h>\n',
+        args.cc,
+        'CLOSE_RANGE_.*',
+        None,
+        linux_version_glibc > linux_version_headers,
+        linux_version_headers > linux_version_glibc))
+
+if __name__ == '__main__':
+    main()
diff --git a/sysdeps/unix/sysv/linux/tst-close_range.c b/sysdeps/unix/sysv/linux/tst-close_range.c
new file mode 100644
index 0000000000..1a127bb9cb
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-close_range.c
@@ -0,0 +1,198 @@
+/* Test for the close_range system call.
+   Copyright (C) 2020 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <array_length.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/descriptors.h>
+#include <support/support.h>
+#include <support/xsched.h>
+#include <support/xunistd.h>
+
+#define NFDS 100
+
+static void
+close_range_test_common (int lowfd, unsigned int flags)
+{
+  const int maximum_fd = lowfd + NFDS;
+  const int half_fd = maximum_fd / 2;
+  const int gap_1 = maximum_fd - 8;
+
+  /* Close half of the descriptors and check result.  */
+  {
+    int r = close_range (lowfd, half_fd, flags);
+    if (r == -1 && errno == ENOSYS)
+      FAIL_UNSUPPORTED ("close_range not supported");
+    TEST_COMPARE (r, 0);
+  }
+  for (int i = lowfd; i <= half_fd; i++)
+    {
+      TEST_COMPARE (fcntl (i, F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  for (int i = half_fd + 1; i < maximum_fd; i++)
+    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
+
+  /* Create some gaps, close up to a threshold, and check result.  */
+  xclose (57);
+  xclose (78);
+  xclose (81);
+  xclose (82);
+  xclose (84);
+  xclose (90);
+
+  TEST_COMPARE (close_range (half_fd + 1, gap_1, flags), 0);
+  for (int i = half_fd + 1; i < gap_1; i++)
+    {
+      TEST_COMPARE (fcntl (i, F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  for (int i = gap_1 + 1; i < maximum_fd; i++)
+    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
+
+  /* Close the remmaining but the last one.  */
+  TEST_COMPARE (close_range (gap_1 + 1, maximum_fd - 1, flags), 0);
+  for (int i = gap_1 + 1; i < maximum_fd - 1; i++)
+    {
+      TEST_COMPARE (fcntl (i, F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  TEST_VERIFY (fcntl (maximum_fd, F_GETFL) > -1);
+
+  /* Close the last one.  */
+  TEST_COMPARE (close_range (maximum_fd, maximum_fd, flags), 0);
+  TEST_COMPARE (fcntl (maximum_fd, F_GETFL), -1);
+  TEST_COMPARE (errno, EBADF);
+}
+
+/* Basic tests: check if the syscall close ranges with and without gaps.  */
+static void
+__attribute__((used))
+close_range_test (void)
+{
+  struct support_descriptors *descrs = support_descriptors_list ();
+
+  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
+  for (int i = 0; i < NFDS; i++)
+    xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
+
+  close_range_test_common (lowfd, 0);
+
+  /* Double check by check the /proc.  */
+  support_descriptors_check (descrs);
+  support_descriptors_free (descrs);
+}
+
+_Noreturn static int
+close_range_test_fn (void *arg)
+{
+  int lowfd = (int) ((uintptr_t) arg);
+  close_range_test_common (lowfd, 0);
+  exit (EXIT_SUCCESS);
+}
+
+/* Check if a clone_range on a subprocess created with CLONE_FILES close
+   the shared file descriptor table entries in the parent.  */
+static void
+__attribute__((used))
+close_range_test_subprocess (void)
+{
+  struct support_descriptors *descrs = support_descriptors_list ();
+
+  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
+  for (int i = 0; i < NFDS; i++)
+    xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
+
+  enum { stack_size = 4096 };
+  DEFINE_STACK (stack, stack_size);
+  pid_t pid = xclone (close_range_test_fn, (void*) (uintptr_t) lowfd, stack,
+		      stack_size, CLONE_FILES | SIGCHLD);
+  TEST_VERIFY_EXIT (pid > 0);
+  int status;
+  xwaitpid (pid, &status, 0);
+  TEST_VERIFY (WIFEXITED (status));
+  TEST_COMPARE (WEXITSTATUS(status), 0);
+
+  for (int i = lowfd; i < NFDS; i++)
+    TEST_VERIFY (fcntl (i, F_GETFL) < 0);
+
+  support_descriptors_check (descrs);
+  support_descriptors_free (descrs);
+}
+
+
+_Noreturn static int
+close_range_unshare_test_fn (void *arg)
+{
+  int lowfd = (int) ((uintptr_t) arg);
+  close_range_test_common (lowfd, CLOSE_RANGE_UNSHARE);
+  exit (EXIT_SUCCESS);
+}
+
+/* Check if a close_range with CLOSE_RANGE_UNSHARE issued from a subprocess
+   created with CLONE_FILES does not close the parent file descriptor list.  */
+static void
+__attribute__((used))
+close_range_unshare_test (void)
+{
+  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
+  for (int i = 0; i < NFDS; i++)
+    xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
+
+  struct support_descriptors *descrs = support_descriptors_list ();
+
+  enum { stack_size = 4096 };
+  DEFINE_STACK (stack, stack_size);
+  pid_t pid = xclone (close_range_unshare_test_fn, (void*) (uintptr_t) lowfd,
+		      stack, stack_size, CLONE_FILES | SIGCHLD);
+  TEST_VERIFY_EXIT (pid > 0);
+  int status;
+  xwaitpid (pid, &status, 0);
+  TEST_VERIFY (WIFEXITED (status));
+  TEST_COMPARE (WEXITSTATUS(status), 0);
+
+  for (int i = 0; i < NFDS; i++)
+    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
+
+  support_descriptors_check (descrs);
+  support_descriptors_free (descrs);
+
+  TEST_COMPARE (close_range (lowfd, lowfd + NFDS, 0), 0);
+}
+
+static int
+do_test (void)
+{
+  close_range_test ();
+  close_range_test_subprocess ();
+  close_range_unshare_test ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 4fff61818b..5089a21981 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2076,6 +2076,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 102ed47a9c..c3db0fc7ca 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2173,6 +2173,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
-- 
2.25.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 3/4] io: Add closefrom [BZ #10353]
  2020-12-22 21:27 [PATCH 1/4] support: Add xclone Adhemerval Zanella
  2020-12-22 21:27 ` [PATCH v2 2/4] Linux: Add close_range Adhemerval Zanella
@ 2020-12-22 21:27 ` Adhemerval Zanella
  2020-12-23 13:28   ` Florian Weimer
  2020-12-22 21:27 ` [PATCH v2 4/4] posix: Add posix_spawn_file_actions_closefrom Adhemerval Zanella
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Adhemerval Zanella @ 2020-12-22 21:27 UTC (permalink / raw)
  To: libc-alpha; +Cc: Florian Weimer

Changes from previous version [1]:

  - Use __close_nocancel_nostatus on generic implementation.
  - Make the symbol not a cancellation entrypoint.
  - Add manual entry.

[1] https://patchwork.sourceware.org/project/glibc/patch/20201221215027.2176966-2-adhemerval.zanella@linaro.org/

--

The symbol closes all open file descriptors greater than or equal to
input argument.  Negative values are campled to 0, i.e, it will close
all file descriptors.

As indicated by the bug report, this is a common symbol provided by
different systems (Solaris, OpenBSD, NetBSD, FreeBSD) and, although
its has inherent issues with not taking in consideration internal libc
file descriptors (such as syslog), this is also a common feature used
in multiple projects [1][2][3][4][5].

The Linux fallback implementation iterates over /proc and close all
file descriptors sequentially.  Although it was raised the questioning
whether getdents on /proc/self/fd might return disjointed entries
when file descriptor are closed; it does not seems the case on my
testing on multiple kernel (v4.18, v5.4, v5.9) and the same strategy
is used on different projects [1][2][3][5].

Also, the interface is set a fail-safe meaning that a failure in the
fallback results in a process abort.

Checked on x86_64-linux-gnu on kernel v5.9 and v5.4.

[1] https://github.com/systemd/systemd/blob/5238e9575906297608ff802a27e2ff9effa3b338/src/basic/fd-util.c#L217
[2] https://github.com/lxc/lxc/blob/ddf4b77e11a4d08f09b7b9cd13e593f8c047edc5/src/lxc/start.c#L236
[3] https://github.com/python/cpython/blob/9e4f2f3a6b8ee995c365e86d976937c141d867f8/Modules/_posixsubprocess.c#L220
[4] https://github.com/rust-lang/rust/blob/5f47c0613ed4eb46fca3633c1297364c09e5e451/src/libstd/sys/unix/process2.rs#L303-L308
[5] https://github.com/openjdk/jdk/blob/master/src/java.base/unix/native/libjava/childproc.c#L82
---
 NEWS                                          |   4 +
 include/unistd.h                              |   1 +
 io/Makefile                                   |   5 +-
 io/Versions                                   |   1 +
 io/closefrom.c                                |  33 ++++
 io/tst-closefrom.c                            | 143 ++++++++++++++++++
 manual/llio.texi                              |  14 ++
 posix/unistd.h                                |   6 +
 sysdeps/mach/hurd/i386/libc.abilist           |   1 +
 sysdeps/unix/sysv/linux/Makefile              |   2 +-
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/closefrom.c           |  35 +++++
 sysdeps/unix/sysv/linux/closefrom_fallback.c  |  88 +++++++++++
 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 +
 .../sysv/linux/microblaze/be/libc.abilist     |   1 +
 .../sysv/linux/microblaze/le/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 +
 .../powerpc/powerpc32/nofpu/libc.abilist      |   1 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv32/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/be/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
 44 files changed, 362 insertions(+), 3 deletions(-)
 create mode 100644 io/closefrom.c
 create mode 100644 io/tst-closefrom.c
 create mode 100644 sysdeps/unix/sysv/linux/closefrom.c
 create mode 100644 sysdeps/unix/sysv/linux/closefrom_fallback.c

diff --git a/NEWS b/NEWS
index 9e829841f6..e6446f0548 100644
--- a/NEWS
+++ b/NEWS
@@ -30,6 +30,10 @@ Major new features:
 
 * On Linux, the close_range function has been added.
 
+* The function closefrom has been added.  It closes all file descriptors
+  greater than given integer.  This function is a GNU extension, although it
+  also present in other systems.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * The mallinfo function is marked deprecated.  Callers should call
diff --git a/include/unistd.h b/include/unistd.h
index 54becbc9eb..d48ad6c799 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -153,6 +153,7 @@ extern int __brk (void *__addr) attribute_hidden;
 extern int __close (int __fd);
 libc_hidden_proto (__close)
 extern int __libc_close (int __fd);
+extern _Bool __closefrom_fallback (int __lowfd) attribute_hidden;
 extern ssize_t __read (int __fd, void *__buf, size_t __nbytes);
 libc_hidden_proto (__read)
 extern ssize_t __write (int __fd, const void *__buf, size_t __n);
diff --git a/io/Makefile b/io/Makefile
index 33f5b0b867..56a788c2d5 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -55,7 +55,8 @@ routines :=								\
 	posix_fadvise posix_fadvise64					\
 	posix_fallocate posix_fallocate64				\
 	sendfile sendfile64 copy_file_range 				\
-	utimensat futimens file_change_detection
+	utimensat futimens file_change_detection			\
+	closefrom
 
 others		:= pwd
 test-srcs	:= ftwtest
@@ -69,7 +70,7 @@ tests		:= test-utime test-stat test-stat2 test-lfs tst-getcwd \
 		   tst-fts tst-fts-lfs tst-open-tmpfile \
 		   tst-copy_file_range tst-getcwd-abspath tst-lockf \
 		   tst-ftw-lnk tst-file_change_detection tst-lchmod \
-		   tst-ftw-bz26353
+		   tst-ftw-bz26353 tst-closefrom
 
 # Likewise for statx, but we do not need static linking here.
 tests-internal += tst-statx
diff --git a/io/Versions b/io/Versions
index 49c4d2d40a..fa33452881 100644
--- a/io/Versions
+++ b/io/Versions
@@ -135,6 +135,7 @@ libc {
   GLIBC_2.33 {
     stat; stat64; fstat; fstat64; lstat; lstat64; fstatat; fstatat64;
     mknod; mknodat;
+    closefrom;
   }
   GLIBC_PRIVATE {
     __libc_fcntl64;
diff --git a/io/closefrom.c b/io/closefrom.c
new file mode 100644
index 0000000000..be95ee40c8
--- /dev/null
+++ b/io/closefrom.c
@@ -0,0 +1,33 @@
+/* Close a range of file descriptors.
+   Copyright (C) 2020 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <unistd.h>
+
+void
+__closefrom (int lowfd)
+{
+  int maxfd = __getdtablesize ();
+  if (maxfd == -1)
+    __fortify_fail ("closefrom failed to get the file descriptor table size");
+
+  for (int i = 0; i < maxfd; i++)
+    if (i >= lowfd)
+      __close_nocancel_nostatus (i);
+}
+weak_alias (__closefrom, closefrom)
diff --git a/io/tst-closefrom.c b/io/tst-closefrom.c
new file mode 100644
index 0000000000..47b50b74b6
--- /dev/null
+++ b/io/tst-closefrom.c
@@ -0,0 +1,143 @@
+/* Smoke test for the closefrom.
+   Copyright (C) 2020 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+#include <support/check.h>
+#include <support/descriptors.h>
+#include <support/xunistd.h>
+
+#include <array_length.h>
+
+#define NFDS 100
+
+static int
+closefrom_test (void)
+{
+  struct support_descriptors *descrs = support_descriptors_list ();
+
+  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
+  for (int i = 0; i < NFDS; i++)
+    xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
+
+  const int maximum_fd = lowfd + NFDS;
+  const int half_fd = maximum_fd / 2;
+  const int gap = maximum_fd / 4;
+
+  /* Close half of the descriptors and check result.  */
+  closefrom (half_fd);
+
+  for (int i = half_fd; i <= maximum_fd; i++)
+    {
+      TEST_COMPARE (fcntl (i, F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  for (int i = 0; i < half_fd; i++)
+    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
+
+  /* Create some gaps, close up to a threshold, and check result.  */
+  xclose (35);
+  xclose (38);
+  xclose (42);
+  xclose (46);
+
+  /* Close half of the descriptors and check result.  */
+  closefrom (gap);
+  for (int i = gap + 1; i < maximum_fd; i++)
+    {
+      TEST_COMPARE (fcntl (i, F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  for (int i = 0; i < gap; i++)
+    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
+
+  /* Close the remmaining but the last one.  */
+  closefrom (lowfd + 1);
+  for (int i = lowfd + 1; i <= maximum_fd; i++)
+    {
+      TEST_COMPARE (fcntl (i, F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  TEST_VERIFY (fcntl (lowfd, F_GETFL) > -1);
+
+  /* Close the last one.  */
+  closefrom (lowfd);
+  TEST_COMPARE (fcntl (lowfd, F_GETFL), -1);
+  TEST_COMPARE (errno, EBADF);
+
+  /* Double check by check the /proc.  */
+  support_descriptors_check (descrs);
+  support_descriptors_free (descrs);
+
+  return 0;
+}
+
+/* Check if closefrom works even when no new file descriptors can be
+   created.  */
+static int
+closefrom_test_file_desc_limit (void)
+{
+  int max_fd = NFDS;
+  {
+    struct rlimit rl;
+    if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
+      FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
+
+    max_fd = (rl.rlim_cur < max_fd ? rl.rlim_cur : max_fd);
+    rl.rlim_cur = max_fd;
+
+    if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
+      FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
+  }
+
+  /* Exhauste the file descriptor limit.  */
+  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
+  for (;;)
+    {
+      int fd = open ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
+      if (fd == -1)
+	{
+	  if (errno != EMFILE)
+	    FAIL_EXIT1 ("create_temp_file: %m");
+	  break;
+	}
+    }
+
+  closefrom (lowfd);
+  for (int i = lowfd; i < NFDS; i++)
+    {
+      TEST_COMPARE (fcntl (i, F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+
+  return 0;
+}
+
+static int
+do_test (void)
+{
+  closefrom_test ();
+  closefrom_test_file_desc_limit ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/manual/llio.texi b/manual/llio.texi
index 018e7933de..d2cf7bbabd 100644
--- a/manual/llio.texi
+++ b/manual/llio.texi
@@ -314,6 +314,20 @@ is used.
 @end table
 @end deftypefun
 
+@deftypefun void closefrom (int @var{lowfd})
+@standards{GNU, unistd.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
+
+The function @code{closefrom} closes all file descriptors large or equal
+then @var{lowfd}.  This function is similar to call @code{close} in specified
+file descriptor range.
+
+@table @code
+@item EINVAL
+The @var{lowfd} value is larger than @var{maxfd} or an unsupported @var{flag}
+is used.
+@end table
+@end deftypefun
 
 @node I/O Primitives
 @section Input and Output Primitives
diff --git a/posix/unistd.h b/posix/unistd.h
index 32b8161619..652fed4616 100644
--- a/posix/unistd.h
+++ b/posix/unistd.h
@@ -352,6 +352,12 @@ extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence)
    __THROW.  */
 extern int close (int __fd);
 
+#ifdef __USE_GNU
+/* Close all open file descriptors greater than or equal to LOWFD.
+   Negative LOWFD is clamped to 0.  */
+extern void closefrom (int __lowfd) __THROW;
+#endif
+
 /* Read NBYTES into BUF from FD.  Return the
    number read, -1 for errors or 0 for EOF.
 
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index 7a5eb66b85..fce67cf3ca 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2191,6 +2191,7 @@ GLIBC_2.32 thrd_current F
 GLIBC_2.32 thrd_equal F
 GLIBC_2.32 thrd_sleep F
 GLIBC_2.32 thrd_yield F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index e06c2a1f0d..59ee6b5b5a 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -61,7 +61,7 @@ sysdep_routines += adjtimex clone umount umount2 readahead sysctl \
 		   open_by_handle_at mlock2 pkey_mprotect pkey_set pkey_get \
 		   timerfd_gettime timerfd_settime prctl \
 		   process_vm_readv process_vm_writev clock_adjtime \
-		   time64-support pselect32 close_range
+		   time64-support pselect32 close_range closefrom_fallback
 
 CFLAGS-gethostid.c = -fexceptions
 CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index a52decb822..811d3b3cd9 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2161,6 +2161,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index ed085c9b3c..d0bc011811 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2243,6 +2243,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 88a17c2fdf..c4e26b3cf6 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1921,6 +1921,7 @@ GLIBC_2.32 write F
 GLIBC_2.32 writev F
 GLIBC_2.32 wscanf F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 3b0a47e967..5ccd1fb07f 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -144,6 +144,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index a690962068..5043e483b8 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -142,6 +142,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/closefrom.c b/sysdeps/unix/sysv/linux/closefrom.c
new file mode 100644
index 0000000000..ba98fccd39
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/closefrom.c
@@ -0,0 +1,35 @@
+/* Close a range of file descriptors.  Linux version.
+   Copyright (C) 2020 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+void
+__closefrom (int lowfd)
+{
+  int l = MAX (0, lowfd);
+
+  int r = __close_range (l, ~0U, 0);
+  if (r == 0)
+    return;
+
+  if (!__closefrom_fallback (l))
+    __fortify_fail ("closefrom failed to close a file descriptor");
+}
+weak_alias (__closefrom, closefrom)
diff --git a/sysdeps/unix/sysv/linux/closefrom_fallback.c b/sysdeps/unix/sysv/linux/closefrom_fallback.c
new file mode 100644
index 0000000000..461582792d
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/closefrom_fallback.c
@@ -0,0 +1,88 @@
+/* Close a range of file descriptors.  Linux version.
+   Copyright (C) 2020 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <arch-fd_to_filename.h>
+#include <dirent.h>
+#include <not-cancel.h>
+#include <stdbool.h>
+
+/* Fallback code: iterates over /proc/self/fd, closing each file descriptor
+   that fall on the criteria.  */
+_Bool
+__closefrom_fallback (int from)
+{
+  bool ret = false;
+
+  int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY,
+			       0);
+  if (dirfd == -1)
+    {
+      /* The closefrom should work even when process can't open new files.
+	 In this case it loops over RLIMIT_NOFILE / rlim_cur until it frees
+	 a file descriptor to iterate over /proc.  */
+      if (errno != EMFILE)
+	goto err;
+
+      int maxfd = __getdtablesize ();
+      for (int i = from; i < maxfd; i++)
+	if (__close_nocancel (i) == 0)
+	  break;
+
+      dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY,
+			       0);
+      if (dirfd == -1)
+	goto err;
+    }
+
+  char buffer[1024];
+  while (true)
+    {
+      ssize_t ret = __getdents64 (dirfd, buffer, sizeof (buffer));
+      if (ret == -1)
+        goto err;
+      else if (ret == 0)
+        break;
+
+      char *begin = buffer, *end = buffer + ret;
+      while (begin != end)
+	{
+          unsigned short int d_reclen;
+	  memcpy (&d_reclen, begin + offsetof (struct dirent64, d_reclen),
+		  sizeof (d_reclen));
+	  const char *dname = begin + offsetof (struct dirent64, d_name);
+	  begin += d_reclen;
+
+	  if (dname[0] == '.')
+	    continue;
+
+	  int fd = 0;
+	  for (const char *s = dname; (unsigned int) (*s) - '0' < 10; s++)
+	    fd = 10 * fd + (*s - '0');
+
+	  if (fd == dirfd || fd < from)
+	    continue;
+
+	  __close_nocancel (fd);
+	}
+    }
+
+  ret = true;
+err:
+  __close_nocancel (dirfd);
+  return ret;
+}
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index d37882413c..6f3718cd14 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2105,6 +2105,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 61450e47d5..84b474dba4 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2064,6 +2064,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 672ff8a002..4c1399102e 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2230,6 +2230,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 53e53005e9..9fcaa40c34 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2096,6 +2096,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 25f2d1c08f..ccb780d9c7 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -145,6 +145,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index cc0d93b381..3afaa1c70e 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2176,6 +2176,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index b4acf52c41..266063d0e8 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2156,6 +2156,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 13d374a031..5d893ec4d1 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2152,6 +2152,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index fadbf99d4b..6207a15a09 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2147,6 +2147,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 4c786070d0..860e5fecfa 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2144,6 +2144,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index c456ebcea3..daed5ae2a8 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2153,6 +2153,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 5ed54e7c94..7b6edfe8f5 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2147,6 +2147,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 67b611ef6d..9dd7d64500 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2194,6 +2194,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index ed0f239cd5..c561e5cf36 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2203,6 +2203,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index f04b167788..d25bf75ed3 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2235,6 +2235,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index a4b9900036..248fab8212 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2066,6 +2066,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index e5d666dab3..d02fa6b3d2 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2356,6 +2356,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index f8c34aca7c..56d1a16b2a 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -597,6 +597,7 @@ GLIBC_2.33 clone F
 GLIBC_2.33 close F
 GLIBC_2.33 close_range F
 GLIBC_2.33 closedir F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 closelog F
 GLIBC_2.33 confstr F
 GLIBC_2.33 connect F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 6042d42aba..8fcd329728 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2123,6 +2123,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 46d2de3030..b06cc94710 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2201,6 +2201,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 9fda4babba..6ede1579ca 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2102,6 +2102,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 22ceaa3d87..0f426028a1 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2070,6 +2070,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 110f7ebf22..8637b683d6 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2068,6 +2068,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 1b31685a24..dc7c01f734 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2192,6 +2192,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 9ad88bf7b3..67d361c881 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2119,6 +2119,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 5089a21981..94bb5a0fa7 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2077,6 +2077,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index c3db0fc7ca..e94ce733ab 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2174,6 +2174,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
-- 
2.25.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v2 4/4] posix: Add posix_spawn_file_actions_closefrom
  2020-12-22 21:27 [PATCH 1/4] support: Add xclone Adhemerval Zanella
  2020-12-22 21:27 ` [PATCH v2 2/4] Linux: Add close_range Adhemerval Zanella
  2020-12-22 21:27 ` [PATCH v2 3/4] io: Add closefrom [BZ #10353] Adhemerval Zanella
@ 2020-12-22 21:27 ` Adhemerval Zanella
  2020-12-23 14:27   ` Florian Weimer
  2020-12-23 11:35 ` [PATCH 1/4] support: Add xclone Florian Weimer
  2020-12-23 12:20 ` Christian Brauner
  4 siblings, 1 reply; 15+ messages in thread
From: Adhemerval Zanella @ 2020-12-22 21:27 UTC (permalink / raw)
  To: libc-alpha; +Cc: Florian Weimer

Change from previous version [1]:

  - Return EINVAL for __posix_spawn_file_actions_addclosefrom fallback.
  - Fixed typos.
  - Remove posix/spawn_int_abi.h.
  - Remove array usage on posix/tst-spawn5.c test.

[1] https://patchwork.sourceware.org/project/glibc/patch/20201221215027.2176966-3-adhemerval.zanella@linaro.org/

--

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.

The posix_spawn is safe to be implemented by interacting over /proc/self/fd,
since the Linux spawni.c helper process does not use CLONE_FILES, so its has
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 [2] (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.

[1] https://docs.oracle.com/cd/E36784_01/html/E36874/posix-spawn-file-actions-addclosefrom-np-3c.html
[2] https://github.com/openjdk/jdk/blob/master/src/java.base/unix/native/libjava/childproc.c#L82
---
 NEWS                                          |   5 +
 posix/Makefile                                |   4 +-
 posix/Versions                                |   3 +
 posix/spawn.h                                 |   8 +
 posix/spawn_faction_addclosefrom.c            |  57 ++++
 posix/spawn_faction_destroy.c                 |   1 +
 posix/spawn_int.h                             |   6 +
 posix/tst-spawn5.c                            | 272 ++++++++++++++++++
 sysdeps/generic/spawn_int_abi.h               |  24 ++
 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/arc/libc.abilist      |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/arm/le/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 +
 .../sysv/linux/microblaze/be/libc.abilist     |   1 +
 .../sysv/linux/microblaze/le/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 +
 .../powerpc/powerpc32/nofpu/libc.abilist      |   1 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv32/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/be/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/sh/le/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              |  35 ++-
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
 46 files changed, 465 insertions(+), 16 deletions(-)
 create mode 100644 posix/spawn_faction_addclosefrom.c
 create mode 100644 posix/tst-spawn5.c
 create mode 100644 sysdeps/generic/spawn_int_abi.h
 create mode 100644 sysdeps/unix/sysv/linux/spawn_int_abi.h

diff --git a/NEWS b/NEWS
index e6446f0548..60a13edcbe 100644
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,11 @@ Major new features:
   greater than given integer.  This function is a GNU extension, although it
   also present in other systems.
 
+* The posix_spawn_file_actions_closefrom_np has been added, enabling
+  posix_spawn and posix_spawnp to close all file descriptors greater than
+  a giver integer.  This function is a GNU extension, although Solaris also
+  provides a similar function.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * The mallinfo function is marked deprecated.  Callers should call
diff --git a/posix/Makefile b/posix/Makefile
index 4bfc8d942c..d40636547e 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				      \
@@ -102,7 +103,7 @@ tests		:= test-errno tstgetopt testfnm runtests runptests \
 		   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 \
-		   tst-wordexp-nocmd
+		   tst-wordexp-nocmd 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
@@ -258,6 +259,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..95d7b01126 100644
--- a/posix/Versions
+++ b/posix/Versions
@@ -147,6 +147,9 @@ libc {
   }
   GLIBC_2.30 {
   }
+  GLIBC_2.33 {
+    posix_spawn_file_actions_addclosefrom_np;
+  }
   GLIBC_PRIVATE {
     __libc_fork; __libc_pread; __libc_pwrite;
     __nanosleep_nocancel; __pause_nocancel;
diff --git a/posix/spawn.h b/posix/spawn.h
index be6bd591a3..e81b4a4e90 100644
--- a/posix/spawn.h
+++ b/posix/spawn.h
@@ -213,6 +213,14 @@ 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..3b5e73fe32
--- /dev/null
+++ b/posix/spawn_faction_addclosefrom.c
@@ -0,0 +1,57 @@
+/* Add a closefrom to a file action list for posix_spawn.
+   Copyright (C) 2020 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 (!__spawn_valid_fd (from))
+    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
+  return EINVAL;
+#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 098385e1e0..33045e2c7f 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 9be54c0416..512dcea0da 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/tst-spawn5.c b/posix/tst-spawn5.c
new file mode 100644
index 0000000000..9bdabd2387
--- /dev/null
+++ b/posix/tst-spawn5.c
@@ -0,0 +1,272 @@
+/* Tests for posix_spawn signal handling.
+   Copyright (C) 2020 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 <arch-fd_to_filename.h>
+#include <array_length.h>
+
+/* Nonzero if the program gets called via `exec'.  */
+static int restart;
+
+/* Hold the four initial argument used to respawn the process.  */
+static char *initial_argv[7];
+
+#define CMDLINE_OPTIONS \
+  { "restart", no_argument, &restart, 1 },
+
+#define NFDS 100
+
+/* Called on process re-execution.  */
+_Noreturn static void
+handle_restart (int argc, char *argv[])
+{
+  size_t nfds = argc > 1 ? argc - 1 : 0;
+  struct fd_t
+  {
+    int fd;
+    _Bool found;
+  } *fds = xmalloc (sizeof (struct fd_t) * nfds);
+  for (int i = 0; i < nfds; i++)
+    {
+      char *endptr;
+      long int fd = strtol (argv[i+1], &endptr, 10);
+      if (*endptr != '\0' || fd < 0 || fd > INT_MAX)
+        FAIL_EXIT1 ("readdir: invalid file descriptor value: %s", argv[i]);
+      fds[i].fd = fd;
+      fds[i].found = false;
+    }
+
+  DIR *dirp = opendir (FD_TO_FILENAME_PREFIX);
+  if (dirp == NULL)
+    FAIL_EXIT1 ("opendir (\"" FD_TO_FILENAME_PREFIX "\"): %m");
+
+  while (true)
+    {
+      errno = 0;
+      struct dirent64 *e = readdir64 (dirp);
+      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 (dirp)
+          || fd == STDIN_FILENO
+	  || fd == STDOUT_FILENO
+	  || fd == STDERR_FILENO)
+        continue;
+
+      bool found = false;
+      for (int i = 0; i < nfds; i++)
+	if (fds[i].fd == fd)
+	  fds[i].found = found = true;
+
+      if (!found)
+        FAIL_EXIT1 ("unexpected open file descriptor: %ld", fd);
+    }
+  closedir (dirp);
+
+  for (int i = 0; i < nfds; i++)
+    if (!fds[i].found)
+      FAIL_EXIT1 ("file descriptor %d not closed", fds[i].fd);
+
+  free (fds);
+
+  exit (EXIT_SUCCESS);
+}
+
+static void
+spawn_closefrom_test (posix_spawn_file_actions_t *fa, int lowfd, int highfd,
+		      int *extrafds, size_t nextrafds)
+{
+  /* 6 elements from initial_argv (path to ld.so, '--library-path', the
+     path', application name', '--direct', and '--restart'), up to
+     2 * maximum_fd arguments (the expected open file descriptors), plus
+     NULL.  */
+  enum { argv_size = array_length (initial_argv) + 2 * NFDS + 1 };
+  char *args[argv_size];
+  int argc = 0;
+
+  for (char **arg = initial_argv; *arg != NULL; arg++)
+    args[argc++] = *arg;
+
+  for (int i = lowfd; i < highfd; i++)
+    args[argc++] = xasprintf ("%d", i);
+
+  for (int i = 0; i < nextrafds; i++)
+    args[argc++] = xasprintf ("%d", extrafds[i]);
+
+  args[argc] = NULL;
+  TEST_VERIFY (argc < argv_size);
+
+  pid_t pid;
+  int status;
+
+  TEST_COMPARE (posix_spawn (&pid, args[0], fa, NULL, args, 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 (void)
+{
+  int lowfd = xopen ("/dev/null", O_WRONLY, 0);
+  for (int i = 1; i < NFDS; i++)
+    xopen ("/dev/null", O_WRONLY, 0);
+  const int half_fd = lowfd + NFDS / 2;
+
+  /* Close half of the descriptors and check result.  */
+  {
+    posix_spawn_file_actions_t fa;
+    TEST_COMPARE (posix_spawn_file_actions_init (&fa), 0);
+
+    int ret = posix_spawn_file_actions_addclosefrom_np (&fa, half_fd);
+    if (ret == EINVAL)
+      /* Hurd currently does not support closefrom fileaction.  */
+      FAIL_UNSUPPORTED ("posix_spawn_file_actions_addclosefrom_np unsupported");
+    TEST_COMPARE (ret, 0);
+
+    spawn_closefrom_test (&fa, lowfd, half_fd, NULL, 0);
+
+    TEST_COMPARE (posix_spawn_file_actions_destroy (&fa), 0);
+  }
+
+  /* Create some gaps, close up to a threshold, and check result.  */
+  xclose (57);
+  xclose (78);
+  xclose (81);
+  xclose (82);
+  xclose (84);
+  xclose (90);
+
+  {
+    posix_spawn_file_actions_t fa;
+    TEST_COMPARE (posix_spawn_file_actions_init (&fa), 0);
+
+    TEST_COMPARE (posix_spawn_file_actions_addclosefrom_np (&fa, half_fd), 0);
+
+    spawn_closefrom_test (&fa, lowfd, half_fd, NULL, 0);
+
+    TEST_COMPARE (posix_spawn_file_actions_destroy (&fa), 0);
+  }
+
+  /* Close the remaining but the last one.  */
+  {
+    posix_spawn_file_actions_t fa;
+    TEST_COMPARE (posix_spawn_file_actions_init (&fa), 0);
+
+    TEST_COMPARE (posix_spawn_file_actions_addclosefrom_np (&fa, lowfd + 1), 0);
+
+    spawn_closefrom_test (&fa, lowfd, lowfd + 1, NULL, 0);
+
+    TEST_COMPARE (posix_spawn_file_actions_destroy (&fa), 0);
+  }
+
+  /* Close everything.  */
+  {
+    posix_spawn_file_actions_t fa;
+    TEST_COMPARE (posix_spawn_file_actions_init (&fa), 0);
+
+    TEST_COMPARE (posix_spawn_file_actions_addclosefrom_np (&fa, lowfd), 0);
+
+    spawn_closefrom_test (&fa, lowfd, lowfd, NULL, 0);
+
+    TEST_COMPARE (posix_spawn_file_actions_destroy (&fa), 0);
+  }
+
+  /* Close a range and add some file actions.  */
+  {
+    posix_spawn_file_actions_t fa;
+    TEST_COMPARE (posix_spawn_file_actions_init (&fa), 0);
+
+    TEST_COMPARE (posix_spawn_file_actions_addclosefrom_np (&fa, lowfd + 1), 0);
+    TEST_COMPARE (posix_spawn_file_actions_addopen (&fa, lowfd, "/dev/null",
+						    0666, O_RDONLY), 0);
+    TEST_COMPARE (posix_spawn_file_actions_adddup2 (&fa, lowfd, lowfd + 1), 0);
+    TEST_COMPARE (posix_spawn_file_actions_addopen (&fa, lowfd, "/dev/null",
+						    0666, O_RDONLY), 0);
+
+    spawn_closefrom_test (&fa, lowfd, lowfd, (int[]){lowfd, lowfd + 1}, 2);
+
+    TEST_COMPARE (posix_spawn_file_actions_destroy (&fa), 0);
+  }
+}
+
+static int
+do_test (int argc, char *argv[])
+{
+  /* We must have either:
+
+     - one or four parameters if called initially:
+       + argv[1]: path for ld.so        optional
+       + argv[2]: "--library-path"      optional
+       + argv[3]: the library path      optional
+       + argv[4]: the application name
+
+     - six parameters left if called through re-execution:
+       + argv[1]: the application name
+       + argv[2]: first expected open file descriptor
+       + argv[n]: last expected open file descritptor
+
+     * When built with --enable-hardcoded-path-in-tests or issued without
+       using the loader directly.  */
+
+  if (restart)
+    handle_restart (argc, argv);
+
+  initial_argv[0] = argv[1]; /* path for ld.so  */
+  initial_argv[1] = argv[2]; /* "--library-path"  */
+  initial_argv[2] = argv[3]; /* the library path  */
+  initial_argv[3] = argv[4]; /* the application name  */
+  initial_argv[4] = (char *) "--direct";
+  initial_argv[5] = (char *) "--restart";
+
+  do_test_closefrom ();
+
+  return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/sysdeps/generic/spawn_int_abi.h b/sysdeps/generic/spawn_int_abi.h
new file mode 100644
index 0000000000..bfc8961598
--- /dev/null
+++ b/sysdeps/generic/spawn_int_abi.h
@@ -0,0 +1,24 @@
+/* Internal ABI specific for posix_spawn functionality.  Generic version.
+   Copyright (C) 2020 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
+
+#define __SPAWN_SUPPORT_CLOSEFROM 0
+
+#endif /* _SPAWN_INT_H */
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index fce67cf3ca..5b23d62b5d 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2201,6 +2201,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/mach/hurd/spawni.c b/sysdeps/mach/hurd/spawni.c
index 178b271e4e..9ea4fc972f 100644
--- a/sysdeps/mach/hurd/spawni.c
+++ b/sysdeps/mach/hurd/spawni.c
@@ -600,6 +600,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 943a598771..d05d2c8520 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 811d3b3cd9..65d5c3cee4 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2171,5 +2171,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index d0bc011811..ac55ceba70 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2253,6 +2253,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index c4e26b3cf6..24e623875d 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1931,5 +1931,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 5ccd1fb07f..50086104ea 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -154,6 +154,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 _Exit F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 5043e483b8..a4ebfccc74 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -152,6 +152,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 6f3718cd14..4b45f0a8a0 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2115,5 +2115,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 84b474dba4..b574604263 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2074,6 +2074,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 4c1399102e..51795cd925 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2240,6 +2240,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 9fcaa40c34..bafbc98f69 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2106,6 +2106,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 ccb780d9c7..8c3fc11399 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -155,6 +155,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 3afaa1c70e..10a11773f2 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2186,6 +2186,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 266063d0e8..e908a7a19a 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2166,5 +2166,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 5d893ec4d1..d8f3ff6dec 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2162,5 +2162,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 6207a15a09..1c41ce7c83 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2157,6 +2157,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 860e5fecfa..dcec226837 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2154,6 +2154,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 daed5ae2a8..022a7ec721 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2163,6 +2163,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 7b6edfe8f5..a312612703 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2157,6 +2157,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 9dd7d64500..d4e4096a11 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2204,5 +2204,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index c561e5cf36..01705658c0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2213,6 +2213,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index d25bf75ed3..eea881eeae 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2245,6 +2245,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 248fab8212..bb346370ad 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2076,6 +2076,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 d02fa6b3d2..0dad53bc80 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2366,5 +2366,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 56d1a16b2a..7ee1f2e189 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -1304,6 +1304,7 @@ GLIBC_2.33 posix_openpt F
 GLIBC_2.33 posix_spawn F
 GLIBC_2.33 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.33 posix_spawn_file_actions_addclose F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 posix_spawn_file_actions_adddup2 F
 GLIBC_2.33 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.33 posix_spawn_file_actions_addopen F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 8fcd329728..51fc25677d 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2133,5 +2133,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index b06cc94710..61bda38fb0 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2211,6 +2211,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 6ede1579ca..a73bc16ae0 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2112,6 +2112,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 0f426028a1..974090f39b 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2080,6 +2080,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 8637b683d6..910c8e752d 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2078,6 +2078,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 dc7c01f734..fabbdaeef0 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2202,6 +2202,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 67d361c881..0ad7f0b18c 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2129,6 +2129,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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..84b31104c5
--- /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) 2020 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 f157bfffd2..c337c7a6a1 100644
--- a/sysdeps/unix/sysv/linux/spawni.c
+++ b/sysdeps/unix/sysv/linux/spawni.c
@@ -16,22 +16,17 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <spawn.h>
-#include <fcntl.h>
-#include <paths.h>
-#include <string.h>
-#include <sys/resource.h>
-#include <sys/wait.h>
-#include <sys/param.h>
-#include <sys/mman.h>
-#include <not-cancel.h>
+#include <arch-fd_to_filename.h>
+#include <internal-signals.h>
+#include <ldsodefs.h>
 #include <local-setxid.h>
+#include <not-cancel.h>
+#include <paths.h>
 #include <shlib-compat.h>
-#include <nptl/pthreadP.h>
-#include <dl-sysdep.h>
-#include <libc-pointer-arith.h>
-#include <ldsodefs.h>
-#include "spawn_int.h"
+#include <spawn.h>
+#include <spawn_int.h>
+#include <sysdep.h>
+#include <sys/resource.h>
 
 /* The Linux implementation of posix_spawn{p} uses the clone syscall directly
    with CLONE_VM and CLONE_VFORK flags and an allocated stack.  The new stack
@@ -280,6 +275,14 @@ __spawni_child (void *arguments)
 	      if (__fchdir (action->action.fchdir_action.fd) != 0)
 		goto fail;
 	      break;
+
+	    case spawn_do_closefrom:
+	      {
+		int lowfd = action->action.closefrom_action.from;
+	        int r = INLINE_SYSCALL_CALL (close_range, lowfd, ~0U, 0);
+		if (r != 0 && !__closefrom_fallback (lowfd))
+		  goto fail;
+	      } break;
 	    }
 	}
     }
@@ -344,7 +347,9 @@ __spawnix (pid_t * pid, const char *file,
   /* 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 94bb5a0fa7..c17d5d93c3 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2087,6 +2087,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 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 e94ce733ab..e8ff4b7cc9 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2184,5 +2184,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
-- 
2.25.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/4] support: Add xclone
  2020-12-22 21:27 [PATCH 1/4] support: Add xclone Adhemerval Zanella
                   ` (2 preceding siblings ...)
  2020-12-22 21:27 ` [PATCH v2 4/4] posix: Add posix_spawn_file_actions_closefrom Adhemerval Zanella
@ 2020-12-23 11:35 ` Florian Weimer
  2020-12-23 13:13   ` Adhemerval Zanella
  2020-12-23 12:20 ` Christian Brauner
  4 siblings, 1 reply; 15+ messages in thread
From: Florian Weimer @ 2020-12-23 11:35 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

* Adhemerval Zanella:

> diff --git a/support/xclone.c b/support/xclone.c
> new file mode 100644
> index 0000000000..e7efffb82b
> --- /dev/null
> +++ b/support/xclone.c
> @@ -0,0 +1,46 @@
> +/* Auxiliary wrapper to issue the clone symbol.

Same wording issue as before.

> +   Copyright (C) 2020 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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <stackinfo.h>  /* For _STACK_GROWS_{UP,DOWN}.  */
> +#include <xsched.h>
> +
> +pid_t
> +xclone (int (*fn) (void *arg), void *arg, void *stack, size_t stack_size,
> +	int flags)
> +{
> +  pid_t r = -1;
> +
> +#ifdef __linux__
> +# ifdef __ia64__
> +  extern int __clone2 (int (*fn) (void *arg), void *stack, size_t stack_size,
> +		       int flags, void *arg, ...);
> +  r = __clone2 (f, stack, stack_size, flags, arg, /* ptid */ NULL,
> +		/* tls */ NULL, /* ctid  */ ctid);
> +# else
> +#  if _STACK_GROWS_DOWN
> +  r = clone (fn, stack + stack_size, flags, arg, /* ptid */ NULL,
> +	     /* tls */ NULL, /* ctid */  NULL);
> +#  elif _STACK_GROWS_UP
> +  r = clone (fn, stack, flags, arg, /* ptid */ NULL, /* tls */ NULL,
> +	     &ctid);
> +#  endif
> +# endif
> +#endif
> +
> +  return r;
> +}

Maybe #ifdef CLONE_VM instead of #ifdef __linux__?  And around the whole
function definition?

Then you can check for an error return from the system call, too, to
match the x* function pattern.

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/4] support: Add xclone
  2020-12-22 21:27 [PATCH 1/4] support: Add xclone Adhemerval Zanella
                   ` (3 preceding siblings ...)
  2020-12-23 11:35 ` [PATCH 1/4] support: Add xclone Florian Weimer
@ 2020-12-23 12:20 ` Christian Brauner
  2020-12-23 13:05   ` Adhemerval Zanella
  4 siblings, 1 reply; 15+ messages in thread
From: Christian Brauner @ 2020-12-23 12:20 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha, Florian Weimer

On Tue, Dec 22, 2020 at 06:27:51PM -0300, Adhemerval Zanella via Libc-alpha wrote:
> It is a wrapper for Linux close syscall, to simplify the call to the

s/close/clone/?

> use only the most common arguments and remove architecture specific
> handling (such as ia64 different name and signature).
> ---
>  support/Makefile |  1 +
>  support/xclone.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
>  support/xsched.h | 36 ++++++++++++++++++++++++++++++++++++
>  3 files changed, 83 insertions(+)
>  create mode 100644 support/xclone.c
>  create mode 100644 support/xsched.h
> 
> diff --git a/support/Makefile b/support/Makefile
> index 3198eb5022..aecd27316e 100644
> --- a/support/Makefile
> +++ b/support/Makefile
> @@ -89,6 +89,7 @@ libsupport-routines = \
>    xcalloc \
>    xchroot \
>    xclock_gettime \
> +  xclone \
>    xclose \
>    xconnect \
>    xcopy_file_range \
> diff --git a/support/xclone.c b/support/xclone.c
> new file mode 100644
> index 0000000000..e7efffb82b
> --- /dev/null
> +++ b/support/xclone.c
> @@ -0,0 +1,46 @@
> +/* Auxiliary wrapper to issue the clone symbol.
> +   Copyright (C) 2020 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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <stackinfo.h>  /* For _STACK_GROWS_{UP,DOWN}.  */
> +#include <xsched.h>
> +
> +pid_t
> +xclone (int (*fn) (void *arg), void *arg, void *stack, size_t stack_size,
> +	int flags)
> +{
> +  pid_t r = -1;
> +
> +#ifdef __linux__
> +# ifdef __ia64__
> +  extern int __clone2 (int (*fn) (void *arg), void *stack, size_t stack_size,
> +		       int flags, void *arg, ...);
> +  r = __clone2 (f, stack, stack_size, flags, arg, /* ptid */ NULL,
> +		/* tls */ NULL, /* ctid  */ ctid);
> +# else
> +#  if _STACK_GROWS_DOWN
> +  r = clone (fn, stack + stack_size, flags, arg, /* ptid */ NULL,
> +	     /* tls */ NULL, /* ctid */  NULL);
> +#  elif _STACK_GROWS_UP
> +  r = clone (fn, stack, flags, arg, /* ptid */ NULL, /* tls */ NULL,
> +	     &ctid);
> +#  endif
> +# endif
> +#endif
> +
> +  return r;
> +}
> diff --git a/support/xsched.h b/support/xsched.h
> new file mode 100644
> index 0000000000..8523f03f82
> --- /dev/null
> +++ b/support/xsched.h
> @@ -0,0 +1,36 @@
> +/* Wrapper for sched.h functions.
> +   Copyright (C) 2020 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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef SUPPORT_XSCHED_H
> +#define SUPPORT_XSCHED_H
> +
> +__BEGIN_DECLS
> +
> +#include <sched.h>
> +#include <sys/types.h>
> +
> +#define DEFINE_STACK(name, size) \
> +  char name[size] __attribute__ ((aligned))
> +
> +pid_t
> +xclone (int (*fn) (void *arg), void *arg, void *stack, size_t stack_size,
> +	int flags);
> +
> +__END_DECLS
> +
> +#endif
> -- 
> 2.25.1
> 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/4] Linux: Add close_range
  2020-12-22 21:27 ` [PATCH v2 2/4] Linux: Add close_range Adhemerval Zanella
@ 2020-12-23 12:22   ` Florian Weimer
  2020-12-23 14:07     ` Adhemerval Zanella
  0 siblings, 1 reply; 15+ messages in thread
From: Florian Weimer @ 2020-12-23 12:22 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

* Adhemerval Zanella:

> diff --git a/manual/llio.texi b/manual/llio.texi
> index c0a53e1a6e..018e7933de 100644
> --- a/manual/llio.texi
> +++ b/manual/llio.texi
> @@ -284,6 +284,37 @@ of trying to close its underlying file descriptor with @code{close}.
>  This flushes any buffered output and updates the stream object to
>  indicate that it is closed.
>  
> +@deftypefun int close_range (unsigned int @var{lowfd}, unsigned int @var{maxfd}, int @var{flags})
> +@standards{Linux, unistd.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
> +@c This is a syscall for Linux v5.9.  There is no fallback emultation for
> +@c older kernels.

Typo: “emultation”

> +The function @code{clode_range} closes the file descriptor from @var{lowfd}
> +to @var{maxfd} (included).  This function is similar to call @code{close} in

“(inclusive)”?

> +specified file descriptor range.

Maybe add, “depending on the flags”?  With the new CLOEXEC variant, the
system call does not close anything, after all.

> +The @var{flags} add options on how the files are closes.  Linux currently
> +supports.

“supports:” (with colon)

> +@vtable @code
> +@item CLOSE_RANGE_UNSHARE
> +It unshare the range of file descriptors from any other processes, instead
> +of closing them.
> +@end vtable

“The function call unshares the range”.

Is this really how CLOSE_RANGE_UNSHARE operates?  I think the
implementation falls through to the closing operation after unsharing
the descriptor table, so it still closes the descriptors.

> +
> +The normal return value from @code{close} is @math{0}; a value of @math{-1}

“close” should be ”close_range”.

> +is returned in case of failure.  The following @code{errno} error
> +conditions are defined for this function:
> +
> +@table @code
> +@item EINVAL
> +The @var{lowfd} value is larger than @var{maxfd} or an unsupported @var{flag}
> +is used.
> +@end table
> +@end deftypefun

Typo: “@var{flag}” (missing s)

Other error codes with CLOSE_RANGE_UNSHARE: ENOMEM, EMFILE (see dup_fd).
Maybe a few more.

> diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list
> index 01ec2bfa95..53575669c7 100644
> --- a/sysdeps/unix/sysv/linux/syscalls.list
> +++ b/sysdeps/unix/sysv/linux/syscalls.list
> @@ -101,3 +101,4 @@ pkey_alloc	EXTRA	pkey_alloc	i:ii	pkey_alloc
>  pkey_free	EXTRA	pkey_free	i:i	pkey_free
>  gettid          EXTRA   gettid          Ei:     __gettid	gettid
>  tgkill          EXTRA   tgkill          i:iii   __tgkill	tgkill
> +close_range     EXTRA   close_range     i:iii   __close_range   close_range

Hmm, I'm trying to wrap around if this is correct for x32.  But since
the kernel uses unsigned int, I think it is.

> diff --git a/sysdeps/unix/sysv/linux/tst-close_range.c b/sysdeps/unix/sysv/linux/tst-close_range.c
> new file mode 100644
> index 0000000000..1a127bb9cb
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-close_range.c
> @@ -0,0 +1,198 @@

> +#include <dirent.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <limits.h>
> +#include <getopt.h>
> +#include <signal.h>
> +#include <stdbool.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +
> +#include <array_length.h>
> +#include <support/capture_subprocess.h>
> +#include <support/check.h>
> +#include <support/descriptors.h>
> +#include <support/support.h>
> +#include <support/xsched.h>
> +#include <support/xunistd.h>
> +
> +#define NFDS 100
> +
> +static void
> +close_range_test_common (int lowfd, unsigned int flags)
> +{
> +  const int maximum_fd = lowfd + NFDS;
> +  const int half_fd = maximum_fd / 2;
> +  const int gap_1 = maximum_fd - 8;
> +
> +  /* Close half of the descriptors and check result.  */
> +  {
> +    int r = close_range (lowfd, half_fd, flags);
> +    if (r == -1 && errno == ENOSYS)
> +      FAIL_UNSUPPORTED ("close_range not supported");
> +    TEST_COMPARE (r, 0);
> +  }
> +  for (int i = lowfd; i <= half_fd; i++)
> +    {
> +      TEST_COMPARE (fcntl (i, F_GETFL), -1);
> +      TEST_COMPARE (errno, EBADF);
> +    }
> +  for (int i = half_fd + 1; i < maximum_fd; i++)
> +    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
> +
> +  /* Create some gaps, close up to a threshold, and check result.  */
> +  xclose (57);
> +  xclose (78);
> +  xclose (81);
> +  xclose (82);
> +  xclose (84);
> +  xclose (90);

Should be lowfd + 57 etc.

> +  TEST_COMPARE (close_range (half_fd + 1, gap_1, flags), 0);
> +  for (int i = half_fd + 1; i < gap_1; i++)
> +    {
> +      TEST_COMPARE (fcntl (i, F_GETFL), -1);
> +      TEST_COMPARE (errno, EBADF);
> +    }
> +  for (int i = gap_1 + 1; i < maximum_fd; i++)
> +    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
> +
> +  /* Close the remmaining but the last one.  */

Typo: “remmaining”

> +  TEST_COMPARE (close_range (gap_1 + 1, maximum_fd - 1, flags), 0);
> +  for (int i = gap_1 + 1; i < maximum_fd - 1; i++)
> +    {
> +      TEST_COMPARE (fcntl (i, F_GETFL), -1);
> +      TEST_COMPARE (errno, EBADF);
> +    }
> +  TEST_VERIFY (fcntl (maximum_fd, F_GETFL) > -1);
> +
> +  /* Close the last one.  */
> +  TEST_COMPARE (close_range (maximum_fd, maximum_fd, flags), 0);
> +  TEST_COMPARE (fcntl (maximum_fd, F_GETFL), -1);
> +  TEST_COMPARE (errno, EBADF);
> +}
> +
> +/* Basic tests: check if the syscall close ranges with and without gaps.  */
> +static void
> +__attribute__((used))

Why __attribute__ ((used))?  (Also elsewhere in the file.)

> +close_range_test (void)
> +{
> +  struct support_descriptors *descrs = support_descriptors_list ();
> +
> +  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
> +  for (int i = 0; i < NFDS; i++)
> +    xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);

Please add a check that there are no gaps.  And this opens NFDS + 1
descriptors, so maybe add a comment to NFDS.

So perhaps this:

  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
  for (int i = 1; i <= NFDS; i++)
    TEST_COMPARE (xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600),
                  lowfd + i);

> +/* Check if a clone_range on a subprocess created with CLONE_FILES close
> +   the shared file descriptor table entries in the parent.  */
> +static void
> +__attribute__((used))
> +close_range_test_subprocess (void)
> +{
> +  struct support_descriptors *descrs = support_descriptors_list ();
> +
> +  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
> +  for (int i = 0; i < NFDS; i++)
> +    xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);

See above, maybe factor this out in a separate function?

> +_Noreturn static int
> +close_range_unshare_test_fn (void *arg)
> +{
> +  int lowfd = (int) ((uintptr_t) arg);
> +  close_range_test_common (lowfd, CLOSE_RANGE_UNSHARE);
> +  exit (EXIT_SUCCESS);
> +}

I think you could check here against the original descriptor set, to
ensure that CLOSE_RANGE_UNSHARE still closes everything.

> +
> +/* Check if a close_range with CLOSE_RANGE_UNSHARE issued from a subprocess
> +   created with CLONE_FILES does not close the parent file descriptor list.  */
> +static void
> +__attribute__((used))
> +close_range_unshare_test (void)
> +{

(Create another descriptor list here.)

> +  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
> +  for (int i = 0; i < NFDS; i++)
> +    xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);

Shared function?

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/4] support: Add xclone
  2020-12-23 12:20 ` Christian Brauner
@ 2020-12-23 13:05   ` Adhemerval Zanella
  0 siblings, 0 replies; 15+ messages in thread
From: Adhemerval Zanella @ 2020-12-23 13:05 UTC (permalink / raw)
  To: Christian Brauner; +Cc: libc-alpha, Florian Weimer



On 23/12/2020 09:20, Christian Brauner wrote:
> On Tue, Dec 22, 2020 at 06:27:51PM -0300, Adhemerval Zanella via Libc-alpha wrote:
>> It is a wrapper for Linux close syscall, to simplify the call to the
> 
> s/close/clone/?

Ack.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/4] support: Add xclone
  2020-12-23 11:35 ` [PATCH 1/4] support: Add xclone Florian Weimer
@ 2020-12-23 13:13   ` Adhemerval Zanella
  0 siblings, 0 replies; 15+ messages in thread
From: Adhemerval Zanella @ 2020-12-23 13:13 UTC (permalink / raw)
  To: Florian Weimer; +Cc: libc-alpha



On 23/12/2020 08:35, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>> diff --git a/support/xclone.c b/support/xclone.c
>> new file mode 100644
>> index 0000000000..e7efffb82b
>> --- /dev/null
>> +++ b/support/xclone.c
>> @@ -0,0 +1,46 @@
>> +/* Auxiliary wrapper to issue the clone symbol.
> 
> Same wording issue as before.

Ack, I forgot to adjust the new file as well.

> 
>> +   Copyright (C) 2020 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
>> +   <https://www.gnu.org/licenses/>.  */
>> +
>> +#include <stackinfo.h>  /* For _STACK_GROWS_{UP,DOWN}.  */
>> +#include <xsched.h>
>> +
>> +pid_t
>> +xclone (int (*fn) (void *arg), void *arg, void *stack, size_t stack_size,
>> +	int flags)
>> +{
>> +  pid_t r = -1;
>> +
>> +#ifdef __linux__
>> +# ifdef __ia64__
>> +  extern int __clone2 (int (*fn) (void *arg), void *stack, size_t stack_size,
>> +		       int flags, void *arg, ...);
>> +  r = __clone2 (f, stack, stack_size, flags, arg, /* ptid */ NULL,
>> +		/* tls */ NULL, /* ctid  */ ctid);
>> +# else
>> +#  if _STACK_GROWS_DOWN
>> +  r = clone (fn, stack + stack_size, flags, arg, /* ptid */ NULL,
>> +	     /* tls */ NULL, /* ctid */  NULL);
>> +#  elif _STACK_GROWS_UP
>> +  r = clone (fn, stack, flags, arg, /* ptid */ NULL, /* tls */ NULL,
>> +	     &ctid);
>> +#  endif
>> +# endif
>> +#endif
>> +
>> +  return r;
>> +}
> 
> Maybe #ifdef CLONE_VM instead of #ifdef __linux__?  And around the whole
> function definition?

The __linux__ is already use on other support implementations, so I think
it would be ok to specific this is system specific wrapper.

For function support, maybe not providing for no Linux build would be
better indeed (the tests will fail to build instead of fail at runtime). 

> 
> Then you can check for an error return from the system call, too, to
> match the x* function pattern.

Ack.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 3/4] io: Add closefrom [BZ #10353]
  2020-12-22 21:27 ` [PATCH v2 3/4] io: Add closefrom [BZ #10353] Adhemerval Zanella
@ 2020-12-23 13:28   ` Florian Weimer
  2020-12-23 14:51     ` Adhemerval Zanella
  0 siblings, 1 reply; 15+ messages in thread
From: Florian Weimer @ 2020-12-23 13:28 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

* Adhemerval Zanella:

> The symbol closes all open file descriptors greater than or equal to
> input argument.  Negative values are campled to 0, i.e, it will close
> all file descriptors.

“The function”?

Typo: “campled”.

> diff --git a/io/tst-closefrom.c b/io/tst-closefrom.c
> new file mode 100644
> index 0000000000..47b50b74b6
> --- /dev/null
> +++ b/io/tst-closefrom.c

> +#define NFDS 100
> +
> +static int
> +closefrom_test (void)
> +{
> +  struct support_descriptors *descrs = support_descriptors_list ();
> +
> +  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
> +  for (int i = 0; i < NFDS; i++)
> +    xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);

See the previous comments about checking for contiguous allocation and
the meaning of NFDS.

> +  const int maximum_fd = lowfd + NFDS;
> +  const int half_fd = maximum_fd / 2;
> +  const int gap = maximum_fd / 4;
> +
> +  /* Close half of the descriptors and check result.  */
> +  closefrom (half_fd);
> +
> +  for (int i = half_fd; i <= maximum_fd; i++)
> +    {
> +      TEST_COMPARE (fcntl (i, F_GETFL), -1);
> +      TEST_COMPARE (errno, EBADF);
> +    }
> +  for (int i = 0; i < half_fd; i++)
> +    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
> +
> +  /* Create some gaps, close up to a threshold, and check result.  */
> +  xclose (35);
> +  xclose (38);
> +  xclose (42);
> +  xclose (46);

lowfd + 35 etc., please.

> +/* Check if closefrom works even when no new file descriptors can be
> +   created.  */
> +static int
> +closefrom_test_file_desc_limit (void)
> +{
> +  int max_fd = NFDS;
> +  {
> +    struct rlimit rl;
> +    if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
> +      FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
> +
> +    max_fd = (rl.rlim_cur < max_fd ? rl.rlim_cur : max_fd);
> +    rl.rlim_cur = max_fd;
> +
> +    if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
> +      FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
> +  }
> +
> +  /* Exhauste the file descriptor limit.  */
> +  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
> +  for (;;)
> +    {
> +      int fd = open ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
> +      if (fd == -1)
> +	{
> +	  if (errno != EMFILE)
> +	    FAIL_EXIT1 ("create_temp_file: %m");
> +	  break;
> +	}
> +    }
> +
> +  closefrom (lowfd);
> +  for (int i = lowfd; i < NFDS; i++)
> +    {
> +      TEST_COMPARE (fcntl (i, F_GETFL), -1);
> +      TEST_COMPARE (errno, EBADF);
> +    }
> +
> +  return 0;
> +}

Good test, thanks.

> diff --git a/manual/llio.texi b/manual/llio.texi
> index 018e7933de..d2cf7bbabd 100644
> --- a/manual/llio.texi
> +++ b/manual/llio.texi
> @@ -314,6 +314,20 @@ is used.
>  @end table
>  @end deftypefun
>  
> +@deftypefun void closefrom (int @var{lowfd})
> +@standards{GNU, unistd.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
> +
> +The function @code{closefrom} closes all file descriptors large or equal
> +then @var{lowfd}.  This function is similar to call @code{close} in specified
> +file descriptor range.
> +
> +@table @code
> +@item EINVAL
> +The @var{lowfd} value is larger than @var{maxfd} or an unsupported @var{flag}
> +is used.
> +@end table
> +@end deftypefun

I think this function cannot fail.

>  @node I/O Primitives
>  @section Input and Output Primitives
> diff --git a/posix/unistd.h b/posix/unistd.h
> index 32b8161619..652fed4616 100644
> --- a/posix/unistd.h
> +++ b/posix/unistd.h
> @@ -352,6 +352,12 @@ extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence)
>     __THROW.  */
>  extern int close (int __fd);
>  
> +#ifdef __USE_GNU
> +/* Close all open file descriptors greater than or equal to LOWFD.
> +   Negative LOWFD is clamped to 0.  */
> +extern void closefrom (int __lowfd) __THROW;
> +#endif

__USE_MISC instead of GNU?  Given that this is so widely implemented.

> diff --git a/sysdeps/unix/sysv/linux/closefrom_fallback.c b/sysdeps/unix/sysv/linux/closefrom_fallback.c
> new file mode 100644
> index 0000000000..461582792d
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/closefrom_fallback.c

> +/* Fallback code: iterates over /proc/self/fd, closing each file descriptor
> +   that fall on the criteria.  */
> +_Bool
> +__closefrom_fallback (int from)
> +{
> +  bool ret = false;
> +
> +  int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY,
> +			       0);
> +  if (dirfd == -1)
> +    {
> +      /* The closefrom should work even when process can't open new files.
> +	 In this case it loops over RLIMIT_NOFILE / rlim_cur until it frees
> +	 a file descriptor to iterate over /proc.  */
> +      if (errno != EMFILE)
> +	goto err;

As explained, this should be errno == ENOENT.  There are a few more
calls that could take the shortcut, but I don't think they can occur in
practice.

> +  char buffer[1024];
> +  while (true)
> +    {
> +      ssize_t ret = __getdents64 (dirfd, buffer, sizeof (buffer));
> +      if (ret == -1)
> +        goto err;
> +      else if (ret == 0)
> +        break;
> +
> +      char *begin = buffer, *end = buffer + ret;
> +      while (begin != end)
> +	{
> +          unsigned short int d_reclen;
> +	  memcpy (&d_reclen, begin + offsetof (struct dirent64, d_reclen),
> +		  sizeof (d_reclen));
> +	  const char *dname = begin + offsetof (struct dirent64, d_name);
> +	  begin += d_reclen;
> +
> +	  if (dname[0] == '.')
> +	    continue;
> +
> +	  int fd = 0;
> +	  for (const char *s = dname; (unsigned int) (*s) - '0' < 10; s++)
> +	    fd = 10 * fd + (*s - '0');
> +
> +	  if (fd == dirfd || fd < from)
> +	    continue;
> +
> +	  __close_nocancel (fd);
> +	}
> +    }

Do you object to the idea of the rewind?  The implementation above
encodes very specific /proc/self/fd behavior.

With containers and seccomp filters, we can't assume that a future
behavioral change will not matter because we have close_range.

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/4] Linux: Add close_range
  2020-12-23 12:22   ` Florian Weimer
@ 2020-12-23 14:07     ` Adhemerval Zanella
  2020-12-23 14:17       ` Florian Weimer
  0 siblings, 1 reply; 15+ messages in thread
From: Adhemerval Zanella @ 2020-12-23 14:07 UTC (permalink / raw)
  To: Florian Weimer; +Cc: libc-alpha



On 23/12/2020 09:22, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>> diff --git a/manual/llio.texi b/manual/llio.texi
>> index c0a53e1a6e..018e7933de 100644
>> --- a/manual/llio.texi
>> +++ b/manual/llio.texi
>> @@ -284,6 +284,37 @@ of trying to close its underlying file descriptor with @code{close}.
>>  This flushes any buffered output and updates the stream object to
>>  indicate that it is closed.
>>  
>> +@deftypefun int close_range (unsigned int @var{lowfd}, unsigned int @var{maxfd}, int @var{flags})
>> +@standards{Linux, unistd.h}
>> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
>> +@c This is a syscall for Linux v5.9.  There is no fallback emultation for
>> +@c older kernels.
> 
> Typo: “emultation”

Ack.

> 
>> +The function @code{clode_range} closes the file descriptor from @var{lowfd}
>> +to @var{maxfd} (included).  This function is similar to call @code{close} in
> 
> “(inclusive)”?
> 
>> +specified file descriptor range.
> 
> Maybe add, “depending on the flags”?  With the new CLOEXEC variant, the
> system call does not close anything, after all.

Ack.

> 
>> +The @var{flags} add options on how the files are closes.  Linux currently
>> +supports.
> 
> “supports:” (with colon)

Ack.

> 
>> +@vtable @code
>> +@item CLOSE_RANGE_UNSHARE
>> +It unshare the range of file descriptors from any other processes, instead
>> +of closing them.
>> +@end vtable
> 
> “The function call unshares the range”.
> 
> Is this really how CLOSE_RANGE_UNSHARE operates?  I think the
> implementation falls through to the closing operation after unsharing
> the descriptor table, so it still closes the descriptors.

It is not, I think I have used a sentence from a in-review patch for man-pages.
I think it would be better to just use the comment in UAPI kernel header:

  Unshare the file descriptor table before closing file descriptors.

> 
>> +
>> +The normal return value from @code{close} is @math{0}; a value of @math{-1}
> 
> “close” should be ”close_range”.

Ack.

> 
>> +is returned in case of failure.  The following @code{errno} error
>> +conditions are defined for this function:
>> +
>> +@table @code
>> +@item EINVAL
>> +The @var{lowfd} value is larger than @var{maxfd} or an unsupported @var{flag}
>> +is used.
>> +@end table
>> +@end deftypefun
> 
> Typo: “@var{flag}” (missing s)

Ack.

> 
> Other error codes with CLOSE_RANGE_UNSHARE: ENOMEM, EMFILE (see dup_fd).
> Maybe a few more.

Right, although I not very found of just duplicating what man-pages will
also document (with probably more details).

> 
>> diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list
>> index 01ec2bfa95..53575669c7 100644
>> --- a/sysdeps/unix/sysv/linux/syscalls.list
>> +++ b/sysdeps/unix/sysv/linux/syscalls.list
>> @@ -101,3 +101,4 @@ pkey_alloc	EXTRA	pkey_alloc	i:ii	pkey_alloc
>>  pkey_free	EXTRA	pkey_free	i:i	pkey_free
>>  gettid          EXTRA   gettid          Ei:     __gettid	gettid
>>  tgkill          EXTRA   tgkill          i:iii   __tgkill	tgkill
>> +close_range     EXTRA   close_range     i:iii   __close_range   close_range
> 
> Hmm, I'm trying to wrap around if this is correct for x32.  But since
> the kernel uses unsigned int, I think it is.

I was in doubt as well if it x32 would require to use 'U', but tests
does pass clean on x32.  I will add a test to check of using ~OU as
second argument as well.

> 
>> diff --git a/sysdeps/unix/sysv/linux/tst-close_range.c b/sysdeps/unix/sysv/linux/tst-close_range.c
>> new file mode 100644
>> index 0000000000..1a127bb9cb
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/tst-close_range.c
>> @@ -0,0 +1,198 @@
> 
>> +#include <dirent.h>
>> +#include <errno.h>
>> +#include <fcntl.h>
>> +#include <limits.h>
>> +#include <getopt.h>
>> +#include <signal.h>
>> +#include <stdbool.h>
>> +#include <stdlib.h>
>> +#include <stdint.h>
>> +
>> +#include <array_length.h>
>> +#include <support/capture_subprocess.h>
>> +#include <support/check.h>
>> +#include <support/descriptors.h>
>> +#include <support/support.h>
>> +#include <support/xsched.h>
>> +#include <support/xunistd.h>
>> +
>> +#define NFDS 100
>> +
>> +static void
>> +close_range_test_common (int lowfd, unsigned int flags)
>> +{
>> +  const int maximum_fd = lowfd + NFDS;
>> +  const int half_fd = maximum_fd / 2;
>> +  const int gap_1 = maximum_fd - 8;
>> +
>> +  /* Close half of the descriptors and check result.  */
>> +  {
>> +    int r = close_range (lowfd, half_fd, flags);
>> +    if (r == -1 && errno == ENOSYS)
>> +      FAIL_UNSUPPORTED ("close_range not supported");
>> +    TEST_COMPARE (r, 0);
>> +  }
>> +  for (int i = lowfd; i <= half_fd; i++)
>> +    {
>> +      TEST_COMPARE (fcntl (i, F_GETFL), -1);
>> +      TEST_COMPARE (errno, EBADF);
>> +    }
>> +  for (int i = half_fd + 1; i < maximum_fd; i++)
>> +    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
>> +
>> +  /* Create some gaps, close up to a threshold, and check result.  */
>> +  xclose (57);
>> +  xclose (78);
>> +  xclose (81);
>> +  xclose (82);
>> +  xclose (84);
>> +  xclose (90);
> 
> Should be lowfd + 57 etc.

It would make more sense indeed.

> 
>> +  TEST_COMPARE (close_range (half_fd + 1, gap_1, flags), 0);
>> +  for (int i = half_fd + 1; i < gap_1; i++)
>> +    {
>> +      TEST_COMPARE (fcntl (i, F_GETFL), -1);
>> +      TEST_COMPARE (errno, EBADF);
>> +    }
>> +  for (int i = gap_1 + 1; i < maximum_fd; i++)
>> +    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
>> +
>> +  /* Close the remmaining but the last one.  */
> 
> Typo: “remmaining”

Ack.

> 
>> +  TEST_COMPARE (close_range (gap_1 + 1, maximum_fd - 1, flags), 0);
>> +  for (int i = gap_1 + 1; i < maximum_fd - 1; i++)
>> +    {
>> +      TEST_COMPARE (fcntl (i, F_GETFL), -1);
>> +      TEST_COMPARE (errno, EBADF);
>> +    }
>> +  TEST_VERIFY (fcntl (maximum_fd, F_GETFL) > -1);
>> +
>> +  /* Close the last one.  */
>> +  TEST_COMPARE (close_range (maximum_fd, maximum_fd, flags), 0);
>> +  TEST_COMPARE (fcntl (maximum_fd, F_GETFL), -1);
>> +  TEST_COMPARE (errno, EBADF);
>> +}
>> +
>> +/* Basic tests: check if the syscall close ranges with and without gaps.  */
>> +static void
>> +__attribute__((used))
> 
> Why __attribute__ ((used))?  (Also elsewhere in the file.)

This is a left over from debugging.

> 
>> +close_range_test (void)
>> +{
>> +  struct support_descriptors *descrs = support_descriptors_list ();
>> +
>> +  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
>> +  for (int i = 0; i < NFDS; i++)
>> +    xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
> 
> Please add a check that there are no gaps.  And this opens NFDS + 1
> descriptors, so maybe add a comment to NFDS.
> 
> So perhaps this:
> 
>   int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
>   for (int i = 1; i <= NFDS; i++)
>     TEST_COMPARE (xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600),
>                   lowfd + i);

Ack.

> 
>> +/* Check if a clone_range on a subprocess created with CLONE_FILES close
>> +   the shared file descriptor table entries in the parent.  */
>> +static void
>> +__attribute__((used))
>> +close_range_test_subprocess (void)
>> +{
>> +  struct support_descriptors *descrs = support_descriptors_list ();
>> +
>> +  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
>> +  for (int i = 0; i < NFDS; i++)
>> +    xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
> 
> See above, maybe factor this out in a separate function?

Ack.

> 
>> +_Noreturn static int
>> +close_range_unshare_test_fn (void *arg)
>> +{
>> +  int lowfd = (int) ((uintptr_t) arg);
>> +  close_range_test_common (lowfd, CLOSE_RANGE_UNSHARE);
>> +  exit (EXIT_SUCCESS);
>> +}
> 
> I think you could check here against the original descriptor set, to
> ensure that CLOSE_RANGE_UNSHARE still closes everything.

But close_range_test_common already does it.

> 
>> +
>> +/* Check if a close_range with CLOSE_RANGE_UNSHARE issued from a subprocess
>> +   created with CLONE_FILES does not close the parent file descriptor list.  */
>> +static void
>> +__attribute__((used))
>> +close_range_unshare_test (void)
>> +{
> 
> (Create another descriptor list here.)

Ack.

> 
>> +  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
>> +  for (int i = 0; i < NFDS; i++)
>> +    xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
> 
> Shared function?

I will add it.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 2/4] Linux: Add close_range
  2020-12-23 14:07     ` Adhemerval Zanella
@ 2020-12-23 14:17       ` Florian Weimer
  0 siblings, 0 replies; 15+ messages in thread
From: Florian Weimer @ 2020-12-23 14:17 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

* Adhemerval Zanella:

>>> +_Noreturn static int
>>> +close_range_unshare_test_fn (void *arg)
>>> +{
>>> +  int lowfd = (int) ((uintptr_t) arg);
>>> +  close_range_test_common (lowfd, CLOSE_RANGE_UNSHARE);
>>> +  exit (EXIT_SUCCESS);
>>> +}
>> 
>> I think you could check here against the original descriptor set, to
>> ensure that CLOSE_RANGE_UNSHARE still closes everything.
>
> But close_range_test_common already does it.

Okay, that's probably enough.

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 4/4] posix: Add posix_spawn_file_actions_closefrom
  2020-12-22 21:27 ` [PATCH v2 4/4] posix: Add posix_spawn_file_actions_closefrom Adhemerval Zanella
@ 2020-12-23 14:27   ` Florian Weimer
  2020-12-23 16:18     ` Adhemerval Zanella
  0 siblings, 1 reply; 15+ messages in thread
From: Florian Weimer @ 2020-12-23 14:27 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

* Adhemerval Zanella:

> +* The posix_spawn_file_actions_closefrom_np has been added, enabling
> +  posix_spawn and posix_spawnp to close all file descriptors greater than
> +  a giver integer.  This function is a GNU extension, although Solaris also
> +  provides a similar function.

“The function posix_spawn_file_actions_closefrom_np”?

> +static void
> +do_test_closefrom (void)
> +{
> +  int lowfd = xopen ("/dev/null", O_WRONLY, 0);
> +  for (int i = 1; i < NFDS; i++)
> +    xopen ("/dev/null", O_WRONLY, 0);

The usual observation about NFDS and fgap checking.

> +  /* Create some gaps, close up to a threshold, and check result.  */
> +  xclose (57);
> +  xclose (78);
> +  xclose (81);
> +  xclose (82);
> +  xclose (84);
> +  xclose (90);

Please add lowfd here as well.

> diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
> index f157bfffd2..c337c7a6a1 100644
> --- a/sysdeps/unix/sysv/linux/spawni.c
> +++ b/sysdeps/unix/sysv/linux/spawni.c
> @@ -16,22 +16,17 @@
>     License along with the GNU C Library; if not, see
>     <https://www.gnu.org/licenses/>.  */
>  
> -#include <spawn.h>
> -#include <fcntl.h>
> -#include <paths.h>
> -#include <string.h>
> -#include <sys/resource.h>
> -#include <sys/wait.h>
> -#include <sys/param.h>
> -#include <sys/mman.h>
> -#include <not-cancel.h>
> +#include <arch-fd_to_filename.h>
> +#include <internal-signals.h>
> +#include <ldsodefs.h>
>  #include <local-setxid.h>
> +#include <not-cancel.h>
> +#include <paths.h>
>  #include <shlib-compat.h>
> -#include <nptl/pthreadP.h>
> -#include <dl-sysdep.h>
> -#include <libc-pointer-arith.h>
> -#include <ldsodefs.h>
> -#include "spawn_int.h"
> +#include <spawn.h>
> +#include <spawn_int.h>
> +#include <sysdep.h>
> +#include <sys/resource.h>

Is <arch-fd_to_filename.h> really required here?

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 3/4] io: Add closefrom [BZ #10353]
  2020-12-23 13:28   ` Florian Weimer
@ 2020-12-23 14:51     ` Adhemerval Zanella
  0 siblings, 0 replies; 15+ messages in thread
From: Adhemerval Zanella @ 2020-12-23 14:51 UTC (permalink / raw)
  To: Florian Weimer; +Cc: libc-alpha



On 23/12/2020 10:28, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>> The symbol closes all open file descriptors greater than or equal to
>> input argument.  Negative values are campled to 0, i.e, it will close
>> all file descriptors.
> 
> “The function”?
> 
> Typo: “campled”.

Ack.

> 
>> diff --git a/io/tst-closefrom.c b/io/tst-closefrom.c
>> new file mode 100644
>> index 0000000000..47b50b74b6
>> --- /dev/null
>> +++ b/io/tst-closefrom.c
> 
>> +#define NFDS 100
>> +
>> +static int
>> +closefrom_test (void)
>> +{
>> +  struct support_descriptors *descrs = support_descriptors_list ();
>> +
>> +  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
>> +  for (int i = 0; i < NFDS; i++)
>> +    xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
> 
> See the previous comments about checking for contiguous allocation and
> the meaning of NFDS.

Ack.

> 
>> +  const int maximum_fd = lowfd + NFDS;
>> +  const int half_fd = maximum_fd / 2;
>> +  const int gap = maximum_fd / 4;
>> +
>> +  /* Close half of the descriptors and check result.  */
>> +  closefrom (half_fd);
>> +
>> +  for (int i = half_fd; i <= maximum_fd; i++)
>> +    {
>> +      TEST_COMPARE (fcntl (i, F_GETFL), -1);
>> +      TEST_COMPARE (errno, EBADF);
>> +    }
>> +  for (int i = 0; i < half_fd; i++)
>> +    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
>> +
>> +  /* Create some gaps, close up to a threshold, and check result.  */
>> +  xclose (35);
>> +  xclose (38);
>> +  xclose (42);
>> +  xclose (46);
> 
> lowfd + 35 etc., please.

Ack.

> 
>> +/* Check if closefrom works even when no new file descriptors can be
>> +   created.  */
>> +static int
>> +closefrom_test_file_desc_limit (void)
>> +{
>> +  int max_fd = NFDS;
>> +  {
>> +    struct rlimit rl;
>> +    if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
>> +      FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
>> +
>> +    max_fd = (rl.rlim_cur < max_fd ? rl.rlim_cur : max_fd);
>> +    rl.rlim_cur = max_fd;
>> +
>> +    if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
>> +      FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
>> +  }
>> +
>> +  /* Exhauste the file descriptor limit.  */
>> +  int lowfd = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
>> +  for (;;)
>> +    {
>> +      int fd = open ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
>> +      if (fd == -1)
>> +	{
>> +	  if (errno != EMFILE)
>> +	    FAIL_EXIT1 ("create_temp_file: %m");
>> +	  break;
>> +	}
>> +    }
>> +
>> +  closefrom (lowfd);
>> +  for (int i = lowfd; i < NFDS; i++)
>> +    {
>> +      TEST_COMPARE (fcntl (i, F_GETFL), -1);
>> +      TEST_COMPARE (errno, EBADF);
>> +    }
>> +
>> +  return 0;
>> +}
> 
> Good test, thanks.
> 
>> diff --git a/manual/llio.texi b/manual/llio.texi
>> index 018e7933de..d2cf7bbabd 100644
>> --- a/manual/llio.texi
>> +++ b/manual/llio.texi
>> @@ -314,6 +314,20 @@ is used.
>>  @end table
>>  @end deftypefun
>>  
>> +@deftypefun void closefrom (int @var{lowfd})
>> +@standards{GNU, unistd.h}
>> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
>> +
>> +The function @code{closefrom} closes all file descriptors large or equal
>> +then @var{lowfd}.  This function is similar to call @code{close} in specified
>> +file descriptor range.
>> +
>> +@table @code
>> +@item EINVAL
>> +The @var{lowfd} value is larger than @var{maxfd} or an unsupported @var{flag}
>> +is used.
>> +@end table
>> +@end deftypefun
> 
> I think this function cannot fail.

I can't, I will remove it.

> 
>>  @node I/O Primitives
>>  @section Input and Output Primitives
>> diff --git a/posix/unistd.h b/posix/unistd.h
>> index 32b8161619..652fed4616 100644
>> --- a/posix/unistd.h
>> +++ b/posix/unistd.h
>> @@ -352,6 +352,12 @@ extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence)
>>     __THROW.  */
>>  extern int close (int __fd);
>>  
>> +#ifdef __USE_GNU
>> +/* Close all open file descriptors greater than or equal to LOWFD.
>> +   Negative LOWFD is clamped to 0.  */
>> +extern void closefrom (int __lowfd) __THROW;
>> +#endif
> 
> __USE_MISC instead of GNU?  Given that this is so widely implemented.

Ack.

> 
>> diff --git a/sysdeps/unix/sysv/linux/closefrom_fallback.c b/sysdeps/unix/sysv/linux/closefrom_fallback.c
>> new file mode 100644
>> index 0000000000..461582792d
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/closefrom_fallback.c
> 
>> +/* Fallback code: iterates over /proc/self/fd, closing each file descriptor
>> +   that fall on the criteria.  */
>> +_Bool
>> +__closefrom_fallback (int from)
>> +{
>> +  bool ret = false;
>> +
>> +  int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY,
>> +			       0);
>> +  if (dirfd == -1)
>> +    {
>> +      /* The closefrom should work even when process can't open new files.
>> +	 In this case it loops over RLIMIT_NOFILE / rlim_cur until it frees
>> +	 a file descriptor to iterate over /proc.  */
>> +      if (errno != EMFILE)
>> +	goto err;
> 
> As explained, this should be errno == ENOENT.  There are a few more
> calls that could take the shortcut, but I don't think they can occur in
> practice.

Alright, I see that we need to bail out early if /proc is not found to
avoid closing file descriptor early.

> 
>> +  char buffer[1024];
>> +  while (true)
>> +    {
>> +      ssize_t ret = __getdents64 (dirfd, buffer, sizeof (buffer));
>> +      if (ret == -1)
>> +        goto err;
>> +      else if (ret == 0)
>> +        break;
>> +
>> +      char *begin = buffer, *end = buffer + ret;
>> +      while (begin != end)
>> +	{
>> +          unsigned short int d_reclen;
>> +	  memcpy (&d_reclen, begin + offsetof (struct dirent64, d_reclen),
>> +		  sizeof (d_reclen));
>> +	  const char *dname = begin + offsetof (struct dirent64, d_name);
>> +	  begin += d_reclen;
>> +
>> +	  if (dname[0] == '.')
>> +	    continue;
>> +
>> +	  int fd = 0;
>> +	  for (const char *s = dname; (unsigned int) (*s) - '0' < 10; s++)
>> +	    fd = 10 * fd + (*s - '0');
>> +
>> +	  if (fd == dirfd || fd < from)
>> +	    continue;
>> +
>> +	  __close_nocancel (fd);
>> +	}
>> +    }
> 
> Do you object to the idea of the rewind?  The implementation above
> encodes very specific /proc/self/fd behavior.

In fact I added it, but I forgot to update the patch.

> 
> With containers and seccomp filters, we can't assume that a future
> behavioral change will not matter because we have close_range.
> 
> Thanks,
> Florian
> 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v2 4/4] posix: Add posix_spawn_file_actions_closefrom
  2020-12-23 14:27   ` Florian Weimer
@ 2020-12-23 16:18     ` Adhemerval Zanella
  0 siblings, 0 replies; 15+ messages in thread
From: Adhemerval Zanella @ 2020-12-23 16:18 UTC (permalink / raw)
  To: Florian Weimer; +Cc: libc-alpha



On 23/12/2020 11:27, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>> +* The posix_spawn_file_actions_closefrom_np has been added, enabling
>> +  posix_spawn and posix_spawnp to close all file descriptors greater than
>> +  a giver integer.  This function is a GNU extension, although Solaris also
>> +  provides a similar function.
> 
> “The function posix_spawn_file_actions_closefrom_np”?

Ack.

> 
>> +static void
>> +do_test_closefrom (void)
>> +{
>> +  int lowfd = xopen ("/dev/null", O_WRONLY, 0);
>> +  for (int i = 1; i < NFDS; i++)
>> +    xopen ("/dev/null", O_WRONLY, 0);
> 
> The usual observation about NFDS and fgap checking.

Ack.

> 
>> +  /* Create some gaps, close up to a threshold, and check result.  */
>> +  xclose (57);
>> +  xclose (78);
>> +  xclose (81);
>> +  xclose (82);
>> +  xclose (84);
>> +  xclose (90);
> 
> Please add lowfd here as well.

Ack.

> 
>> diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
>> index f157bfffd2..c337c7a6a1 100644
>> --- a/sysdeps/unix/sysv/linux/spawni.c
>> +++ b/sysdeps/unix/sysv/linux/spawni.c
>> @@ -16,22 +16,17 @@
>>     License along with the GNU C Library; if not, see
>>     <https://www.gnu.org/licenses/>.  */
>>  
>> -#include <spawn.h>
>> -#include <fcntl.h>
>> -#include <paths.h>
>> -#include <string.h>
>> -#include <sys/resource.h>
>> -#include <sys/wait.h>
>> -#include <sys/param.h>
>> -#include <sys/mman.h>
>> -#include <not-cancel.h>
>> +#include <arch-fd_to_filename.h>
>> +#include <internal-signals.h>
>> +#include <ldsodefs.h>
>>  #include <local-setxid.h>
>> +#include <not-cancel.h>
>> +#include <paths.h>
>>  #include <shlib-compat.h>
>> -#include <nptl/pthreadP.h>
>> -#include <dl-sysdep.h>
>> -#include <libc-pointer-arith.h>
>> -#include <ldsodefs.h>
>> -#include "spawn_int.h"
>> +#include <spawn.h>
>> +#include <spawn_int.h>
>> +#include <sysdep.h>
>> +#include <sys/resource.h>
> 
> Is <arch-fd_to_filename.h> really required here?
> 

Indeed.

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2020-12-23 16:18 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-22 21:27 [PATCH 1/4] support: Add xclone Adhemerval Zanella
2020-12-22 21:27 ` [PATCH v2 2/4] Linux: Add close_range Adhemerval Zanella
2020-12-23 12:22   ` Florian Weimer
2020-12-23 14:07     ` Adhemerval Zanella
2020-12-23 14:17       ` Florian Weimer
2020-12-22 21:27 ` [PATCH v2 3/4] io: Add closefrom [BZ #10353] Adhemerval Zanella
2020-12-23 13:28   ` Florian Weimer
2020-12-23 14:51     ` Adhemerval Zanella
2020-12-22 21:27 ` [PATCH v2 4/4] posix: Add posix_spawn_file_actions_closefrom Adhemerval Zanella
2020-12-23 14:27   ` Florian Weimer
2020-12-23 16:18     ` Adhemerval Zanella
2020-12-23 11:35 ` [PATCH 1/4] support: Add xclone Florian Weimer
2020-12-23 13:13   ` Adhemerval Zanella
2020-12-23 12:20 ` Christian Brauner
2020-12-23 13:05   ` Adhemerval Zanella

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).