public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v4 1/5] support: Add support_stack_alloc
@ 2021-03-10 15:26 Adhemerval Zanella
  2021-03-10 15:26 ` [PATCH v4 2/5] support: Add xclone Adhemerval Zanella
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Adhemerval Zanella @ 2021-03-10 15:26 UTC (permalink / raw)
  To: libc-alpha

The code to allocate a stack from xsigstack is refactored so it can
be more generic.
---
 support/Makefile              |  1 +
 support/support.h             | 20 +++++++++
 support/support_stack_alloc.c | 78 +++++++++++++++++++++++++++++++++++
 support/xsigstack.c           | 43 +++----------------
 4 files changed, 104 insertions(+), 38 deletions(-)
 create mode 100644 support/support_stack_alloc.c

diff --git a/support/Makefile b/support/Makefile
index 8d63fbd5da..7ce42bf6e8 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -39,6 +39,7 @@ libsupport-routines = \
   resolv_response_context_free \
   resolv_test \
   set_fortify_handler \
+  support_stack_alloc \
   support-xfstat \
   support-xstat \
   support_become_root \
diff --git a/support/support.h b/support/support.h
index 9cbc455720..f46bdd761d 100644
--- a/support/support.h
+++ b/support/support.h
@@ -129,6 +129,26 @@ extern void support_copy_file (const char *from, const char *to);
 extern ssize_t support_copy_file_range (int, off64_t *, int, off64_t *,
 					size_t, unsigned int);
 
+
+struct support_stack
+{
+  void *stack;
+  size_t size;
+  size_t guardsize;
+};
+
+/* Allocate stack suitable to used with xclone or sigaltstack call. The stack
+   will have a minimum size of SIZE + MINSIGSTKSZ bytes, rounded up to a whole
+   number of pages.  There will be a large (at least 1 MiB) inaccessible guard
+   bands on either side of it.
+   The returned value on ALLOC_BASE and ALLOC_SIZE will be the usable stack
+   region, excluding the GUARD_SIZE allocated area.
+   It also terminates the process on error.  */
+struct support_stack support_stack_alloc (size_t size);
+
+/* Deallocate the STACK.  */
+void support_stack_free (struct support_stack *stack);
+
 __END_DECLS
 
 #endif /* SUPPORT_H */
diff --git a/support/support_stack_alloc.c b/support/support_stack_alloc.c
new file mode 100644
index 0000000000..781fa36435
--- /dev/null
+++ b/support/support_stack_alloc.c
@@ -0,0 +1,78 @@
+/* Allocate a stack suitable to be used with xclone or xsigaltstack.
+   Copyright (C) 2021 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 <support/check.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/param.h> /* roundup, MAX  */
+
+#ifndef MAP_NORESERVE
+# define MAP_NORESERVE 0
+#endif
+#ifndef MAP_STACK
+# define MAP_STACK 0
+#endif
+
+struct support_stack
+support_stack_alloc (size_t size)
+{
+  size_t pagesize = sysconf (_SC_PAGESIZE);
+  if (pagesize == -1)
+    FAIL_EXIT1 ("sysconf (_SC_PAGESIZE): %m\n");
+
+  /* Always supply at least MINSIGSTKSZ space; passing 0 as size means
+     only that much space.  No matter what the number is, round it up
+     to a whole number of pages.  */
+  size_t stacksize = roundup (size + MINSIGSTKSZ, pagesize);
+
+  /* The guard bands need to be large enough to intercept offset
+     accesses from a stack address that might otherwise hit another
+     mapping.  Make them at least twice as big as the stack itself, to
+     defend against an offset by the entire size of a large
+     stack-allocated array.  The minimum is 1MiB, which is arbitrarily
+     chosen to be larger than any "typical" wild pointer offset.
+     Again, no matter what the number is, round it up to a whole
+     number of pages.  */
+  size_t guardsize = roundup (MAX (2 * stacksize, 1024 * 1024), pagesize);
+  size_t alloc_size = guardsize + stacksize + guardsize;
+  /* Use MAP_NORESERVE so that RAM will not be wasted on the guard
+     bands; touch all the pages of the actual stack before returning,
+     so we know they are allocated.  */
+  void *alloc_base = xmmap (0,
+                            alloc_size,
+                            PROT_READ|PROT_WRITE,
+                            MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE|MAP_STACK,
+                            -1);
+  xmprotect (alloc_base, guardsize, PROT_NONE);
+  xmprotect (alloc_base + guardsize + stacksize, guardsize, PROT_NONE);
+  memset (alloc_base + guardsize, 0xA5, stacksize);
+  return (struct support_stack) { alloc_base + guardsize,
+				  alloc_size - 2 * guardsize,
+				  guardsize };
+}
+
+void
+support_stack_free (struct support_stack *stack)
+{
+  void *alloc_base = (void *)((uintptr_t) stack->stack - stack->guardsize);
+  size_t alloc_size = stack->size + 2 * stack->guardsize;
+  xmunmap (alloc_base, alloc_size);
+}
diff --git a/support/xsigstack.c b/support/xsigstack.c
index a2f0e3269a..a471c853cb 100644
--- a/support/xsigstack.c
+++ b/support/xsigstack.c
@@ -37,8 +37,7 @@
    structures.  */
 struct sigstack_desc
 {
-  void *alloc_base;  /* Base address of the complete allocation.  */
-  size_t alloc_size; /* Size of the complete allocation.  */
+  struct support_stack stack;
   stack_t alt_stack; /* The address and size of the stack itself.  */
   stack_t old_stack; /* The previous signal stack.  */
 };
@@ -46,43 +45,11 @@ struct sigstack_desc
 void *
 xalloc_sigstack (size_t size)
 {
-  size_t pagesize = sysconf (_SC_PAGESIZE);
-  if (pagesize == -1)
-    FAIL_EXIT1 ("sysconf (_SC_PAGESIZE): %m\n");
-
-  /* Always supply at least MINSIGSTKSZ space; passing 0 as size means
-     only that much space.  No matter what the number is, round it up
-     to a whole number of pages.  */
-  size_t stacksize = roundup (size + MINSIGSTKSZ, pagesize);
-
-  /* The guard bands need to be large enough to intercept offset
-     accesses from a stack address that might otherwise hit another
-     mapping.  Make them at least twice as big as the stack itself, to
-     defend against an offset by the entire size of a large
-     stack-allocated array.  The minimum is 1MiB, which is arbitrarily
-     chosen to be larger than any "typical" wild pointer offset.
-     Again, no matter what the number is, round it up to a whole
-     number of pages.  */
-  size_t guardsize = roundup (MAX (2 * stacksize, 1024 * 1024), pagesize);
-
   struct sigstack_desc *desc = xmalloc (sizeof (struct sigstack_desc));
-  desc->alloc_size = guardsize + stacksize + guardsize;
-  /* Use MAP_NORESERVE so that RAM will not be wasted on the guard
-     bands; touch all the pages of the actual stack before returning,
-     so we know they are allocated.  */
-  desc->alloc_base = xmmap (0,
-                            desc->alloc_size,
-                            PROT_READ|PROT_WRITE,
-                            MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE|MAP_STACK,
-                            -1);
-
-  xmprotect (desc->alloc_base, guardsize, PROT_NONE);
-  xmprotect (desc->alloc_base + guardsize + stacksize, guardsize, PROT_NONE);
-  memset (desc->alloc_base + guardsize, 0xA5, stacksize);
-
-  desc->alt_stack.ss_sp    = desc->alloc_base + guardsize;
+  desc->stack = support_stack_alloc (size);
+  desc->alt_stack.ss_sp    = desc->stack.stack;
   desc->alt_stack.ss_flags = 0;
-  desc->alt_stack.ss_size  = stacksize;
+  desc->alt_stack.ss_size  = desc->stack.size;
 
   if (sigaltstack (&desc->alt_stack, &desc->old_stack))
     FAIL_EXIT1 ("sigaltstack (new stack: sp=%p, size=%zu, flags=%u): %m\n",
@@ -101,7 +68,7 @@ xfree_sigstack (void *stack)
     FAIL_EXIT1 ("sigaltstack (restore old stack: sp=%p, size=%zu, flags=%u): "
                 "%m\n", desc->old_stack.ss_sp, desc->old_stack.ss_size,
                 desc->old_stack.ss_flags);
-  xmunmap (desc->alloc_base, desc->alloc_size);
+  support_stack_free (&desc->stack);
   free (desc);
 }
 
-- 
2.25.1


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

* [PATCH v4 2/5] support: Add xclone
  2021-03-10 15:26 [PATCH v4 1/5] support: Add support_stack_alloc Adhemerval Zanella
@ 2021-03-10 15:26 ` Adhemerval Zanella
  2021-03-10 15:26 ` [PATCH v4 3/5] Linux: Add close_range Adhemerval Zanella
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 12+ messages in thread
From: Adhemerval Zanella @ 2021-03-10 15:26 UTC (permalink / raw)
  To: libc-alpha

Changes from previous version:

  - Removed DEFINE_STACK

---

It is a wrapper for Linux clone 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 | 50 ++++++++++++++++++++++++++++++++++++++++++++++++
 support/xsched.h | 34 ++++++++++++++++++++++++++++++++
 3 files changed, 85 insertions(+)
 create mode 100644 support/xclone.c
 create mode 100644 support/xsched.h

diff --git a/support/Makefile b/support/Makefile
index 7ce42bf6e8..56534f0f9d 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -92,6 +92,7 @@ libsupport-routines = \
   xchroot \
   xclock_gettime \
   xclock_settime \
+  xclone \
   xclose \
   xchmod \
   xconnect \
diff --git a/support/xclone.c b/support/xclone.c
new file mode 100644
index 0000000000..924d2b8754
--- /dev/null
+++ b/support/xclone.c
@@ -0,0 +1,50 @@
+/* Auxiliary functions to issue the clone syscall.
+   Copyright (C) 2021 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/>.  */
+
+#ifdef __linux__
+# include <support/check.h>
+# 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 __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
+
+  if (r < 0)
+    FAIL_EXIT1 ("clone: %m");
+
+  return r;
+}
+#endif
diff --git a/support/xsched.h b/support/xsched.h
new file mode 100644
index 0000000000..eefd731940
--- /dev/null
+++ b/support/xsched.h
@@ -0,0 +1,34 @@
+/* Wrapper for sched.h functions.
+   Copyright (C) 2021 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>
+
+#ifdef __linux__
+pid_t xclone (int (*fn) (void *arg), void *arg, void *stack,
+	      size_t stack_size, int flags);
+#endif
+
+__END_DECLS
+
+#endif
-- 
2.25.1


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

* [PATCH v4 3/5] Linux: Add close_range
  2021-03-10 15:26 [PATCH v4 1/5] support: Add support_stack_alloc Adhemerval Zanella
  2021-03-10 15:26 ` [PATCH v4 2/5] support: Add xclone Adhemerval Zanella
@ 2021-03-10 15:26 ` Adhemerval Zanella
  2021-03-24 22:42   ` Alyssa Ross
  2021-03-10 15:26 ` [PATCH v4 4/5] io: Add closefrom [BZ #10353] Adhemerval Zanella
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Adhemerval Zanella @ 2021-03-10 15:26 UTC (permalink / raw)
  To: libc-alpha

Changes from previous version:

  - Use the new support_stack_alloc to create the temporary stack
    for the xclone call.
  - Added a note on manual about the lack of fallback and the
    semantic for already-closed file descriptors.
  - Fixed the glibc version and copyright year for newer files.
  - The Linux linux/close_range.h header is included if available
    and the tst-close_range-consts.py is removed.

---

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                                          |   3 +
 include/bits/unistd_ext.h                     |   6 +
 manual/llio.texi                              |  42 ++++
 sysdeps/unix/sysv/linux/Makefile              |   2 +-
 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/be/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/bits/unistd_ext.h     |  18 ++
 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/syscalls.list         |   1 +
 sysdeps/unix/sysv/linux/tst-close_range.c     | 226 ++++++++++++++++++
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
 40 files changed, 332 insertions(+), 1 deletion(-)
 create mode 100644 include/bits/unistd_ext.h
 create mode 100644 sysdeps/unix/sysv/linux/tst-close_range.c

diff --git a/NEWS b/NEWS
index aa0f10a891..ff2b952a06 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,9 @@ Major new features:
   a dump of information related to IFUNC resolver operation and
   glibc-hwcaps subdirectory selection.
 
+* On Linux, the close_range function has been added.  It allows efficiently
+  closing a range of file descriptors on recent kernels (version 5.9).
+
 Deprecated and removed features, and other changes affecting compatibility:
 
   [Add deprecations, removals and changes affecting compatibility here]
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..c1f54f4a8a 100644
--- a/manual/llio.texi
+++ b/manual/llio.texi
@@ -284,6 +284,48 @@ 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 emulation for
+@c older kernels.
+
+The function @code{close_range} closes the file descriptor from @var{lowfd}
+to @var{maxfd} (inclusive).  This function is similar to call @code{close} in
+specified file descriptor range depending on the @var{flags}.
+
+This is function is only supportted on recent Linux versions and @theglibc{}
+does not provide any fallback (the application will need to handle possible
+@code{ENOSYS}).
+
+The @var{flags} add options on how the files are closes.  Linux currently
+supports:
+
+@vtable @code
+@item CLOSE_RANGE_UNSHARE
+Unshare the file descriptor table before closing file descriptors.
+@end vtable
+
+The normal return value from @code{close_range} 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{flags}
+is used.
+
+@item ENOMEM
+Either there is not enough memory for the operation, or the process is
+out of address space.
+
+@item EMFILE
+The process has too many files open.
+The maximum number of file descriptors is controlled by the
+@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 e42bc7f13b..8cf908ac8d 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -108,7 +108,7 @@ tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \
 	 tst-rlimit-infinity tst-ofdlocks tst-gettid tst-gettid-kill \
 	 tst-tgkill tst-sysvsem-linux tst-sysvmsg-linux tst-sysvshm-linux \
 	 tst-timerfd tst-ppoll tst-futimens tst-utime tst-utimes \
-	 tst-clock_adjtime tst-adjtimex tst-ntp_adjtime
+	 tst-clock_adjtime tst-adjtimex tst-ntp_adjtime tst-close_range
 
 # Test for the symbol version of fcntl that was replaced in glibc 2.28.
 ifeq ($(have-GLIBC_2.27)$(build-shared),yesyes)
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index c35f783e2a..497ac94d62 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -169,6 +169,9 @@ libc {
   }
   GLIBC_2.32 {
   }
+  GLIBC_2.34 {
+    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 bac795262d..ba6112e28f 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2172,3 +2172,4 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 897f70db22..d87677063e 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2254,6 +2254,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 604d259ad6..2ec383822c 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1932,3 +1932,4 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 094236f713..3df5df5436 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -156,6 +156,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 2bb4d31e81..175dc3165c 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -153,6 +153,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/bits/unistd_ext.h b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
index 2e529be577..7ddc09a30e 100644
--- a/sysdeps/unix/sysv/linux/bits/unistd_ext.h
+++ b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
@@ -33,4 +33,22 @@
    not detached and has not been joined.  */
 extern __pid_t gettid (void) __THROW;
 
+/* Unshare the file descriptor table before closing file descriptors.  */
+#ifdef __has_include
+# if __has_include ("linux/close_range.h")
+#  include "linux/close_range.h"
+# endif
 #endif
+#ifndef CLOSE_RANGE_UNSHARE
+# define CLOSE_RANGE_UNSHARE (1U << 1)
+#endif
+
+/* 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 /* __USE_GNU  */
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index d4291fecfb..cbb89a2dc0 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2116,3 +2116,4 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 1fd2a862f6..a0b43e9861 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2075,6 +2075,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 943331f01e..24b7180311 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2242,6 +2242,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index f530151bde..ac26edbe34 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2107,6 +2107,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 6e76b6dcaa..7ad5ce4421 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -157,6 +157,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 7541b8289f..ad3efc33bf 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2187,6 +2187,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 6cf1936c42..4bf921c5eb 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2167,3 +2167,4 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 98730ebcda..c3db2009a2 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2164,3 +2164,4 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 92fa6cbc73..74396aa313 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2158,6 +2158,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 265a49e74e..58bde27971 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2156,6 +2156,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 cfa5e1111b..2e91d9f1df 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2164,6 +2164,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 8c03ac52cd..30eed1ac64 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2158,6 +2158,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 17f5609e06..a05d72a10f 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2205,3 +2205,4 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 76a16e2a6d..ccce71f5ac 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2214,6 +2214,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 697f072fd4..eb79b4acd5 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2247,6 +2247,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 2647bb51f1..80b1c66f9d 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2077,6 +2077,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 036b1c8345..0a82bbfc6f 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2367,3 +2367,4 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index ff3225e16f..02db9c5967 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -1934,3 +1934,4 @@ GLIBC_2.33 write F
 GLIBC_2.33 writev F
 GLIBC_2.33 wscanf F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index fb5ad9909f..0e0d0a88db 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2134,3 +2134,4 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index cead75acc5..5dfeadb8b9 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2212,6 +2212,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 31366dd7e6..fd951e93ce 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2113,6 +2113,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index a3a8be8910..19b23cf363 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2082,6 +2082,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 8f505c5045..70956fc56d 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2079,6 +2079,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 53ef6304f1..537e27fb83 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2203,6 +2203,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index eba0cb156d..056a51ba88 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2130,6 +2130,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk 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.c b/sysdeps/unix/sysv/linux/tst-close_range.c
new file mode 100644
index 0000000000..6f9157be49
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-close_range.c
@@ -0,0 +1,226 @@
+/* Test for the close_range system call.
+   Copyright (C) 2021 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 int
+open_multiple_temp_files (void)
+{
+  /* Check if the temporary file descriptor has no no gaps.  */
+  int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
+  for (int i = 1; i <= NFDS; i++)
+    TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600),
+		  lowfd + i);
+  return lowfd;
+}
+
+static void
+close_range_test_max_upper_limit (void)
+{
+  struct support_descriptors *descrs = support_descriptors_list ();
+
+  int lowfd = open_multiple_temp_files ();
+
+  {
+    int r = close_range (lowfd, ~0U, 0);
+    if (r == -1 && errno == ENOSYS)
+      FAIL_UNSUPPORTED ("close_range not supported");
+    TEST_COMPARE (r, 0);
+  }
+
+  support_descriptors_check (descrs);
+  support_descriptors_free (descrs);
+}
+
+static void
+close_range_test_common (int lowfd, unsigned int flags)
+{
+  const int maximum_fd = lowfd + NFDS;
+  const int half_fd = lowfd + NFDS / 2;
+  const int gap_1 = maximum_fd - 8;
+
+  /* Close half of the descriptors and check result.  */
+  TEST_COMPARE (close_range (lowfd, half_fd, flags), 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 (lowfd + 57);
+  xclose (lowfd + 78);
+  xclose (lowfd + 81);
+  xclose (lowfd + 82);
+  xclose (lowfd + 84);
+  xclose (lowfd + 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 remaining 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
+close_range_test (void)
+{
+  struct support_descriptors *descrs = support_descriptors_list ();
+
+  /* Check if the temporary file descriptor has no no gaps.  */
+  int lowfd = open_multiple_temp_files ();
+
+  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
+close_range_test_subprocess (void)
+{
+  struct support_descriptors *descrs = support_descriptors_list ();
+
+  /* Check if the temporary file descriptor has no no gaps.  */
+  int lowfd = open_multiple_temp_files ();
+
+  struct support_stack stack = support_stack_alloc (4096);
+
+  pid_t pid = xclone (close_range_test_fn, (void*) (uintptr_t) lowfd,
+		      stack.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);
+
+  support_stack_free (&stack);
+
+  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
+close_range_unshare_test (void)
+{
+  struct support_descriptors *descrs1 = support_descriptors_list ();
+
+  /* Check if the temporary file descriptor has no no gaps.  */
+  int lowfd = open_multiple_temp_files ();
+
+  struct support_descriptors *descrs2 = support_descriptors_list ();
+
+  struct support_stack stack = support_stack_alloc (4096);
+
+  pid_t pid = xclone (close_range_unshare_test_fn, (void*) (uintptr_t) lowfd,
+		      stack.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);
+
+  support_stack_free (&stack);
+
+  for (int i = 0; i < NFDS; i++)
+    TEST_VERIFY (fcntl (i, F_GETFL) > -1);
+
+  support_descriptors_check (descrs2);
+  support_descriptors_free (descrs2);
+
+  TEST_COMPARE (close_range (lowfd, lowfd + NFDS, 0), 0);
+
+  support_descriptors_check (descrs1);
+  support_descriptors_free (descrs1);
+}
+
+static int
+do_test (void)
+{
+  close_range_test_max_upper_limit ();
+  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 17ce5dfd58..84903475e4 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2089,6 +2089,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 17a1c83903..303106af6a 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2186,3 +2186,4 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 close_range F
-- 
2.25.1


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

* [PATCH v4 4/5] io: Add closefrom [BZ #10353]
  2021-03-10 15:26 [PATCH v4 1/5] support: Add support_stack_alloc Adhemerval Zanella
  2021-03-10 15:26 ` [PATCH v4 2/5] support: Add xclone Adhemerval Zanella
  2021-03-10 15:26 ` [PATCH v4 3/5] Linux: Add close_range Adhemerval Zanella
@ 2021-03-10 15:26 ` Adhemerval Zanella
  2021-03-10 21:54   ` Joseph Myers
  2021-03-10 15:26 ` [PATCH v4 5/5] posix: Add posix_spawn_file_actions_closefrom_np Adhemerval Zanella
  2021-03-10 16:10 ` [PATCH v4 1/5] support: Add support_stack_alloc Florian Weimer
  4 siblings, 1 reply; 12+ messages in thread
From: Adhemerval Zanella @ 2021-03-10 15:26 UTC (permalink / raw)
  To: libc-alpha

Changes from previous version:

  - Fixed manual.
  - Fixed the glibc version and copyright year for newer files.
  - Added the previous review fixes for __closefrom_fallback.

---

The function closes all open file descriptors greater than or equal to
input argument.  Negative values are clamped 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                                   |   3 +
 io/closefrom.c                                |  34 ++++
 io/tst-closefrom.c                            | 152 ++++++++++++++++++
 manual/llio.texi                              |  10 ++
 posix/unistd.h                                |   6 +
 sysdeps/mach/hurd/i386/libc.abilist           |   1 +
 sysdeps/unix/sysv/linux/Makefile              |   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/be/libc.abilist   |   2 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/closefrom.c           |  35 ++++
 sysdeps/unix/sysv/linux/closefrom_fallback.c  |  97 +++++++++++
 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     |   2 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
 .../sysv/linux/microblaze/be/libc.abilist     |   1 +
 .../sysv/linux/microblaze/le/libc.abilist     |   2 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
 .../sysv/linux/mips/mips32/nofpu/libc.abilist |   2 +
 .../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      |   2 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |   2 +
 .../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    |   2 +
 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, 387 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 ff2b952a06..0c7bc74cca 100644
--- a/NEWS
+++ b/NEWS
@@ -91,6 +91,10 @@ Major new features:
   The latest GCC available at this time (10.2) does not support this level of
   fortification.
 
+* 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 b7bebe923f..f6aee2cc37 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -54,7 +54,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
@@ -68,7 +69,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..f28bd43773 100644
--- a/io/Versions
+++ b/io/Versions
@@ -136,6 +136,9 @@ libc {
     stat; stat64; fstat; fstat64; lstat; lstat64; fstatat; fstatat64;
     mknod; mknodat;
   }
+  GLIBC_2.34 {
+    closefrom;
+  }
   GLIBC_PRIVATE {
     __libc_fcntl64;
     __fcntl_nocancel;
diff --git a/io/closefrom.c b/io/closefrom.c
new file mode 100644
index 0000000000..01660a7531
--- /dev/null
+++ b/io/closefrom.c
@@ -0,0 +1,34 @@
+/* Close a range of file descriptors.
+   Copyright (C) 2021 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>
+#include <not-cancel.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..d4c187073c
--- /dev/null
+++ b/io/tst-closefrom.c
@@ -0,0 +1,152 @@
+/* Smoke test for the closefrom.
+   Copyright (C) 2021 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
+open_multiple_temp_files (void)
+{
+  /* Check if the temporary file descriptor has no no gaps.  */
+  int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
+  for (int i = 1; i <= NFDS; i++)
+    TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), lowfd + i);
+  return lowfd;
+}
+
+static int
+closefrom_test (void)
+{
+  struct support_descriptors *descrs = support_descriptors_list ();
+
+  int lowfd = open_multiple_temp_files ();
+
+  const int maximum_fd = lowfd + NFDS;
+  const int half_fd = lowfd + NFDS / 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 (lowfd + 35);
+  xclose (lowfd + 38);
+  xclose (lowfd + 42);
+  xclose (lowfd + 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, 0600);
+  for (;;)
+    {
+      int fd = open ("/dev/null", O_RDONLY, 0600);
+      if (fd == -1)
+	{
+	  if (errno != EMFILE)
+	    FAIL_EXIT1 ("open: %m");
+	  break;
+	}
+      TEST_VERIFY_EXIT (fd < max_fd);
+    }
+
+  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 c1f54f4a8a..1cffe7bd74 100644
--- a/manual/llio.texi
+++ b/manual/llio.texi
@@ -325,6 +325,16 @@ The maximum number of file descriptors is controlled by the
 @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 larger than or equal
+to @var{lowfd} then @var{lowfd}.  This function is similar to call
+@code{close} applied to the specified file descriptor range.
+
+Already closed file descriptors are ignored.
+@end deftypefun
 
 @node I/O Primitives
 @section Input and Output Primitives
diff --git a/posix/unistd.h b/posix/unistd.h
index 3f22763379..cf47550497 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_MISC
+/* 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 e10a286d2e..b07d989f01 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2204,6 +2204,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 8cf908ac8d..083e6f12af 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -64,7 +64,8 @@ sysdep_routines += adjtimex clone umount umount2 readahead sysctl \
 		   time64-support pselect32 \
 		   xstat fxstat lxstat xstat64 fxstat64 lxstat64 \
 		   fxstatat fxstatat64 \
-		   xmknod xmknodat
+		   xmknod xmknodat \
+		   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 ba6112e28f..3dfa9a4aaa 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2173,3 +2173,4 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index d87677063e..6c70e66707 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2255,6 +2255,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 2ec383822c..314f8255ea 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1933,3 +1933,4 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 3df5df5436..ba5abe4cf8 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
@@ -157,6 +158,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 175dc3165c..e098657c94 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -154,6 +154,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/closefrom.c b/sysdeps/unix/sysv/linux/closefrom.c
new file mode 100644
index 0000000000..f5d7342c2c
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/closefrom.c
@@ -0,0 +1,35 @@
+/* Close a range of file descriptors.  Linux version.
+   Copyright (C) 2021 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..14331e848d
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/closefrom_fallback.c
@@ -0,0 +1,97 @@
+/* Close a range of file descriptors.  Linux version.
+   Copyright (C) 2021 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.  */
+      if (errno == ENOENT)
+	goto err;
+
+      for (int i = from; i < INT_MAX; i++)
+	{
+	  int r = __close_nocancel (i);
+	  if (r == 0 || (r == -1 && errno != EBADF))
+	    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;
+
+      /* If any file descriptor is closed it resets the /proc/self position
+	 read again from the start (to obtain any possible kernel update).  */
+      bool closed = false;
+      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;
+
+	  /* We ignore close errors because EBADF, EINTR, and EIO means the
+	     descriptor has been released.  */
+	  __close_nocancel (fd);
+	  closed = true;
+	}
+
+      if (closed && __lseek (dirfd, 0, SEEK_SET) < 0)
+	goto err;
+    }
+
+  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 cbb89a2dc0..a4cbaaad94 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2117,3 +2117,4 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index a0b43e9861..9de1867afc 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2076,6 +2076,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 24b7180311..fcf5b01c2a 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2243,6 +2243,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index ac26edbe34..3b799c442e 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2108,6 +2108,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 7ad5ce4421..5efd4b2b12 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
@@ -158,6 +159,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index ad3efc33bf..e217bf46bb 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2188,6 +2188,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 4bf921c5eb..aeb06619cd 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2168,3 +2168,4 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index c3db2009a2..624fb0932b 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
@@ -2165,3 +2166,4 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 74396aa313..9a99d8ec89 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2159,6 +2159,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 58bde27971..e065227ebc 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
@@ -2157,6 +2158,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 2e91d9f1df..d33486f7df 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2165,6 +2165,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 30eed1ac64..78fa717048 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2159,6 +2159,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index a05d72a10f..16df5c01e4 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2206,3 +2206,4 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index ccce71f5ac..7972650090 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2215,6 +2215,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index eb79b4acd5..9b73f7e289 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
@@ -2248,6 +2249,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 80b1c66f9d..57998bef13 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2078,6 +2078,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 0a82bbfc6f..ad3b8148a7 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2368,3 +2368,4 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 02db9c5967..de5a81bc0c 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -596,6 +596,7 @@ GLIBC_2.33 clock_settime F
 GLIBC_2.33 clone F
 GLIBC_2.33 close 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
@@ -1935,3 +1936,4 @@ GLIBC_2.33 writev F
 GLIBC_2.33 wscanf F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 0e0d0a88db..c4629ee6ef 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2135,3 +2135,4 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 5dfeadb8b9..01d1decb29 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2213,6 +2213,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index fd951e93ce..e10f2c4750 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2114,6 +2114,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 19b23cf363..0b3185c7ab 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
@@ -2083,6 +2084,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 70956fc56d..6b4a6e22b0 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2080,6 +2080,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 537e27fb83..f5f8ac70dc 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2204,6 +2204,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 056a51ba88..c2120f08f8 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2131,6 +2131,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 84903475e4..522f974655 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2090,6 +2090,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 303106af6a..b48f2c11bd 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2187,3 +2187,4 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
+GLIBC_2.34 closefrom F
-- 
2.25.1


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

* [PATCH v4 5/5] posix: Add posix_spawn_file_actions_closefrom_np
  2021-03-10 15:26 [PATCH v4 1/5] support: Add support_stack_alloc Adhemerval Zanella
                   ` (2 preceding siblings ...)
  2021-03-10 15:26 ` [PATCH v4 4/5] io: Add closefrom [BZ #10353] Adhemerval Zanella
@ 2021-03-10 15:26 ` Adhemerval Zanella
  2021-03-10 16:10 ` [PATCH v4 1/5] support: Add support_stack_alloc Florian Weimer
  4 siblings, 0 replies; 12+ messages in thread
From: Adhemerval Zanella @ 2021-03-10 15:26 UTC (permalink / raw)
  To: libc-alpha

Changes from previous version:

  - Fixed commit title and message.
  - Fixed manual.
  - Fixed the glibc version and copyright year for newer files.
  - Renamed spawn_int_abi.h to spawn_int_def.h.

---

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 function posix_spawn_file_actions_closefrom_np is safe to be
implemented by iterating 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 +
 include/unistd.h                              |   2 +-
 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                            | 284 ++++++++++++++++++
 sysdeps/generic/spawn_int_def.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/closefrom.c           |   3 +-
 sysdeps/unix/sysv/linux/closefrom_fallback.c  |   8 +-
 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_def.h       |  25 ++
 sysdeps/unix/sysv/linux/spawni.c              |  34 ++-
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
 49 files changed, 484 insertions(+), 21 deletions(-)
 create mode 100644 posix/spawn_faction_addclosefrom.c
 create mode 100644 posix/tst-spawn5.c
 create mode 100644 sysdeps/generic/spawn_int_def.h
 create mode 100644 sysdeps/unix/sysv/linux/spawn_int_def.h

diff --git a/NEWS b/NEWS
index 0c7bc74cca..3b759d5145 100644
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,11 @@ Major new features:
 * On Linux, the close_range function has been added.  It allows efficiently
   closing a range of file descriptors on recent kernels (version 5.9).
 
+* The posix_spawn_file_actions_closefrom_np function has been added, enabling
+  posix_spawn and posix_spawnp to close all file descriptors great than or
+  equal to 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:
 
   [Add deprecations, removals and changes affecting compatibility here]
diff --git a/include/unistd.h b/include/unistd.h
index d48ad6c799..a1e9d47cb8 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -153,7 +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 _Bool __closefrom_fallback (int __lowfd, _Bool) 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/posix/Makefile b/posix/Makefile
index 305ec757cd..e3d1395c84 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				      \
@@ -103,7 +104,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
 
 # Test for the glob symbol version that was replaced in glibc 2.27.
 ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes)
@@ -270,6 +271,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 cfd3819966..6524a8c564 100644
--- a/posix/Versions
+++ b/posix/Versions
@@ -147,6 +147,9 @@ libc {
   }
   GLIBC_2.30 {
   }
+  GLIBC_2.34 {
+    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 a29da028cc..990d8a6ba2 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 or equal to 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..ff35b0519b
--- /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) 2021 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 7776f1a462..1a01b8e80e 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 c579cb981d..81d43f2fa3 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_def.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..1e67d071b4
--- /dev/null
+++ b/posix/tst-spawn5.c
@@ -0,0 +1,284 @@
+/* Tests for posix_spawn signal handling.
+   Copyright (C) 2021 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, plus
+   the extra '--direct' and '--restart', and a final NULL.  */
+static char *initial_argv[7];
+
+#define CMDLINE_OPTIONS \
+  { "restart", no_argument, &restart, 1 },
+
+#define NFDS 100
+
+static int
+open_multiple_temp_files (void)
+{
+  /* Check if the temporary file descriptor has no no gaps.  */
+  int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
+  for (int i = 1; i <= NFDS; i++)
+    TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600),
+		  lowfd + i);
+  return lowfd;
+}
+
+/* Called on process re-execution.  The arguments are the expected opened
+   file descriptors.  */
+_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 unsigned int fd = strtoul (argv[i+1], &endptr, 10);
+      if (*endptr != '\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 opened", 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 = open_multiple_temp_files ();
+  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 (lowfd + 57);
+  xclose (lowfd + 78);
+  xclose (lowfd + 81);
+  xclose (lowfd + 82);
+  xclose (lowfd + 84);
+  xclose (lowfd + 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_def.h b/sysdeps/generic/spawn_int_def.h
new file mode 100644
index 0000000000..ef6e03b1ef
--- /dev/null
+++ b/sysdeps/generic/spawn_int_def.h
@@ -0,0 +1,24 @@
+/* Internal definitions for posix_spawn functionality.  Generic version.
+   Copyright (C) 2021 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_DEF_H
+#define _SPAWN_INT_DEF_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 b07d989f01..e7c51bce5a 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2205,6 +2205,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/mach/hurd/spawni.c b/sysdeps/mach/hurd/spawni.c
index 9bc1571c29..002c934db9 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 a649788668..75dedaca56 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 3dfa9a4aaa..ff4ec2008f 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2174,3 +2174,4 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 6c70e66707..b5eb5fbe16 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2256,6 +2256,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 314f8255ea..5827e833da 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1934,3 +1934,4 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index ba5abe4cf8..af0cac9f70 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -159,6 +159,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index e098657c94..84fbcab235 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -155,6 +155,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/closefrom.c b/sysdeps/unix/sysv/linux/closefrom.c
index f5d7342c2c..372896b775 100644
--- a/sysdeps/unix/sysv/linux/closefrom.c
+++ b/sysdeps/unix/sysv/linux/closefrom.c
@@ -16,6 +16,7 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <sys/param.h>
 #include <unistd.h>
@@ -29,7 +30,7 @@ __closefrom (int lowfd)
   if (r == 0)
     return;
 
-  if (!__closefrom_fallback (l))
+  if (!__closefrom_fallback (l, true))
     __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
index 14331e848d..9226cc0ed0 100644
--- a/sysdeps/unix/sysv/linux/closefrom_fallback.c
+++ b/sysdeps/unix/sysv/linux/closefrom_fallback.c
@@ -22,9 +22,11 @@
 #include <stdbool.h>
 
 /* Fallback code: iterates over /proc/self/fd, closing each file descriptor
-   that fall on the criteria.  */
+   that fall on the criteria.  If DIRFD_FALLBACK is set, a failure on
+   /proc/self/fd open will trigger a fallback that tries to close a file
+   descriptor before proceed.  */
 _Bool
-__closefrom_fallback (int from)
+__closefrom_fallback (int from, _Bool dirfd_fallback)
 {
   bool ret = false;
 
@@ -33,7 +35,7 @@ __closefrom_fallback (int from)
   if (dirfd == -1)
     {
       /* The closefrom should work even when process can't open new files.  */
-      if (errno == ENOENT)
+      if (errno == ENOENT || !dirfd_fallback)
 	goto err;
 
       for (int i = from; i < INT_MAX; i++)
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index a4cbaaad94..30781d837d 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2118,3 +2118,4 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 9de1867afc..5e172924c2 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2077,6 +2077,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index fcf5b01c2a..d40243d549 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2244,6 +2244,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 3b799c442e..ab077591eb 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2109,6 +2109,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 5efd4b2b12..94f085cecc 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -160,6 +160,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index e217bf46bb..b92ad70bff 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2189,6 +2189,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index aeb06619cd..4f85e2db4f 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2169,3 +2169,4 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 624fb0932b..6159773934 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2167,3 +2167,4 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 9a99d8ec89..d39773d3de 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2160,6 +2160,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 e065227ebc..f3affaa2fb 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2159,6 +2159,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 d33486f7df..9030cabcd8 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2166,6 +2166,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 78fa717048..ca846a6676 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2160,6 +2160,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 16df5c01e4..215ade1218 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2207,3 +2207,4 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 7972650090..d7588a8ad9 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2216,6 +2216,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 9b73f7e289..29a87092dd 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2250,6 +2250,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 57998bef13..50a640607d 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2079,6 +2079,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index ad3b8148a7..ab68eb3c40 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2369,3 +2369,4 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index de5a81bc0c..8418f808bc 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -1937,3 +1937,4 @@ GLIBC_2.33 wscanf F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index c4629ee6ef..de94a162b5 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2136,3 +2136,4 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 01d1decb29..f5a7e231bb 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2214,6 +2214,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index e10f2c4750..de7961b9ed 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2115,6 +2115,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 0b3185c7ab..6e37ca2f6e 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2085,6 +2085,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 6b4a6e22b0..d9c91c3114 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2081,6 +2081,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index f5f8ac70dc..e8ee4489b7 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2205,6 +2205,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index c2120f08f8..5a10b033ab 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2132,6 +2132,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/spawn_int_def.h b/sysdeps/unix/sysv/linux/spawn_int_def.h
new file mode 100644
index 0000000000..3be65b5711
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/spawn_int_def.h
@@ -0,0 +1,25 @@
+/* Internal definitions for posix_spawn functionality.  Linux version.
+   Copyright (C) 2021 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_DEF_H
+#define _SPAWN_INT_DEF_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 b53b81b8fc..b5ed170998 100644
--- a/sysdeps/unix/sysv/linux/spawni.c
+++ b/sysdeps/unix/sysv/linux/spawni.c
@@ -16,22 +16,16 @@
    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 <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 +274,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, false))
+		  goto fail;
+	      } break;
 	    }
 	}
     }
@@ -344,7 +346,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 522f974655..0ebb212eef 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2091,6 +2091,7 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 b48f2c11bd..2a80e15367 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2188,3 +2188,4 @@ GLIBC_2.33 stat64 F
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 close_range F
 GLIBC_2.34 closefrom F
+GLIBC_2.34 posix_spawn_file_actions_addclosefrom_np F
-- 
2.25.1


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

* Re: [PATCH v4 1/5] support: Add support_stack_alloc
  2021-03-10 15:26 [PATCH v4 1/5] support: Add support_stack_alloc Adhemerval Zanella
                   ` (3 preceding siblings ...)
  2021-03-10 15:26 ` [PATCH v4 5/5] posix: Add posix_spawn_file_actions_closefrom_np Adhemerval Zanella
@ 2021-03-10 16:10 ` Florian Weimer
  2021-03-12 13:24   ` Adhemerval Zanella
  4 siblings, 1 reply; 12+ messages in thread
From: Florian Weimer @ 2021-03-10 16:10 UTC (permalink / raw)
  To: Adhemerval Zanella via Libc-alpha

* Adhemerval Zanella via Libc-alpha:

> +  /* Use MAP_NORESERVE so that RAM will not be wasted on the guard
> +     bands; touch all the pages of the actual stack before returning,
> +     so we know they are allocated.  */
> +  void *alloc_base = xmmap (0,
> +                            alloc_size,
> +                            PROT_READ|PROT_WRITE,
> +                            MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE|MAP_STACK,
> +                            -1);
> +  xmprotect (alloc_base, guardsize, PROT_NONE);
> +  xmprotect (alloc_base + guardsize + stacksize, guardsize, PROT_NONE);

The usual pattern is to map with PROT_NONE and then use
PROT_READ|PROT_WRITE with mprotect.

Rest looks okay, thanks.

Florian


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

* Re: [PATCH v4 4/5] io: Add closefrom [BZ #10353]
  2021-03-10 15:26 ` [PATCH v4 4/5] io: Add closefrom [BZ #10353] Adhemerval Zanella
@ 2021-03-10 21:54   ` Joseph Myers
  2021-03-11 11:24     ` Adhemerval Zanella
  0 siblings, 1 reply; 12+ messages in thread
From: Joseph Myers @ 2021-03-10 21:54 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

On Wed, 10 Mar 2021, Adhemerval Zanella via Libc-alpha wrote:

> diff --git a/NEWS b/NEWS
> index ff2b952a06..0c7bc74cca 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -91,6 +91,10 @@ Major new features:
>    The latest GCC available at this time (10.2) does not support this level of
>    fortification.
>  
> +* 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.

That's the NEWS section for 2.33.  This needs to go in the section for 
2.34.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [PATCH v4 4/5] io: Add closefrom [BZ #10353]
  2021-03-10 21:54   ` Joseph Myers
@ 2021-03-11 11:24     ` Adhemerval Zanella
  0 siblings, 0 replies; 12+ messages in thread
From: Adhemerval Zanella @ 2021-03-11 11:24 UTC (permalink / raw)
  To: Joseph Myers; +Cc: libc-alpha



On 10/03/2021 18:54, Joseph Myers wrote:
> On Wed, 10 Mar 2021, Adhemerval Zanella via Libc-alpha wrote:
> 
>> diff --git a/NEWS b/NEWS
>> index ff2b952a06..0c7bc74cca 100644
>> --- a/NEWS
>> +++ b/NEWS
>> @@ -91,6 +91,10 @@ Major new features:
>>    The latest GCC available at this time (10.2) does not support this level of
>>    fortification.
>>  
>> +* 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.
> 
> That's the NEWS section for 2.33.  This needs to go in the section for 
> 2.34.
> 

Ack.

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

* Re: [PATCH v4 1/5] support: Add support_stack_alloc
  2021-03-10 16:10 ` [PATCH v4 1/5] support: Add support_stack_alloc Florian Weimer
@ 2021-03-12 13:24   ` Adhemerval Zanella
  2021-03-12 13:35     ` Florian Weimer
  0 siblings, 1 reply; 12+ messages in thread
From: Adhemerval Zanella @ 2021-03-12 13:24 UTC (permalink / raw)
  To: Florian Weimer, Adhemerval Zanella via Libc-alpha



On 10/03/2021 13:10, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
> 
>> +  /* Use MAP_NORESERVE so that RAM will not be wasted on the guard
>> +     bands; touch all the pages of the actual stack before returning,
>> +     so we know they are allocated.  */
>> +  void *alloc_base = xmmap (0,
>> +                            alloc_size,
>> +                            PROT_READ|PROT_WRITE,
>> +                            MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE|MAP_STACK,
>> +                            -1);
>> +  xmprotect (alloc_base, guardsize, PROT_NONE);
>> +  xmprotect (alloc_base + guardsize + stacksize, guardsize, PROT_NONE);
> 
> The usual pattern is to map with PROT_NONE and then use
> PROT_READ|PROT_WRITE with mprotect.
> 
> Rest looks okay, thanks.
> 
> Florian
> 

Ok, I will fix it and push upstream.

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

* Re: [PATCH v4 1/5] support: Add support_stack_alloc
  2021-03-12 13:24   ` Adhemerval Zanella
@ 2021-03-12 13:35     ` Florian Weimer
  2021-03-12 14:01       ` Adhemerval Zanella
  0 siblings, 1 reply; 12+ messages in thread
From: Florian Weimer @ 2021-03-12 13:35 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: Adhemerval Zanella via Libc-alpha

* Adhemerval Zanella:

> On 10/03/2021 13:10, Florian Weimer wrote:
>> * Adhemerval Zanella via Libc-alpha:
>> 
>>> +  /* Use MAP_NORESERVE so that RAM will not be wasted on the guard
>>> +     bands; touch all the pages of the actual stack before returning,
>>> +     so we know they are allocated.  */
>>> +  void *alloc_base = xmmap (0,
>>> +                            alloc_size,
>>> +                            PROT_READ|PROT_WRITE,
>>> +                            MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE|MAP_STACK,
>>> +                            -1);
>>> +  xmprotect (alloc_base, guardsize, PROT_NONE);
>>> +  xmprotect (alloc_base + guardsize + stacksize, guardsize, PROT_NONE);
>> 
>> The usual pattern is to map with PROT_NONE and then use
>> PROT_READ|PROT_WRITE with mprotect.
>> 
>> Rest looks okay, thanks.
>> 
>> Florian
>> 
>
> Ok, I will fix it and push upstream.

Just to be clear, it avoids the need for MAP_NORESERVE.

Thanks,
Florian


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

* Re: [PATCH v4 1/5] support: Add support_stack_alloc
  2021-03-12 13:35     ` Florian Weimer
@ 2021-03-12 14:01       ` Adhemerval Zanella
  0 siblings, 0 replies; 12+ messages in thread
From: Adhemerval Zanella @ 2021-03-12 14:01 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Adhemerval Zanella via Libc-alpha



On 12/03/2021 10:35, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>> On 10/03/2021 13:10, Florian Weimer wrote:
>>> * Adhemerval Zanella via Libc-alpha:
>>>
>>>> +  /* Use MAP_NORESERVE so that RAM will not be wasted on the guard
>>>> +     bands; touch all the pages of the actual stack before returning,
>>>> +     so we know they are allocated.  */
>>>> +  void *alloc_base = xmmap (0,
>>>> +                            alloc_size,
>>>> +                            PROT_READ|PROT_WRITE,
>>>> +                            MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE|MAP_STACK,
>>>> +                            -1);
>>>> +  xmprotect (alloc_base, guardsize, PROT_NONE);
>>>> +  xmprotect (alloc_base + guardsize + stacksize, guardsize, PROT_NONE);
>>>
>>> The usual pattern is to map with PROT_NONE and then use
>>> PROT_READ|PROT_WRITE with mprotect.
>>>
>>> Rest looks okay, thanks.
>>>
>>> Florian
>>>
>>
>> Ok, I will fix it and push upstream.
> 
> Just to be clear, it avoids the need for MAP_NORESERVE.

Right, I will fix it.

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

* Re: [PATCH v4 3/5] Linux: Add close_range
  2021-03-10 15:26 ` [PATCH v4 3/5] Linux: Add close_range Adhemerval Zanella
@ 2021-03-24 22:42   ` Alyssa Ross
  0 siblings, 0 replies; 12+ messages in thread
From: Alyssa Ross @ 2021-03-24 22:42 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

[-- Attachment #1: Type: text/plain, Size: 2095 bytes --]

Adhemerval Zanella via Libc-alpha <libc-alpha@sourceware.org> writes:

> diff --git a/manual/llio.texi b/manual/llio.texi
> index c0a53e1a6e..c1f54f4a8a 100644
> --- a/manual/llio.texi
> +++ b/manual/llio.texi
> @@ -284,6 +284,48 @@ 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 emulation for
> +@c older kernels.
> +
> +The function @code{close_range} closes the file descriptor from @var{lowfd}
> +to @var{maxfd} (inclusive).  This function is similar to call @code{close} in
> +specified file descriptor range depending on the @var{flags}.
> +
> +This is function is only supportted on recent Linux versions and @theglibc{}

Typo here: "supportted"

> +does not provide any fallback (the application will need to handle possible
> +@code{ENOSYS}).
> +
> +The @var{flags} add options on how the files are closes.  Linux currently
> +supports:
> +
> +@vtable @code
> +@item CLOSE_RANGE_UNSHARE
> +Unshare the file descriptor table before closing file descriptors.
> +@end vtable
> +
> +The normal return value from @code{close_range} 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{flags}
> +is used.
> +
> +@item ENOMEM
> +Either there is not enough memory for the operation, or the process is
> +out of address space.
> +
> +@item EMFILE
> +The process has too many files open.
> +The maximum number of file descriptors is controlled by the
> +@end table
> +@end deftypefun
> +
> +
>  @node I/O Primitives
>  @section Input and Output Primitives

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

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

end of thread, other threads:[~2021-03-24 22:43 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-10 15:26 [PATCH v4 1/5] support: Add support_stack_alloc Adhemerval Zanella
2021-03-10 15:26 ` [PATCH v4 2/5] support: Add xclone Adhemerval Zanella
2021-03-10 15:26 ` [PATCH v4 3/5] Linux: Add close_range Adhemerval Zanella
2021-03-24 22:42   ` Alyssa Ross
2021-03-10 15:26 ` [PATCH v4 4/5] io: Add closefrom [BZ #10353] Adhemerval Zanella
2021-03-10 21:54   ` Joseph Myers
2021-03-11 11:24     ` Adhemerval Zanella
2021-03-10 15:26 ` [PATCH v4 5/5] posix: Add posix_spawn_file_actions_closefrom_np Adhemerval Zanella
2021-03-10 16:10 ` [PATCH v4 1/5] support: Add support_stack_alloc Florian Weimer
2021-03-12 13:24   ` Adhemerval Zanella
2021-03-12 13:35     ` Florian Weimer
2021-03-12 14:01       ` 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).