public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 1/3] Linux: Add close_range
@ 2020-12-21 21:50 Adhemerval Zanella
  2020-12-21 21:50 ` [PATCH 2/3] io: Add closefrom [BZ #10353] Adhemerval Zanella
                   ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Adhemerval Zanella @ 2020-12-21 21:50 UTC (permalink / raw)
  To: libc-alpha

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).

Similar to close, this is marked as a cancellation entrypoint.

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

Checked on x86_64-linux-gnu on kernel v5.9 and v5.4.
---
 NEWS                                          |   2 +
 include/bits/unistd_ext.h                     |   6 +
 sysdeps/unix/sysv/linux/Makefile              |  13 +-
 sysdeps/unix/sysv/linux/Versions              |   3 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/bits/unistd_ext.h     |  11 ++
 sysdeps/unix/sysv/linux/close_range.c         |  28 +++
 sysdeps/unix/sysv/linux/csky/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist     |   1 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
 .../sysv/linux/microblaze/be/libc.abilist     |   1 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist    |   1 +
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |   1 +
 .../unix/sysv/linux/s390/s390-32/libc.abilist |   1 +
 .../unix/sysv/linux/s390/s390-64/libc.abilist |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/tst-clone.h           |  48 +++++
 .../unix/sysv/linux/tst-close_range-consts.py |  49 +++++
 sysdeps/unix/sysv/linux/tst-close_range.c     | 175 ++++++++++++++++++
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
 35 files changed, 359 insertions(+), 2 deletions(-)
 create mode 100644 include/bits/unistd_ext.h
 create mode 100644 sysdeps/unix/sysv/linux/close_range.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-clone.h
 create mode 100644 sysdeps/unix/sysv/linux/tst-close_range-consts.py
 create mode 100644 sysdeps/unix/sysv/linux/tst-close_range.c

diff --git a/NEWS b/NEWS
index 0820984547..9e829841f6 100644
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,8 @@ Major new features:
   The 32-bit RISC-V port requires at least Linux 5.4, GCC 7.1 and binutils
   2.28.
 
+* On Linux, the close_range function has been added.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * The mallinfo function is marked deprecated.  Callers should call
diff --git a/include/bits/unistd_ext.h b/include/bits/unistd_ext.h
new file mode 100644
index 0000000000..277be05746
--- /dev/null
+++ b/include/bits/unistd_ext.h
@@ -0,0 +1,6 @@
+#include_next <bits/unistd_ext.h>
+
+#ifndef _ISOMAC
+extern int __close_range (unsigned int lowfd, unsigned int highfd, int flags);
+libc_hidden_proto (__close_range);
+#endif
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 09604e128b..e06c2a1f0d 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -61,7 +61,7 @@ sysdep_routines += adjtimex clone umount umount2 readahead sysctl \
 		   open_by_handle_at mlock2 pkey_mprotect pkey_set pkey_get \
 		   timerfd_gettime timerfd_settime prctl \
 		   process_vm_readv process_vm_writev clock_adjtime \
-		   time64-support pselect32
+		   time64-support pselect32 close_range
 
 CFLAGS-gethostid.c = -fexceptions
 CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables
@@ -103,7 +103,8 @@ tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \
 	 tst-quota tst-sync_file_range tst-sysconf-iov_max tst-ttyname \
 	 test-errno-linux tst-memfd_create tst-mlock2 tst-pkey \
 	 tst-rlimit-infinity tst-ofdlocks tst-gettid tst-gettid-kill \
-	 tst-tgkill tst-sysvsem-linux tst-sysvmsg-linux tst-sysvshm-linux
+	 tst-tgkill tst-sysvsem-linux tst-sysvmsg-linux tst-sysvshm-linux \
+	 tst-close_range
 tests-internal += tst-ofdlocks-compat tst-sigcontext-get_pc
 
 CFLAGS-tst-sigcontext-get_pc.c = -fasynchronous-unwind-tables
@@ -177,6 +178,14 @@ $(objpfx)tst-mman-consts.out: ../sysdeps/unix/sysv/linux/tst-mman-consts.py
 	  < /dev/null > $@ 2>&1; $(evaluate-test)
 $(objpfx)tst-mman-consts.out: $(sysdeps-linux-python-deps)
 
+tests-special += $(objpfx)tst-close_range-consts.out
+$(objpfx)tst-close_range-consts.out: ../sysdeps/unix/sysv/linux/tst-close_range-consts.py
+	$(sysdeps-linux-python) \
+	../sysdeps/unix/sysv/linux/tst-close_range-consts.py \
+	    $(sysdeps-linux-python-cc) \
+	< /dev/null > $@ 2>&1; $(evaluate-test)
+$(objpfx)tst-close_range-consts.out: $(sysdeps-linux-python-deps)
+
 $(objpfx)tst-gettid: $(shared-thread-library)
 $(objpfx)tst-gettid-kill: $(shared-thread-library)
 $(objpfx)tst-tgkill: $(shared-thread-library)
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index c35f783e2a..e2a6fa763f 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -169,6 +169,9 @@ libc {
   }
   GLIBC_2.32 {
   }
+  GLIBC_2.33 {
+    close_range;
+  }
   GLIBC_PRIVATE {
     # functions used in other libraries
     __syscall_rt_sigqueueinfo;
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 4cc1c6a591..a52decb822 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2160,6 +2160,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 26ad9845e4..ed085c9b3c 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2242,6 +2242,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index bb9dfd4daf..88a17c2fdf 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1920,6 +1920,7 @@ GLIBC_2.32 wprintf F
 GLIBC_2.32 write F
 GLIBC_2.32 writev F
 GLIBC_2.32 wscanf F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 9ab3924888..a690962068 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -141,6 +141,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/bits/unistd_ext.h b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
index c315cc5cb8..799c59512c 100644
--- a/sysdeps/unix/sysv/linux/bits/unistd_ext.h
+++ b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
@@ -33,4 +33,15 @@
    not detached and has not been joined.  */
 extern __pid_t gettid (void) __THROW;
 
+/* Unshare the file descriptor table before closing file descriptors.  */
+#define CLOSE_RANGE_UNSHARE     (1U << 1)
+
+/* Close all file descriptors in the range FD up to MAX_FD.  The flag FLAGS
+   are define by the CLOSE_RANGE prefix.  This function behaves like close
+   on the range, but in a fail-safe where it will either fail and not close
+   any file descriptor or close all of them.  Returns 0 on successor or -1
+   for failure (and sets errno accordingly).  */
+extern int close_range (unsigned int __fd, unsigned int __max_fd,
+			int __flags) __THROW;
+
 #endif
diff --git a/sysdeps/unix/sysv/linux/close_range.c b/sysdeps/unix/sysv/linux/close_range.c
new file mode 100644
index 0000000000..a664e158ee
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/close_range.c
@@ -0,0 +1,28 @@
+/* Close a range of file descriptors.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <unistd.h>
+#include <sysdep.h>
+
+int
+__close_range (unsigned int lowfd, unsigned int highfd, int flags)
+{
+  return SYSCALL_CANCEL (close_range, lowfd, highfd, flags);
+}
+libc_hidden_def (__close_range)
+weak_alias (__close_range, close_range)
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 14a84dac8f..d37882413c 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2104,6 +2104,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 5c8502f3d3..61450e47d5 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2063,6 +2063,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 4f0d3c1eb5..672ff8a002 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2229,6 +2229,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index e3b345b803..53e53005e9 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2095,6 +2095,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index c4891479d3..cc0d93b381 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2175,6 +2175,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 143b0163b4..b4acf52c41 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2155,6 +2155,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index b2295f1937..fadbf99d4b 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2146,6 +2146,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index aa9c6a4dca..c456ebcea3 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2152,6 +2152,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 5939588ad5..5ed54e7c94 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2146,6 +2146,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 92556c4237..67b611ef6d 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2193,6 +2193,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 26c93dff05..ed0f239cd5 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2202,6 +2202,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index c2ca00709e..a4b9900036 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2065,6 +2065,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 0ea50dc851..e5d666dab3 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2355,6 +2355,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 0263e284d4..f8c34aca7c 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -595,6 +595,7 @@ GLIBC_2.33 clock_nanosleep F
 GLIBC_2.33 clock_settime F
 GLIBC_2.33 clone F
 GLIBC_2.33 close F
+GLIBC_2.33 close_range F
 GLIBC_2.33 closedir F
 GLIBC_2.33 closelog F
 GLIBC_2.33 confstr F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 1626c5351f..6042d42aba 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2122,6 +2122,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index a66426eb4d..46d2de3030 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2200,6 +2200,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index ab351873ae..9fda4babba 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2101,6 +2101,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index d36f228192..110f7ebf22 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2067,6 +2067,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 59b4313280..1b31685a24 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2191,6 +2191,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 266dcdfa08..9ad88bf7b3 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2118,6 +2118,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/tst-clone.h b/sysdeps/unix/sysv/linux/tst-clone.h
new file mode 100644
index 0000000000..2344ac5101
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-clone.h
@@ -0,0 +1,48 @@
+/* Auxiliary wrapper to issue the clone symbol.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _TST_CLONE_H
+#define _TST_CLONE_H
+
+#include <sched.h>
+#include <stackinfo.h>  /* For _STACK_GROWS_{UP,DOWN}.  */
+
+#define DEFINE_STACK(name, size) \
+  char name[size] __attribute__ ((aligned))
+
+static inline pid_t
+clone_call (int (*fn) (void *arg), void *arg, void *stack, size_t stack_size,
+	    int flags)
+{
+#ifdef __ia64__
+  extern int __clone2 (int (*fn) (void *arg), void *stack, size_t stack_size,
+		       int flags, void *arg, ...);
+  return __clone2 (f, stack, stack_size, flags, arg, /* ptid */ NULL,
+		   /* tls */ NULL, /* ctid  */ ctid);
+#else
+# if _STACK_GROWS_DOWN
+  return clone (fn, stack + stack_size, flags, arg, /* ptid */ NULL,
+	        /* tls */ NULL, /* ctid */  NULL);
+# elif _STACK_GROWS_UP
+  return clone (fn, stack, flags, arg, /* ptid */ NULL, /* tls */ NULL,
+	        &ctid);
+# endif
+#endif
+}
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/tst-close_range-consts.py b/sysdeps/unix/sysv/linux/tst-close_range-consts.py
new file mode 100644
index 0000000000..3a0d4423e8
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-close_range-consts.py
@@ -0,0 +1,49 @@
+#!/usr/bin/python3
+# Test that glibc's unistd_ext.h constants match the kernel's.
+# Copyright (C) 2020 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <https://www.gnu.org/licenses/>.
+
+import argparse
+import sys
+
+import glibcextract
+import glibcsyscalls
+
+
+def main():
+    """The main entry point."""
+    parser = argparse.ArgumentParser(
+        description="Test that glibc's unistd_ext.h constants match "
+                    "the kernel's.")
+    parser.add_argument('--cc', metavar='CC',
+                        help='C compiler (including options) to use')
+    args = parser.parse_args()
+    linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
+    linux_version_glibc = (5, 9)
+    sys.exit(glibcextract.compare_macro_consts(
+        '#define _GNU_SOURCE 1\n'
+        '#include <unistd.h>\n',
+        '#define _GNU_SOURCE 1\n'
+        '#include <linux/close_range.h>\n',
+        args.cc,
+        'CLOSE_RANGE_.*',
+        None,
+        linux_version_glibc > linux_version_headers,
+        linux_version_headers > linux_version_glibc))
+
+if __name__ == '__main__':
+    main()
diff --git a/sysdeps/unix/sysv/linux/tst-close_range.c b/sysdeps/unix/sysv/linux/tst-close_range.c
new file mode 100644
index 0000000000..a685e7d359
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-close_range.c
@@ -0,0 +1,175 @@
+/* Test for the close_range system call.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/descriptors.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+
+#include <array_length.h>
+#include <tst-clone.h>
+
+static unsigned int
+first_invalid_flag (void)
+{
+  static const unsigned int flags[] = {
+    CLOSE_RANGE_UNSHARE,
+  };
+
+  unsigned int r = 1;
+  for (int i = 0; i < array_length (flags); i++)
+    if ((1U << r) & flags[i])
+      r++;
+  return 1U << r;
+}
+
+enum
+{
+  maximum_fd = 100,
+  half_fd = maximum_fd / 2,
+  gap_1 = maximum_fd - 8,
+  gap_0 = (maximum_fd * 3) / 4
+};
+
+static void
+close_range_test_common (int *fds, unsigned int flags)
+{
+  /* Basic test for invalid flags, bail out if unsupported.  */
+  TEST_COMPARE (close_range (fds[0], fds[half_fd], first_invalid_flag()), -1);
+  if (errno == ENOSYS)
+    FAIL_UNSUPPORTED ("close_range not supported");
+  TEST_COMPARE (errno, EINVAL);
+
+  /* Close half of the descriptors and check result.  */
+  TEST_COMPARE (close_range (fds[0], fds[half_fd], flags), 0);
+  for (int i = 0; i <= half_fd; i++)
+    {
+      TEST_COMPARE (fcntl (fds[i], F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  for (int i = half_fd + 1; i < maximum_fd; i++)
+    TEST_VERIFY (fcntl (fds[i], F_GETFL) > -1);
+
+  /* Create some gaps, close up to a threshold, and check result.  */
+  xclose (57);
+  xclose (78);
+  xclose (81);
+  xclose (82);
+  xclose (84);
+  xclose (90);
+
+  TEST_COMPARE (close_range (fds[half_fd + 1], fds[gap_1], flags), 0);
+  for (int i = half_fd + 1; i < gap_1; i++)
+    {
+      TEST_COMPARE (fcntl (fds[i], F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  for (int i = gap_1 + 1; i < maximum_fd; i++)
+    TEST_VERIFY (fcntl (fds[i], F_GETFL) > -1);
+
+  /* Close the remmaining but the last one.  */
+  TEST_COMPARE (close_range (fds[gap_1 + 1], fds[maximum_fd - 1], flags), 0);
+  for (int i = gap_1 + 1; i < maximum_fd - 1; i++)
+    {
+      TEST_COMPARE (fcntl (fds[i], F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  TEST_VERIFY (fcntl (fds[maximum_fd], F_GETFL) > -1);
+
+  /* Close the last one.  */
+  TEST_COMPARE (close_range (fds[maximum_fd], fds[maximum_fd], flags), 0);
+  TEST_COMPARE (fcntl (fds[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)
+{
+  int fds[maximum_fd + 1];
+
+  struct support_descriptors *descrs = support_descriptors_list ();
+
+  for (int i = 0; i < array_length (fds); i++)
+    fds[i] = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
+
+  close_range_test_common (fds, 0);
+
+  /* Double check by check the /proc.  */
+  support_descriptors_check (descrs);
+  support_descriptors_free (descrs);
+}
+
+static int
+close_range_unshare_test_fn (void *arg)
+{
+  close_range_test_common (arg, 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)
+{
+  int fds[maximum_fd + 1];
+
+  for (int i = 0; i < array_length (fds); i++)
+    fds[i] = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
+
+  struct support_descriptors *descrs = support_descriptors_list ();
+
+  enum { stack_size = 4096 };
+  DEFINE_STACK (stack, stack_size);
+  pid_t pid = clone_call (close_range_unshare_test_fn, fds, stack, stack_size,
+			  CLONE_FILES | SIGCHLD);
+  TEST_VERIFY_EXIT (pid > 0);
+  int status;
+  xwaitpid (pid, &status, 0);
+  TEST_VERIFY (WIFEXITED (status));
+  TEST_COMPARE (WEXITSTATUS(status), 0);
+
+  for (int i = 0; i < maximum_fd; i++)
+    TEST_VERIFY (fcntl (fds[i], F_GETFL) > -1);
+
+  support_descriptors_check (descrs);
+  support_descriptors_free (descrs);
+
+  TEST_COMPARE (close_range (fds[0], fds[maximum_fd], 0), 0);
+}
+
+static int
+do_test (void)
+{
+  close_range_test ();
+  close_range_unshare_test ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 4fff61818b..5089a21981 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2076,6 +2076,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 102ed47a9c..c3db0fc7ca 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2173,6 +2173,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 close_range F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
-- 
2.25.1


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

* [PATCH 2/3] io: Add closefrom [BZ #10353]
  2020-12-21 21:50 [PATCH 1/3] Linux: Add close_range Adhemerval Zanella
@ 2020-12-21 21:50 ` Adhemerval Zanella
  2020-12-22 10:49   ` Florian Weimer
  2020-12-21 21:50 ` [PATCH 3/3] posix: Add posix_spawn_file_actions_closefrom Adhemerval Zanella
  2020-12-22  9:05 ` [PATCH 1/3] Linux: Add close_range Florian Weimer
  2 siblings, 1 reply; 19+ messages in thread
From: Adhemerval Zanella @ 2020-12-21 21:50 UTC (permalink / raw)
  To: libc-alpha

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

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

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

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

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

[1] https://github.com/systemd/systemd/blob/5238e9575906297608ff802a27e2ff9effa3b338/src/basic/fd-util.c#L217
[2] https://github.com/lxc/lxc/blob/ddf4b77e11a4d08f09b7b9cd13e593f8c047edc5/src/lxc/start.c#L236
[3] https://github.com/python/cpython/blob/9e4f2f3a6b8ee995c365e86d976937c141d867f8/Modules/_posixsubprocess.c#L220
[4] https://github.com/rust-lang/rust/blob/5f47c0613ed4eb46fca3633c1297364c09e5e451/src/libstd/sys/unix/process2.rs#L303-L308
[5] https://github.com/openjdk/jdk/blob/master/src/java.base/unix/native/libjava/childproc.c#L82
---
 NEWS                                          |  4 +
 include/unistd.h                              |  1 +
 io/Makefile                                   |  5 +-
 io/Versions                                   |  1 +
 io/closefrom.c                                | 34 +++++++
 io/tst-closefrom.c                            | 94 +++++++++++++++++++
 posix/unistd.h                                |  8 ++
 sysdeps/mach/hurd/i386/libc.abilist           |  1 +
 sysdeps/unix/sysv/linux/Makefile              |  2 +-
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |  1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |  1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |  1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |  1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |  1 +
 sysdeps/unix/sysv/linux/closefrom.c           | 35 +++++++
 sysdeps/unix/sysv/linux/closefrom_fallback.c  | 74 +++++++++++++++
 sysdeps/unix/sysv/linux/csky/libc.abilist     |  1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |  1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |  1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist     |  1 +
 .../sysv/linux/m68k/coldfire/libc.abilist     |  1 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |  1 +
 .../sysv/linux/microblaze/be/libc.abilist     |  1 +
 .../sysv/linux/microblaze/le/libc.abilist     |  1 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |  1 +
 .../sysv/linux/mips/mips32/nofpu/libc.abilist |  1 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |  1 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |  1 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist    |  1 +
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |  1 +
 .../powerpc/powerpc32/nofpu/libc.abilist      |  1 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |  1 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |  1 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |  1 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |  1 +
 .../unix/sysv/linux/s390/s390-32/libc.abilist |  1 +
 .../unix/sysv/linux/s390/s390-64/libc.abilist |  1 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist    |  1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |  1 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |  1 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |  1 +
 .../unix/sysv/linux/x86_64/64/libc.abilist    |  1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |  1 +
 43 files changed, 288 insertions(+), 3 deletions(-)
 create mode 100644 io/closefrom.c
 create mode 100644 io/tst-closefrom.c
 create mode 100644 sysdeps/unix/sysv/linux/closefrom.c
 create mode 100644 sysdeps/unix/sysv/linux/closefrom_fallback.c

diff --git a/NEWS b/NEWS
index 9e829841f6..221eb4d98e 100644
--- a/NEWS
+++ b/NEWS
@@ -30,6 +30,10 @@ Major new features:
 
 * On Linux, the close_range function has been added.
 
+* The function closefrom has been adeed.  It closes all file descriptors
+  greater than given integer.  This function is a GNU extension, although it
+  also present in other systems.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * The mallinfo function is marked deprecated.  Callers should call
diff --git a/include/unistd.h b/include/unistd.h
index 54becbc9eb..d48ad6c799 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -153,6 +153,7 @@ extern int __brk (void *__addr) attribute_hidden;
 extern int __close (int __fd);
 libc_hidden_proto (__close)
 extern int __libc_close (int __fd);
+extern _Bool __closefrom_fallback (int __lowfd) attribute_hidden;
 extern ssize_t __read (int __fd, void *__buf, size_t __nbytes);
 libc_hidden_proto (__read)
 extern ssize_t __write (int __fd, const void *__buf, size_t __n);
diff --git a/io/Makefile b/io/Makefile
index 33f5b0b867..56a788c2d5 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -55,7 +55,8 @@ routines :=								\
 	posix_fadvise posix_fadvise64					\
 	posix_fallocate posix_fallocate64				\
 	sendfile sendfile64 copy_file_range 				\
-	utimensat futimens file_change_detection
+	utimensat futimens file_change_detection			\
+	closefrom
 
 others		:= pwd
 test-srcs	:= ftwtest
@@ -69,7 +70,7 @@ tests		:= test-utime test-stat test-stat2 test-lfs tst-getcwd \
 		   tst-fts tst-fts-lfs tst-open-tmpfile \
 		   tst-copy_file_range tst-getcwd-abspath tst-lockf \
 		   tst-ftw-lnk tst-file_change_detection tst-lchmod \
-		   tst-ftw-bz26353
+		   tst-ftw-bz26353 tst-closefrom
 
 # Likewise for statx, but we do not need static linking here.
 tests-internal += tst-statx
diff --git a/io/Versions b/io/Versions
index 49c4d2d40a..fa33452881 100644
--- a/io/Versions
+++ b/io/Versions
@@ -135,6 +135,7 @@ libc {
   GLIBC_2.33 {
     stat; stat64; fstat; fstat64; lstat; lstat64; fstatat; fstatat64;
     mknod; mknodat;
+    closefrom;
   }
   GLIBC_PRIVATE {
     __libc_fcntl64;
diff --git a/io/closefrom.c b/io/closefrom.c
new file mode 100644
index 0000000000..7e8f5a1ce5
--- /dev/null
+++ b/io/closefrom.c
@@ -0,0 +1,34 @@
+/* Close a range of file descriptors.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <unistd.h>
+
+void
+__closefrom (int lowfd)
+{
+  int maxfd = __getdtablesize ();
+  if (maxfd == -1)
+    __fortify_fail ("closefrom failed to get the file descriptor table size");
+
+  for (int i = 0; i < maxfd; i++)
+    if (i >= lowfd)
+      if (__close (i) == -1)
+        __fortify_fail ("closefrom failed to close a file descriptor");
+}
+weak_alias (__closefrom, closefrom)
diff --git a/io/tst-closefrom.c b/io/tst-closefrom.c
new file mode 100644
index 0000000000..6eb97cec10
--- /dev/null
+++ b/io/tst-closefrom.c
@@ -0,0 +1,94 @@
+/* Smoke test for the closefrom.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <support/check.h>
+#include <support/descriptors.h>
+#include <support/xunistd.h>
+
+#include <array_length.h>
+
+static int
+do_test (void)
+{
+  enum
+  {
+    maximum_fd = 100,
+    half_fd = maximum_fd / 2,
+    gap = maximum_fd / 4
+  };
+
+  int fds[maximum_fd + 1];
+
+  struct support_descriptors *descrs = support_descriptors_list ();
+
+  for (int i = 0; i < array_length (fds); i++)
+    fds[i] = xopen ("/dev/null", O_RDONLY | O_CLOEXEC, 0600);
+
+  /* Close half of the descriptors and check result.  */
+  closefrom (fds[half_fd]);
+
+  for (int i = half_fd; i <= maximum_fd; i++)
+    {
+      TEST_COMPARE (fcntl (fds[i], F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  for (int i = 0; i < half_fd; i++)
+    TEST_VERIFY (fcntl (fds[i], F_GETFL) > -1);
+
+  /* Create some gaps, close up to a threshold, and check result.  */
+  xclose (35);
+  xclose (38);
+  xclose (42);
+  xclose (46);
+
+  /* Close half of the descriptors and check result.  */
+  closefrom (fds[gap]);
+  for (int i = gap + 1; i < maximum_fd; i++)
+    {
+      TEST_COMPARE (fcntl (fds[i], F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  for (int i = 0; i < gap; i++)
+    TEST_VERIFY (fcntl (fds[i], F_GETFL) > -1);
+
+  /* Close the remmaining but the last one.  */
+  closefrom (fds[1]);
+  for (int i = 1; i <= maximum_fd; i++)
+    {
+      TEST_COMPARE (fcntl (fds[i], F_GETFL), -1);
+      TEST_COMPARE (errno, EBADF);
+    }
+  TEST_VERIFY (fcntl (fds[0], F_GETFL) > -1);
+
+  /* Close the last one.  */
+  closefrom (fds[0]);
+  TEST_COMPARE (fcntl (fds[0], F_GETFL), -1);
+  TEST_COMPARE (errno, EBADF);
+
+  /* Double check by check the /proc.  */
+  support_descriptors_check (descrs);
+  support_descriptors_free (descrs);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/posix/unistd.h b/posix/unistd.h
index 32b8161619..43ddd516aa 100644
--- a/posix/unistd.h
+++ b/posix/unistd.h
@@ -352,6 +352,14 @@ extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence)
    __THROW.  */
 extern int close (int __fd);
 
+#ifdef __USE_GNU
+/* Close all open file descriptors greater than or equal to LOWFD.
+   Negative LOWFD is clamped to 0.
+
+   Similar to close, this functions is a cancellation point.  */
+extern void closefrom (int __lowfd);
+#endif
+
 /* Read NBYTES into BUF from FD.  Return the
    number read, -1 for errors or 0 for EOF.
 
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index 7a5eb66b85..fce67cf3ca 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2191,6 +2191,7 @@ GLIBC_2.32 thrd_current F
 GLIBC_2.32 thrd_equal F
 GLIBC_2.32 thrd_sleep F
 GLIBC_2.32 thrd_yield F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index e06c2a1f0d..59ee6b5b5a 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -61,7 +61,7 @@ sysdep_routines += adjtimex clone umount umount2 readahead sysctl \
 		   open_by_handle_at mlock2 pkey_mprotect pkey_set pkey_get \
 		   timerfd_gettime timerfd_settime prctl \
 		   process_vm_readv process_vm_writev clock_adjtime \
-		   time64-support pselect32 close_range
+		   time64-support pselect32 close_range closefrom_fallback
 
 CFLAGS-gethostid.c = -fexceptions
 CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index a52decb822..811d3b3cd9 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2161,6 +2161,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index ed085c9b3c..d0bc011811 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2243,6 +2243,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 88a17c2fdf..c4e26b3cf6 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1921,6 +1921,7 @@ GLIBC_2.32 write F
 GLIBC_2.32 writev F
 GLIBC_2.32 wscanf F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 3b0a47e967..5ccd1fb07f 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -144,6 +144,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index a690962068..5043e483b8 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -142,6 +142,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/closefrom.c b/sysdeps/unix/sysv/linux/closefrom.c
new file mode 100644
index 0000000000..ba98fccd39
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/closefrom.c
@@ -0,0 +1,35 @@
+/* Close a range of file descriptors.  Linux version.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+void
+__closefrom (int lowfd)
+{
+  int l = MAX (0, lowfd);
+
+  int r = __close_range (l, ~0U, 0);
+  if (r == 0)
+    return;
+
+  if (!__closefrom_fallback (l))
+    __fortify_fail ("closefrom failed to close a file descriptor");
+}
+weak_alias (__closefrom, closefrom)
diff --git a/sysdeps/unix/sysv/linux/closefrom_fallback.c b/sysdeps/unix/sysv/linux/closefrom_fallback.c
new file mode 100644
index 0000000000..48815941dd
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/closefrom_fallback.c
@@ -0,0 +1,74 @@
+/* Close a range of file descriptors.  Linux version.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <arch-fd_to_filename.h>
+#include <dirent.h>
+#include <not-cancel.h>
+#include <stdbool.h>
+
+/* Fallback code: iterates over /proc/self/fd, closing each file descriptor
+   that fall on the criteria.  */
+_Bool
+__closefrom_fallback (int from)
+{
+  int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY,
+			       0);
+  if (dirfd == -1)
+    return false;
+
+  enum { buffer_size = 1024 };
+  char buffer[buffer_size];
+  bool ret = true;
+
+  while (true)
+    {
+      ssize_t ret = __getdents64 (dirfd, buffer, sizeof (buffer));
+      if (ret == -1)
+        goto err;
+      else if (ret == 0)
+        break;
+
+      char *begin = buffer, *end = buffer + ret;
+      while (begin != end)
+	{
+          unsigned short int d_reclen;
+	  memcpy (&d_reclen, begin + offsetof (struct dirent64, d_reclen),
+		  sizeof (d_reclen));
+	  const char *dname = begin + offsetof (struct dirent64, d_name);
+	  begin += d_reclen;
+
+	  if (dname[0] == '.')
+	    continue;
+
+	  int fd = 0;
+	  for (const char *s = dname; (unsigned int) (*s) - '0' < 10; s++)
+	    fd = 10 * fd + (*s - '0');
+
+	  if (fd == dirfd || fd < from)
+	    continue;
+
+	  if (__close_nocancel (fd) < 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 d37882413c..6f3718cd14 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2105,6 +2105,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 61450e47d5..84b474dba4 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2064,6 +2064,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 672ff8a002..4c1399102e 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2230,6 +2230,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 53e53005e9..9fcaa40c34 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2096,6 +2096,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 25f2d1c08f..ccb780d9c7 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -145,6 +145,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index cc0d93b381..3afaa1c70e 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2176,6 +2176,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index b4acf52c41..266063d0e8 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2156,6 +2156,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 13d374a031..5d893ec4d1 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2152,6 +2152,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index fadbf99d4b..6207a15a09 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2147,6 +2147,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 4c786070d0..860e5fecfa 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2144,6 +2144,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index c456ebcea3..daed5ae2a8 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2153,6 +2153,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 5ed54e7c94..7b6edfe8f5 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2147,6 +2147,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 67b611ef6d..9dd7d64500 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2194,6 +2194,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index ed0f239cd5..c561e5cf36 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2203,6 +2203,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index f04b167788..d25bf75ed3 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2235,6 +2235,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index a4b9900036..248fab8212 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2066,6 +2066,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index e5d666dab3..d02fa6b3d2 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2356,6 +2356,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index f8c34aca7c..56d1a16b2a 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -597,6 +597,7 @@ GLIBC_2.33 clone F
 GLIBC_2.33 close F
 GLIBC_2.33 close_range F
 GLIBC_2.33 closedir F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 closelog F
 GLIBC_2.33 confstr F
 GLIBC_2.33 connect F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 6042d42aba..8fcd329728 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2123,6 +2123,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 46d2de3030..b06cc94710 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2201,6 +2201,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 9fda4babba..6ede1579ca 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2102,6 +2102,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 22ceaa3d87..0f426028a1 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2070,6 +2070,7 @@ GLIBC_2.32 sigabbrev_np F
 GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 110f7ebf22..8637b683d6 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2068,6 +2068,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 1b31685a24..dc7c01f734 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2192,6 +2192,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 9ad88bf7b3..67d361c881 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2119,6 +2119,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 5089a21981..94bb5a0fa7 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2077,6 +2077,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index c3db0fc7ca..e94ce733ab 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2174,6 +2174,7 @@ GLIBC_2.32 sigdescr_np F
 GLIBC_2.32 strerrordesc_np F
 GLIBC_2.32 strerrorname_np F
 GLIBC_2.33 close_range F
+GLIBC_2.33 closefrom F
 GLIBC_2.33 fstat F
 GLIBC_2.33 fstat64 F
 GLIBC_2.33 fstatat F
-- 
2.25.1


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

* [PATCH 3/3] posix: Add posix_spawn_file_actions_closefrom
  2020-12-21 21:50 [PATCH 1/3] Linux: Add close_range Adhemerval Zanella
  2020-12-21 21:50 ` [PATCH 2/3] io: Add closefrom [BZ #10353] Adhemerval Zanella
@ 2020-12-21 21:50 ` Adhemerval Zanella
  2020-12-22 11:32   ` Florian Weimer
  2020-12-22  9:05 ` [PATCH 1/3] Linux: Add close_range Florian Weimer
  2 siblings, 1 reply; 19+ messages in thread
From: Adhemerval Zanella @ 2020-12-21 21:50 UTC (permalink / raw)
  To: libc-alpha

This patch adds a way to close a range of file descriptors on posix_spawn
as a new file action.  The API is similar to the one provided by Solaris
11 [1], where the file action causes the all open file descriptors greater
than or equal to input on to be closed when the new process is spawned.

The posix_spawn is safe to be implemented by interacting over /proc/self/fd,
since the Linux spawni.c helper process does not use CLONE_FILES, so its has
own file descriptor table and any failure (in /proc operation) aborts the
process creation and returns an error to the caller.

I am aware that this file action might be redundant to the current approach
of POSIX in promoting O_CLOEXEC in more interfaces. However O_CLOEXEC is still
not the default and for some specific usages, the caller needs to close all
possible file descriptors to avoid them leaking.  Some examples are CPython
(discussed in BZ#10353) and OpenJDK jspawnhelper [2] (where OpenJDK spawns a
helper process to exactly closes all file descriptors).  Most likely any
environment which calls functions that might open file descriptor under the
hood and aim to use posix_spawn might face the same requirement.

Checked on x86_64-linux-gnu, i686-linux-gnu, powerpc64le-linux-gnu, and
aarch64-linux-gnu.

[1] https://docs.oracle.com/cd/E36784_01/html/E36874/posix-spawn-file-actions-addclosefrom-np-3c.html
[2] https://github.com/openjdk/jdk/blob/master/src/java.base/unix/native/libjava/childproc.c#L82
---
 NEWS                                          |   5 +
 posix/Makefile                                |   4 +-
 posix/Versions                                |   3 +
 posix/spawn.h                                 |   7 +
 posix/spawn_faction_addclosefrom.c            |  58 ++++
 posix/spawn_faction_destroy.c                 |   1 +
 posix/spawn_int.h                             |   6 +
 posix/spawn_int_abi.h                         |  27 ++
 posix/tst-spawn5.c                            | 279 ++++++++++++++++++
 sysdeps/generic/spawn_int_abi.h               |  24 ++
 sysdeps/mach/hurd/i386/libc.abilist           |   1 +
 sysdeps/mach/hurd/spawni.c                    |   4 +
 sysdeps/posix/spawni.c                        |   4 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/csky/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist     |   1 +
 .../sysv/linux/m68k/coldfire/libc.abilist     |   1 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
 .../sysv/linux/microblaze/be/libc.abilist     |   1 +
 .../sysv/linux/microblaze/le/libc.abilist     |   1 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
 .../sysv/linux/mips/mips32/nofpu/libc.abilist |   1 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist    |   1 +
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
 .../powerpc/powerpc32/nofpu/libc.abilist      |   1 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |   1 +
 .../unix/sysv/linux/s390/s390-32/libc.abilist |   1 +
 .../unix/sysv/linux/s390/s390-64/libc.abilist |   1 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/spawn_int_abi.h       |  25 ++
 sysdeps/unix/sysv/linux/spawni.c              |  36 ++-
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
 47 files changed, 500 insertions(+), 16 deletions(-)
 create mode 100644 posix/spawn_faction_addclosefrom.c
 create mode 100644 posix/spawn_int_abi.h
 create mode 100644 posix/tst-spawn5.c
 create mode 100644 sysdeps/generic/spawn_int_abi.h
 create mode 100644 sysdeps/unix/sysv/linux/spawn_int_abi.h

diff --git a/NEWS b/NEWS
index 221eb4d98e..f37864b926 100644
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,11 @@ Major new features:
   greater than given integer.  This function is a GNU extension, although it
   also present in other systems.
 
+* The posix_spawn_file_actions_closefrom_np has been added, enabling
+  posix_spawn and posix_spawnp to close all file descriptors greater than
+  a giver interger.  This function is a GNU extension, although Solaris also
+  provides a similar function.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * The mallinfo function is marked deprecated.  Callers should call
diff --git a/posix/Makefile b/posix/Makefile
index 4bfc8d942c..d40636547e 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -57,6 +57,7 @@ routines :=								      \
 	spawn_faction_init spawn_faction_destroy spawn_faction_addclose	      \
 	spawn_faction_addopen spawn_faction_adddup2 spawn_valid_fd	      \
 	spawn_faction_addchdir spawn_faction_addfchdir			      \
+	spawn_faction_addclosefrom					      \
 	spawnattr_init spawnattr_destroy				      \
 	spawnattr_getdefault spawnattr_setdefault			      \
 	spawnattr_getflags spawnattr_setflags				      \
@@ -102,7 +103,7 @@ tests		:= test-errno tstgetopt testfnm runtests runptests \
 		   tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \
 		   tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \
 		   bug-regex38 tst-regcomp-truncated tst-spawn-chdir \
-		   tst-wordexp-nocmd
+		   tst-wordexp-nocmd tst-spawn5
 tests-internal	:= bug-regex5 bug-regex20 bug-regex33 \
 		   tst-rfc3484 tst-rfc3484-2 tst-rfc3484-3 \
 		   tst-glob_lstat_compat tst-spawn4-compat
@@ -258,6 +259,7 @@ tst-exec-static-ARGS = $(tst-exec-ARGS)
 tst-execvpe5-ARGS = -- $(host-test-program-cmd)
 tst-spawn-ARGS = -- $(host-test-program-cmd)
 tst-spawn-static-ARGS = $(tst-spawn-ARGS)
+tst-spawn5-ARGS = -- $(host-test-program-cmd)
 tst-dir-ARGS = `pwd` `cd $(common-objdir)/$(subdir); pwd` `cd $(common-objdir); pwd` $(objpfx)tst-dir
 tst-chmod-ARGS = $(objdir)
 tst-vfork3-ARGS = --test-dir=$(objpfx)
diff --git a/posix/Versions b/posix/Versions
index 7d06a6d0c0..95d7b01126 100644
--- a/posix/Versions
+++ b/posix/Versions
@@ -147,6 +147,9 @@ libc {
   }
   GLIBC_2.30 {
   }
+  GLIBC_2.33 {
+    posix_spawn_file_actions_addclosefrom_np;
+  }
   GLIBC_PRIVATE {
     __libc_fork; __libc_pread; __libc_pwrite;
     __nanosleep_nocancel; __pause_nocancel;
diff --git a/posix/spawn.h b/posix/spawn.h
index be6bd591a3..21ea563425 100644
--- a/posix/spawn.h
+++ b/posix/spawn.h
@@ -213,6 +213,13 @@ extern int posix_spawn_file_actions_addchdir_np (posix_spawn_file_actions_t *
 extern int posix_spawn_file_actions_addfchdir_np (posix_spawn_file_actions_t *,
 						  int __fd)
      __THROW __nonnull ((1));
+
+/* Add an action to close all file descriptor greater than FROM during
+   spawn.  This affects the subsequent file actions.  */
+extern int posix_spawn_file_actions_addclosefrom_np (posix_spawn_file_actions_t *,
+						     int __from)
+     __THROW __nonnull ((1));
+
 #endif
 
 __END_DECLS
diff --git a/posix/spawn_faction_addclosefrom.c b/posix/spawn_faction_addclosefrom.c
new file mode 100644
index 0000000000..3a295580bc
--- /dev/null
+++ b/posix/spawn_faction_addclosefrom.c
@@ -0,0 +1,58 @@
+/* Add a closefrom to a file action list for posix_spawn.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <spawn.h>
+#include <unistd.h>
+#include <spawn_int.h>
+
+int
+__posix_spawn_file_actions_addclosefrom (posix_spawn_file_actions_t
+					 *file_actions, int from)
+{
+#if __SPAWN_SUPPORT_CLOSEFROM
+  struct __spawn_action *rec;
+
+  if (!__spawn_valid_fd (from))
+    return EBADF;
+
+  /* Allocate more memory if needed.  */
+  if (file_actions->__used == file_actions->__allocated
+      && __posix_spawn_file_actions_realloc (file_actions) != 0)
+    /* This can only mean we ran out of memory.  */
+    return ENOMEM;
+
+  /* Add the new value.  */
+  rec = &file_actions->__actions[file_actions->__used];
+  rec->tag = spawn_do_closefrom;
+  rec->action.closefrom_action.from = from;
+
+  /* Account for the new entry.  */
+  ++file_actions->__used;
+
+  return 0;
+#else
+  __set_errno (EINVAL);
+  return -1;
+#endif
+}
+weak_alias (__posix_spawn_file_actions_addclosefrom,
+	    posix_spawn_file_actions_addclosefrom_np)
+#if !__SPAWN_SUPPORT_CLOSEFROM
+stub_warning (posix_spawn_file_actions_addclosefrom_np)
+#endif
diff --git a/posix/spawn_faction_destroy.c b/posix/spawn_faction_destroy.c
index 098385e1e0..33045e2c7f 100644
--- a/posix/spawn_faction_destroy.c
+++ b/posix/spawn_faction_destroy.c
@@ -39,6 +39,7 @@ __posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions)
 	case spawn_do_close:
 	case spawn_do_dup2:
 	case spawn_do_fchdir:
+	case spawn_do_closefrom:
 	  /* No cleanup required.  */
 	  break;
 	}
diff --git a/posix/spawn_int.h b/posix/spawn_int.h
index 9be54c0416..512dcea0da 100644
--- a/posix/spawn_int.h
+++ b/posix/spawn_int.h
@@ -20,6 +20,7 @@
 #define _SPAWN_INT_H
 
 #include <spawn.h>
+#include <spawn_int_abi.h>
 #include <stdbool.h>
 
 /* Data structure to contain the action information.  */
@@ -32,6 +33,7 @@ struct __spawn_action
     spawn_do_open,
     spawn_do_chdir,
     spawn_do_fchdir,
+    spawn_do_closefrom,
   } tag;
 
   union
@@ -60,6 +62,10 @@ struct __spawn_action
     {
       int fd;
     } fchdir_action;
+    struct
+    {
+      int from;
+    } closefrom_action;
   } action;
 };
 
diff --git a/posix/spawn_int_abi.h b/posix/spawn_int_abi.h
new file mode 100644
index 0000000000..5fda4d3442
--- /dev/null
+++ b/posix/spawn_int_abi.h
@@ -0,0 +1,27 @@
+/* Internal ABI specific for posix_spawn functionality.  Generic version.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _SPAWN_INT_ABI_H
+#define _SPAWN_INT_ABI_H
+
+/* The closefrom file actions requires either a syscall or an arch-specific
+   way to interact over all file descriptors and act uppon them (such
+   /proc/self/fd on Linux).  */
+#define __SPAWN_SUPPOR_CLOSEFROM 0
+
+#endif /* _SPAWN_INT_H */
diff --git a/posix/tst-spawn5.c b/posix/tst-spawn5.c
new file mode 100644
index 0000000000..1f901d112b
--- /dev/null
+++ b/posix/tst-spawn5.c
@@ -0,0 +1,279 @@
+/* Tests for posix_spawn signal handling.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <spawn.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <support/support.h>
+
+#include <arch-fd_to_filename.h>
+#include <array_length.h>
+
+/* Nonzero if the program gets called via `exec'.  */
+static int restart;
+
+/* Hold the four initial argument used to respawn the process.  */
+static char *initial_argv[7];
+
+#define CMDLINE_OPTIONS \
+  { "restart", no_argument, &restart, 1 },
+
+enum
+{
+  maximum_fd = 100,
+  half_fd = maximum_fd / 2,
+};
+static int fds[maximum_fd + 1];
+
+
+/* Called on process re-execution.  */
+_Noreturn static void
+handle_restart (int argc, char *argv[])
+{
+  size_t nfds = argc > 1 ? argc - 1 : 0;
+  struct fd_t
+  {
+    int fd;
+    _Bool found;
+  } *fds = xmalloc (sizeof (struct fd_t) * nfds);
+  for (int i = 0; i < nfds; i++)
+    {
+      char *endptr;
+      long int fd = strtol (argv[i+1], &endptr, 10);
+      if (*endptr != '\0' || fd < 0 || fd > INT_MAX)
+        FAIL_EXIT1 ("readdir: invalid file descriptor value: %s", argv[i]);
+      fds[i].fd = fd;
+      fds[i].found = false;
+    }
+
+  DIR *dirp = opendir (FD_TO_FILENAME_PREFIX);
+  if (dirp == NULL)
+    FAIL_EXIT1 ("opendir (\"" FD_TO_FILENAME_PREFIX "\"): %m");
+
+  while (true)
+    {
+      errno = 0;
+      struct dirent64 *e = readdir64 (dirp);
+      if (e == NULL)
+        {
+          if (errno != 0)
+            FAIL_EXIT1 ("readdir: %m");
+          break;
+        }
+
+      if (e->d_name[0] == '.')
+        continue;
+
+      char *endptr;
+      long int fd = strtol (e->d_name, &endptr, 10);
+      if (*endptr != '\0' || fd < 0 || fd > INT_MAX)
+        FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s",
+                    e->d_name);
+
+      /* Skip the descriptor which is used to enumerate the descriptors.  */
+      if (fd == dirfd (dirp)
+          || fd == STDIN_FILENO
+	  || fd == STDOUT_FILENO
+	  || fd == STDERR_FILENO)
+        continue;
+
+      bool found = false;
+      for (int i = 0; i < nfds; i++)
+	if (fds[i].fd == fd)
+	  fds[i].found = found = true;
+
+      if (!found)
+        FAIL_EXIT1 ("unexpected open file descriptor: %ld", fd);
+    }
+  closedir (dirp);
+
+  for (int i = 0; i < nfds; i++)
+    if (!fds[i].found)
+      FAIL_EXIT1 ("file descriptor %d not closed", fds[i].fd);
+
+  free (fds);
+
+  exit (EXIT_SUCCESS);
+}
+
+static void
+spawn_closefrom_test (posix_spawn_file_actions_t *fa, int lowfd,
+		      int *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 * maximum_fd + 1 };
+  char *args[argv_size];
+  int argc = 0;
+
+  for (char **arg = initial_argv; *arg != NULL; arg++)
+    args[argc++] = *arg;
+
+  for (int i = 0; i < lowfd; i++)
+    args[argc++] = xasprintf ("%d", fds[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)
+{
+  for (int i = 0; i < array_length (fds); i++)
+    fds[i] = xopen ("/dev/null", O_WRONLY, 0);
+
+  /* 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, fds[half_fd]);
+    if (ret == -1 && errno == 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, half_fd, NULL, 0);
+
+    TEST_COMPARE (posix_spawn_file_actions_destroy (&fa), 0);
+  }
+
+  /* Create some gaps, close up to a threshold, and check result.  */
+  xclose (57);
+  xclose (78);
+  xclose (81);
+  xclose (82);
+  xclose (84);
+  xclose (90);
+
+  {
+    posix_spawn_file_actions_t fa;
+    TEST_COMPARE (posix_spawn_file_actions_init (&fa), 0);
+
+    TEST_COMPARE (posix_spawn_file_actions_addclosefrom_np (&fa,
+							    fds[half_fd]),
+		  0);
+
+    spawn_closefrom_test (&fa, half_fd, NULL, 0);
+
+    TEST_COMPARE (posix_spawn_file_actions_destroy (&fa), 0);
+  }
+
+  /* Close the remmaining 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, fds[1]), 0);
+
+    spawn_closefrom_test (&fa, 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, fds[0]), 0);
+
+    spawn_closefrom_test (&fa, 0, 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, fds[1]), 0);
+    TEST_COMPARE (posix_spawn_file_actions_addopen (&fa, fds[0], "/dev/null",
+						    0666, O_RDONLY), 0);
+    TEST_COMPARE (posix_spawn_file_actions_adddup2 (&fa, fds[0], fds[1]), 0);
+    TEST_COMPARE (posix_spawn_file_actions_addopen (&fa, fds[0], "/dev/null",
+						    0666, O_RDONLY), 0);
+
+    spawn_closefrom_test (&fa, 0, (int[]){fds[0], fds[1]}, 2);
+
+    TEST_COMPARE (posix_spawn_file_actions_destroy (&fa), 0);
+  }
+}
+
+
+static int
+do_test (int argc, char *argv[])
+{
+  /* We must have either:
+
+     - one or four parameters if called initially:
+       + argv[1]: path for ld.so        optional
+       + argv[2]: "--library-path"      optional
+       + argv[3]: the library path      optional
+       + argv[4]: the application name
+
+     - six parameters left if called through re-execution:
+       + argv[1]: the application name
+       + argv[2]: first expected open file descriptor
+       + argv[n]: last expected open file descritptor
+
+     * When built with --enable-hardcoded-path-in-tests or issued without
+       using the loader directly.  */
+
+  if (restart)
+    handle_restart (argc, argv);
+
+  initial_argv[0] = argv[1]; /* path for ld.so  */
+  initial_argv[1] = argv[2]; /* "--library-path"  */
+  initial_argv[2] = argv[3]; /* the library path  */
+  initial_argv[3] = argv[4]; /* the application name  */
+  initial_argv[4] = (char *) "--direct";
+  initial_argv[5] = (char *) "--restart";
+
+  do_test_closefrom ();
+
+  return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/sysdeps/generic/spawn_int_abi.h b/sysdeps/generic/spawn_int_abi.h
new file mode 100644
index 0000000000..bfc8961598
--- /dev/null
+++ b/sysdeps/generic/spawn_int_abi.h
@@ -0,0 +1,24 @@
+/* Internal ABI specific for posix_spawn functionality.  Generic version.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _SPAWN_INT_ABI_H
+#define _SPAWN_INT_ABI_H
+
+#define __SPAWN_SUPPORT_CLOSEFROM 0
+
+#endif /* _SPAWN_INT_H */
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index fce67cf3ca..5b23d62b5d 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2201,6 +2201,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/mach/hurd/spawni.c b/sysdeps/mach/hurd/spawni.c
index 178b271e4e..9ea4fc972f 100644
--- a/sysdeps/mach/hurd/spawni.c
+++ b/sysdeps/mach/hurd/spawni.c
@@ -600,6 +600,10 @@ __spawni (pid_t *pid, const char *file,
 	  case spawn_do_fchdir:
 	    err = child_fchdir (action->action.fchdir_action.fd);
 	    break;
+
+	  case spawn_do_closefrom:
+	    err = EINVAL;
+	    break;
 	  }
 
 	if (err)
diff --git a/sysdeps/posix/spawni.c b/sysdeps/posix/spawni.c
index 943a598771..d05d2c8520 100644
--- a/sysdeps/posix/spawni.c
+++ b/sysdeps/posix/spawni.c
@@ -231,6 +231,10 @@ __spawni_child (void *arguments)
 	      if (__fchdir (action->action.fchdir_action.fd) != 0)
 		goto fail;
 	      break;
+
+	    case spawn_do_closefrom:
+	      __set_errno (EINVAL);
+	      goto fail;
 	    }
 	}
     }
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 811d3b3cd9..65d5c3cee4 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2171,5 +2171,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index d0bc011811..ac55ceba70 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2253,6 +2253,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index c4e26b3cf6..24e623875d 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -1931,5 +1931,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 5ccd1fb07f..50086104ea 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -154,6 +154,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 _Exit F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 5043e483b8..a4ebfccc74 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -152,6 +152,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 _Exit F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 6f3718cd14..4b45f0a8a0 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2115,5 +2115,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 84b474dba4..b574604263 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2074,6 +2074,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 4c1399102e..51795cd925 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2240,6 +2240,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 9fcaa40c34..bafbc98f69 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2106,6 +2106,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index ccb780d9c7..8c3fc11399 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -155,6 +155,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 _Exit F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 3afaa1c70e..10a11773f2 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2186,6 +2186,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 266063d0e8..e908a7a19a 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2166,5 +2166,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 5d893ec4d1..d8f3ff6dec 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2162,5 +2162,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 6207a15a09..1c41ce7c83 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2157,6 +2157,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 860e5fecfa..dcec226837 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2154,6 +2154,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index daed5ae2a8..022a7ec721 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2163,6 +2163,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 7b6edfe8f5..a312612703 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2157,6 +2157,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 9dd7d64500..d4e4096a11 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2204,5 +2204,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index c561e5cf36..01705658c0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2213,6 +2213,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index d25bf75ed3..eea881eeae 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2245,6 +2245,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 248fab8212..bb346370ad 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2076,6 +2076,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index d02fa6b3d2..0dad53bc80 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2366,5 +2366,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 56d1a16b2a..7ee1f2e189 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -1304,6 +1304,7 @@ GLIBC_2.33 posix_openpt F
 GLIBC_2.33 posix_spawn F
 GLIBC_2.33 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.33 posix_spawn_file_actions_addclose F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 posix_spawn_file_actions_adddup2 F
 GLIBC_2.33 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.33 posix_spawn_file_actions_addopen F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 8fcd329728..51fc25677d 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2133,5 +2133,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index b06cc94710..61bda38fb0 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2211,6 +2211,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 6ede1579ca..a73bc16ae0 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2112,6 +2112,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 0f426028a1..974090f39b 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2080,6 +2080,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 8637b683d6..910c8e752d 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2078,6 +2078,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index dc7c01f734..fabbdaeef0 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2202,6 +2202,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 67d361c881..0ad7f0b18c 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2129,6 +2129,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/spawn_int_abi.h b/sysdeps/unix/sysv/linux/spawn_int_abi.h
new file mode 100644
index 0000000000..84b31104c5
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/spawn_int_abi.h
@@ -0,0 +1,25 @@
+/* Internal ABI specific for posix_spawn functionality.  Linux version.
+   Copyright (C) 2020 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _SPAWN_INT_ABI_H
+#define _SPAWN_INT_ABI_H
+
+/* spawni.c implements closefrom by interacting over /proc/self/fd.  */
+#define __SPAWN_SUPPORT_CLOSEFROM 1
+
+#endif /* _SPAWN_INT_H */
diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
index f157bfffd2..f496578d19 100644
--- a/sysdeps/unix/sysv/linux/spawni.c
+++ b/sysdeps/unix/sysv/linux/spawni.c
@@ -16,22 +16,17 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <spawn.h>
-#include <fcntl.h>
-#include <paths.h>
-#include <string.h>
-#include <sys/resource.h>
-#include <sys/wait.h>
-#include <sys/param.h>
-#include <sys/mman.h>
-#include <not-cancel.h>
+#include <arch-fd_to_filename.h>
+#include <internal-signals.h>
+#include <ldsodefs.h>
 #include <local-setxid.h>
+#include <not-cancel.h>
+#include <paths.h>
 #include <shlib-compat.h>
-#include <nptl/pthreadP.h>
-#include <dl-sysdep.h>
-#include <libc-pointer-arith.h>
-#include <ldsodefs.h>
-#include "spawn_int.h"
+#include <spawn.h>
+#include <spawn_int.h>
+#include <sysdep.h>
+#include <sys/resource.h>
 
 /* The Linux implementation of posix_spawn{p} uses the clone syscall directly
    with CLONE_VM and CLONE_VFORK flags and an allocated stack.  The new stack
@@ -280,6 +275,15 @@ __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;
+	        /* close_range is a cancellation entrypoint.  */
+	        int r = INLINE_SYSCALL_CALL (close_range, lowfd, ~0U, 0);
+		if (r != 0 && !__closefrom_fallback (lowfd))
+		  goto fail;
+	      } break;
 	    }
 	}
     }
@@ -344,7 +348,9 @@ __spawnix (pid_t * pid, const char *file,
   /* We need at least a few pages in case the compiler's stack checking is
      enabled.  In some configs, it is known to use at least 24KiB.  We use
      32KiB to be "safe" from anything the compiler might do.  Besides, the
-     extra pages won't actually be allocated unless they get used.  */
+     extra pages won't actually be allocated unless they get used.
+     It also acts the slack for spawn_closefrom (including MIPS64 getdents64
+     where it might use about 1k extra stack space.  */
   argv_size += (32 * 1024);
   size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize));
   void *stack = __mmap (NULL, stack_size, prot,
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 94bb5a0fa7..c17d5d93c3 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2087,6 +2087,7 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index e94ce733ab..e8ff4b7cc9 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2184,5 +2184,6 @@ GLIBC_2.33 lstat64 F
 GLIBC_2.33 mallinfo2 F
 GLIBC_2.33 mknod F
 GLIBC_2.33 mknodat F
+GLIBC_2.33 posix_spawn_file_actions_addclosefrom_np F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
-- 
2.25.1


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

* Re: [PATCH 1/3] Linux: Add close_range
  2020-12-21 21:50 [PATCH 1/3] Linux: Add close_range Adhemerval Zanella
  2020-12-21 21:50 ` [PATCH 2/3] io: Add closefrom [BZ #10353] Adhemerval Zanella
  2020-12-21 21:50 ` [PATCH 3/3] posix: Add posix_spawn_file_actions_closefrom Adhemerval Zanella
@ 2020-12-22  9:05 ` Florian Weimer
  2020-12-22 11:35   ` Adhemerval Zanella
  2 siblings, 1 reply; 19+ messages in thread
From: Florian Weimer @ 2020-12-22  9:05 UTC (permalink / raw)
  To: Adhemerval Zanella via Libc-alpha

* Adhemerval Zanella via Libc-alpha:

> 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/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile

Missing __THROW?  (But see below.)

> diff --git a/sysdeps/unix/sysv/linux/bits/unistd_ext.h b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
> index c315cc5cb8..799c59512c 100644
> --- a/sysdeps/unix/sysv/linux/bits/unistd_ext.h
> +++ b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
> @@ -33,4 +33,15 @@
>     not detached and has not been joined.  */
>  extern __pid_t gettid (void) __THROW;
>  
> +/* Unshare the file descriptor table before closing file descriptors.  */
> +#define CLOSE_RANGE_UNSHARE     (1U << 1)
> +
> +/* Close all file descriptors in the range FD up to MAX_FD.  The flag FLAGS
> +   are define by the CLOSE_RANGE prefix.  This function behaves like close
> +   on the range, but in a fail-safe where it will either fail and not close
> +   any file descriptor or close all of them.  Returns 0 on successor or -1
> +   for failure (and sets errno accordingly).  */
> +extern int close_range (unsigned int __fd, unsigned int __max_fd,
> +			int __flags) __THROW;
> +
>  #endif

I think we generally use int for file descriptors, following POSIX.

CLOSE_RANGE_CLOEXEC is coming (but it's not in the released 5.10).  I
think it makes sense to adjust the comment to reflect that.

__THROW is incompatible with close_range as a cancellation point.  I'm
not sure if it is useful for this function to be a cancellation point,
given that it's mostly used for cleanup.  It's true that close can block
for an indefinite time for certain descriptors, but I don't know if
close_range inherits that behavior.  It certainly does not apply to
CLOSE_RANGE_CLOEXEC.

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

> +int
> +__close_range (unsigned int lowfd, unsigned int highfd, int flags)
> +{
> +  return SYSCALL_CANCEL (close_range, lowfd, highfd, flags);
> +}
> +libc_hidden_def (__close_range)
> +weak_alias (__close_range, close_range)

See above, this should probably be INLINE_SYSCALL_CALL.  And you could
use the syscall lists file to define the system call either way.

> diff --git a/sysdeps/unix/sysv/linux/tst-clone.h b/sysdeps/unix/sysv/linux/tst-clone.h
> new file mode 100644
> index 0000000000..2344ac5101
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-clone.h
> @@ -0,0 +1,48 @@
> +/* Auxiliary wrapper to issue the clone symbol.

It's not clear to me what this means.

> +   Copyright (C) 2020 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#ifndef _TST_CLONE_H
> +#define _TST_CLONE_H
> +
> +#include <sched.h>
> +#include <stackinfo.h>  /* For _STACK_GROWS_{UP,DOWN}.  */
> +
> +#define DEFINE_STACK(name, size) \
> +  char name[size] __attribute__ ((aligned))
> +
> +static inline pid_t
> +clone_call (int (*fn) (void *arg), void *arg, void *stack, size_t stack_size,
> +	    int flags)
> +{
> +#ifdef __ia64__
> +  extern int __clone2 (int (*fn) (void *arg), void *stack, size_t stack_size,
> +		       int flags, void *arg, ...);
> +  return __clone2 (f, stack, stack_size, flags, arg, /* ptid */ NULL,
> +		   /* tls */ NULL, /* ctid  */ ctid);
> +#else
> +# if _STACK_GROWS_DOWN
> +  return clone (fn, stack + stack_size, flags, arg, /* ptid */ NULL,
> +	        /* tls */ NULL, /* ctid */  NULL);
> +# elif _STACK_GROWS_UP
> +  return clone (fn, stack, flags, arg, /* ptid */ NULL, /* tls */ NULL,
> +	        &ctid);
> +# endif
> +#endif
> +}
> +
> +#endif

Should this go into support/?

> 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..a685e7d359
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/tst-close_range.c

> +static unsigned int
> +first_invalid_flag (void)
> +{
> +  static const unsigned int flags[] = {
> +    CLOSE_RANGE_UNSHARE,
> +  };
> +
> +  unsigned int r = 1;
> +  for (int i = 0; i < array_length (flags); i++)
> +    if ((1U << r) & flags[i])
> +      r++;
> +  return 1U << r;
> +}
> +
> +enum
> +{
> +  maximum_fd = 100,
> +  half_fd = maximum_fd / 2,
> +  gap_1 = maximum_fd - 8,
> +  gap_0 = (maximum_fd * 3) / 4
> +};
> +
> +static void
> +close_range_test_common (int *fds, unsigned int flags)
> +{
> +  /* Basic test for invalid flags, bail out if unsupported.  */
> +  TEST_COMPARE (close_range (fds[0], fds[half_fd], first_invalid_flag()), -1);

This test is not future-proof at all.  I don't think it's valuable.

> +  if (errno == ENOSYS)
> +    FAIL_UNSUPPORTED ("close_range not supported");
> +  TEST_COMPARE (errno, EINVAL);
> +
> +  /* Close half of the descriptors and check result.  */
> +  TEST_COMPARE (close_range (fds[0], fds[half_fd], flags), 0);
> +  for (int i = 0; i <= half_fd; i++)
> +    {
> +      TEST_COMPARE (fcntl (fds[i], F_GETFL), -1);
> +      TEST_COMPARE (errno, EBADF);
> +    }

I have some difficulty figuring out whether you expect the descriptors
to be in a continuous range or not.

I think it would make sense to create one specific layout of file
descriptors and test with that.

> +static int
> +close_range_unshare_test_fn (void *arg)
> +{
> +  close_range_test_common (arg, 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)
> +{

I think there could also be a test without CLOSE_RANGE_UNSHARE that
verifies that the subprocess operators on the shared file descriptor
table.

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


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

* Re: [PATCH 2/3] io: Add closefrom [BZ #10353]
  2020-12-21 21:50 ` [PATCH 2/3] io: Add closefrom [BZ #10353] Adhemerval Zanella
@ 2020-12-22 10:49   ` Florian Weimer
  2020-12-22 11:50     ` Adhemerval Zanella
  0 siblings, 1 reply; 19+ messages in thread
From: Florian Weimer @ 2020-12-22 10:49 UTC (permalink / raw)
  To: Adhemerval Zanella via Libc-alpha

* Adhemerval Zanella via Libc-alpha:

> diff --git a/NEWS b/NEWS
> index 9e829841f6..221eb4d98e 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -30,6 +30,10 @@ Major new features:
>  
>  * On Linux, the close_range function has been added.
>  
> +* The function closefrom has been adeed.  It closes all file descriptors
> +  greater than given integer.  This function is a GNU extension, although it
> +  also present in other systems.

Typo: “adeed”


> diff --git a/io/closefrom.c b/io/closefrom.c
> new file mode 100644
> index 0000000000..7e8f5a1ce5
> --- /dev/null
> +++ b/io/closefrom.c
> @@ -0,0 +1,34 @@

> +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)
> +      if (__close (i) == -1)
> +        __fortify_fail ("closefrom failed to close a file descriptor");
> +}
> +weak_alias (__closefrom, closefrom)

Is __getdtablesize accurate on Hurd?  Then I guess this part is okay.

__close should probably be __close_nocancel_nostatus.  The error check
is incorrect.

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

> +  int fds[maximum_fd + 1];

Same issue as the other test?  Contiguous set of descriptors or not?

> +#include <support/test-driver.c>
> diff --git a/posix/unistd.h b/posix/unistd.h
> index 32b8161619..43ddd516aa 100644
> --- a/posix/unistd.h
> +++ b/posix/unistd.h
> @@ -352,6 +352,14 @@ extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence)
>     __THROW.  */
>  extern int close (int __fd);
>  
> +#ifdef __USE_GNU
> +/* Close all open file descriptors greater than or equal to LOWFD.
> +   Negative LOWFD is clamped to 0.
> +
> +   Similar to close, this functions is a cancellation point.  */
> +extern void closefrom (int __lowfd);
> +#endif

I think this function should not be a cancellation point, so you can add
__THROW.

> +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..48815941dd
> --- /dev/null
> +++ b/sysdeps/unix/sysv/linux/closefrom_fallback.c

> +/* Fallback code: iterates over /proc/self/fd, closing each file descriptor
> +   that fall on the criteria.  */
> +_Bool
> +__closefrom_fallback (int from)
> +{
> +  int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY,
> +			       0);
> +  if (dirfd == -1)
> +    return false;

You could try to close a few descriptors if the error is ENOENT and try
again.

> +  enum { buffer_size = 1024 };
> +  char buffer[buffer_size];
> +  bool ret = true;

buffer_size is only used once, so I think it's not needed.

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

I still think it's necessary to seek to position zero after exhausting
the current buffer and some files have been closed.

The error check for __close_nocancel seems superfluous.  It's possible
that you get EBADF due to a race with another thread, and that does not
seem sufficient reason to terminate the process?

Please also add a brief documentation to the manual (likewise for
close_range).

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


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

* Re: [PATCH 3/3] posix: Add posix_spawn_file_actions_closefrom
  2020-12-21 21:50 ` [PATCH 3/3] posix: Add posix_spawn_file_actions_closefrom Adhemerval Zanella
@ 2020-12-22 11:32   ` Florian Weimer
  2020-12-22 11:56     ` Adhemerval Zanella
  0 siblings, 1 reply; 19+ messages in thread
From: Florian Weimer @ 2020-12-22 11:32 UTC (permalink / raw)
  To: Adhemerval Zanella via Libc-alpha

* Adhemerval Zanella via Libc-alpha:

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

Two typos: “giver interger”

> diff --git a/posix/spawn.h b/posix/spawn.h
> index be6bd591a3..21ea563425 100644
> --- a/posix/spawn.h
> +++ b/posix/spawn.h
> @@ -213,6 +213,13 @@ extern int posix_spawn_file_actions_addchdir_np (posix_spawn_file_actions_t *
>  extern int posix_spawn_file_actions_addfchdir_np (posix_spawn_file_actions_t *,
>  						  int __fd)
>       __THROW __nonnull ((1));
> +
> +/* Add an action to close all file descriptor greater than FROM during
> +   spawn.  This affects the subsequent file actions.  */
> +extern int posix_spawn_file_actions_addclosefrom_np (posix_spawn_file_actions_t *,
> +						     int __from)
> +     __THROW __nonnull ((1));
> +
>  #endif

Line length issue (but I'm not sure how to avoid that).

> diff --git a/posix/spawn_faction_addclosefrom.c b/posix/spawn_faction_addclosefrom.c
> new file mode 100644
> index 0000000000..3a295580bc
> --- /dev/null
> +++ b/posix/spawn_faction_addclosefrom.c

> +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
> +  __set_errno (EINVAL);
> +  return -1;
> +#endif
> +}

Should this return EINVAL for the fallback case?

> diff --git a/posix/spawn_int_abi.h b/posix/spawn_int_abi.h
> new file mode 100644
> index 0000000000..5fda4d3442
> --- /dev/null
> +++ b/posix/spawn_int_abi.h
> @@ -0,0 +1,27 @@
> +/* Internal ABI specific for posix_spawn functionality.  Generic version.
> +   Copyright (C) 2020 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#ifndef _SPAWN_INT_ABI_H
> +#define _SPAWN_INT_ABI_H
> +
> +/* The closefrom file actions requires either a syscall or an arch-specific
> +   way to interact over all file descriptors and act uppon them (such
> +   /proc/self/fd on Linux).  */
> +#define __SPAWN_SUPPOR_CLOSEFROM 0
> +
> +#endif /* _SPAWN_INT_H */

I think Hurd has support for this via __getdtablesize, so perhaps this
is not needed?

In any case, ABI is a bit of a misnomer here, and this file is
uncessary, given the sysdeps/generic file.

> diff --git a/posix/tst-spawn5.c b/posix/tst-spawn5.c
> new file mode 100644
> index 0000000000..1f901d112b
> --- /dev/null
> +++ b/posix/tst-spawn5.c

> +enum
> +{
> +  maximum_fd = 100,
> +  half_fd = maximum_fd / 2,
> +};
> +static int fds[maximum_fd + 1];

The usual comments about file descriptor layout. 8-)

> +static void
> +do_test_closefrom (void)
> +{
> +  for (int i = 0; i < array_length (fds); i++)
> +    fds[i] = xopen ("/dev/null", O_WRONLY, 0);

This should perhaps check that the descriptors 57, …, 90 have actually
been opened, perhaps implicitly by checking that the resulting
descriptors end up as one block.

> +  /* Close the remmaining but the last one.  */

Typo: “remmaining”

> +  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>

You could simplify the reinvocation logic by making this a static or a
container test.

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

Suprious changes?

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


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

* Re: [PATCH 1/3] Linux: Add close_range
  2020-12-22  9:05 ` [PATCH 1/3] Linux: Add close_range Florian Weimer
@ 2020-12-22 11:35   ` Adhemerval Zanella
  2020-12-22 11:41     ` Florian Weimer
  0 siblings, 1 reply; 19+ messages in thread
From: Adhemerval Zanella @ 2020-12-22 11:35 UTC (permalink / raw)
  To: Florian Weimer, Adhemerval Zanella via Libc-alpha



On 22/12/2020 06:05, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
> 
>> 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/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
> 
> Missing __THROW?  (But see below.)
> 
>> diff --git a/sysdeps/unix/sysv/linux/bits/unistd_ext.h b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
>> index c315cc5cb8..799c59512c 100644
>> --- a/sysdeps/unix/sysv/linux/bits/unistd_ext.h
>> +++ b/sysdeps/unix/sysv/linux/bits/unistd_ext.h
>> @@ -33,4 +33,15 @@
>>     not detached and has not been joined.  */
>>  extern __pid_t gettid (void) __THROW;
>>  
>> +/* Unshare the file descriptor table before closing file descriptors.  */
>> +#define CLOSE_RANGE_UNSHARE     (1U << 1)
>> +
>> +/* Close all file descriptors in the range FD up to MAX_FD.  The flag FLAGS
>> +   are define by the CLOSE_RANGE prefix.  This function behaves like close
>> +   on the range, but in a fail-safe where it will either fail and not close
>> +   any file descriptor or close all of them.  Returns 0 on successor or -1
>> +   for failure (and sets errno accordingly).  */
>> +extern int close_range (unsigned int __fd, unsigned int __max_fd,
>> +			int __flags) __THROW;
>> +
>>  #endif
> 
> I think we generally use int for file descriptors, following POSIX.

The Linux interface uses unsigned integer, meaning that negative values
won't really trigger an invalid usage (kernel will return EINVAL if 
second argument is larger than first one though).

I would prefer for syscall wrapper to be close as possible of the kernel
interface, otherwise it would require to add additional semantic to
handle potential pitfall cases.

On this case, if we go for 'int' as argument should we return EBADF 
for invalid handles? 

> 
> CLOSE_RANGE_CLOEXEC is coming (but it's not in the released 5.10).  I
> think it makes sense to adjust the comment to reflect that.

I have a patch to add CLOSE_RANGE_CLOEXEC as soon it is on a released
kernel, it includes changes in the enum and some tests.

> 
> __THROW is incompatible with close_range as a cancellation point.  I'm
> not sure if it is useful for this function to be a cancellation point,
> given that it's mostly used for cleanup.  It's true that close can block
> for an indefinite time for certain descriptors, but I don't know if
> close_range inherits that behavior.  It certainly does not apply to
> CLOSE_RANGE_CLOEXEC.

I wasn't sure about making a cancellation entrypoint, so I followed
current close semantic.  The cancellation entrypoing would act also
in an early mode, meaning that asynchronous cancellation is enabled
and thread signaled the cancellation will act prior the syscall 
execution. 

In the other hand, reading the close_range code it does seen it 
returns with side-effects due signal interrupt. So maybe not making
a cancellation entrypoint is indeed a better option.

The FreeBSD implementation does not seem to make close_range a 
cancellation entrypoint. 

> 
>> diff --git a/sysdeps/unix/sysv/linux/close_range.c b/sysdeps/unix/sysv/linux/close_range.c
>> new file mode 100644
>> index 0000000000..a664e158ee
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/close_range.c
> 
>> +int
>> +__close_range (unsigned int lowfd, unsigned int highfd, int flags)
>> +{
>> +  return SYSCALL_CANCEL (close_range, lowfd, highfd, flags);
>> +}
>> +libc_hidden_def (__close_range)
>> +weak_alias (__close_range, close_range)
> 
> See above, this should probably be INLINE_SYSCALL_CALL.  And you could
> use the syscall lists file to define the system call either way.
> 
>> diff --git a/sysdeps/unix/sysv/linux/tst-clone.h b/sysdeps/unix/sysv/linux/tst-clone.h
>> new file mode 100644
>> index 0000000000..2344ac5101
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/tst-clone.h
>> @@ -0,0 +1,48 @@
>> +/* Auxiliary wrapper to issue the clone symbol.
> 
> It's not clear to me what this means.

Maybe:

  Auxiliary functions to issue the clone syscall. ?

> 
>> +   Copyright (C) 2020 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   The GNU C Library is free software; you can redistribute it and/or
>> +   modify it under the terms of the GNU Lesser General Public
>> +   License as published by the Free Software Foundation; either
>> +   version 2.1 of the License, or (at your option) any later version.
>> +
>> +   The GNU C Library is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +   Lesser General Public License for more details.
>> +
>> +   You should have received a copy of the GNU Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <https://www.gnu.org/licenses/>.  */
>> +
>> +#ifndef _TST_CLONE_H
>> +#define _TST_CLONE_H
>> +
>> +#include <sched.h>
>> +#include <stackinfo.h>  /* For _STACK_GROWS_{UP,DOWN}.  */
>> +
>> +#define DEFINE_STACK(name, size) \
>> +  char name[size] __attribute__ ((aligned))
>> +
>> +static inline pid_t
>> +clone_call (int (*fn) (void *arg), void *arg, void *stack, size_t stack_size,
>> +	    int flags)
>> +{
>> +#ifdef __ia64__
>> +  extern int __clone2 (int (*fn) (void *arg), void *stack, size_t stack_size,
>> +		       int flags, void *arg, ...);
>> +  return __clone2 (f, stack, stack_size, flags, arg, /* ptid */ NULL,
>> +		   /* tls */ NULL, /* ctid  */ ctid);
>> +#else
>> +# if _STACK_GROWS_DOWN
>> +  return clone (fn, stack + stack_size, flags, arg, /* ptid */ NULL,
>> +	        /* tls */ NULL, /* ctid */  NULL);
>> +# elif _STACK_GROWS_UP
>> +  return clone (fn, stack, flags, arg, /* ptid */ NULL, /* tls */ NULL,
>> +	        &ctid);
>> +# endif
>> +#endif
>> +}
>> +
>> +#endif
> 
> Should this go into support/?

Ok, although it would be a Linux only interface.

> 
>> 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..a685e7d359
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/tst-close_range.c
> 
>> +static unsigned int
>> +first_invalid_flag (void)
>> +{
>> +  static const unsigned int flags[] = {
>> +    CLOSE_RANGE_UNSHARE,
>> +  };
>> +
>> +  unsigned int r = 1;
>> +  for (int i = 0; i < array_length (flags); i++)
>> +    if ((1U << r) & flags[i])
>> +      r++;
>> +  return 1U << r;
>> +}
>> +
>> +enum
>> +{
>> +  maximum_fd = 100,
>> +  half_fd = maximum_fd / 2,
>> +  gap_1 = maximum_fd - 8,
>> +  gap_0 = (maximum_fd * 3) / 4
>> +};
>> +
>> +static void
>> +close_range_test_common (int *fds, unsigned int flags)
>> +{
>> +  /* Basic test for invalid flags, bail out if unsupported.  */
>> +  TEST_COMPARE (close_range (fds[0], fds[half_fd], first_invalid_flag()), -1);
> 
> This test is not future-proof at all.  I don't think it's valuable.

But the idea is exactly to raise a warning if the underlying kernel
supports more flags than the one support by glibc.

> 
>> +  if (errno == ENOSYS)
>> +    FAIL_UNSUPPORTED ("close_range not supported");
>> +  TEST_COMPARE (errno, EINVAL);
>> +
>> +  /* Close half of the descriptors and check result.  */
>> +  TEST_COMPARE (close_range (fds[0], fds[half_fd], flags), 0);
>> +  for (int i = 0; i <= half_fd; i++)
>> +    {
>> +      TEST_COMPARE (fcntl (fds[i], F_GETFL), -1);
>> +      TEST_COMPARE (errno, EBADF);
>> +    }
> 
> I have some difficulty figuring out whether you expect the descriptors
> to be in a continuous range or not.
> 
> I think it would make sense to create one specific layout of file
> descriptors and test with that.

I think it is a fair assumption that descriptors are a continuous range.
I modeled this tests using the kernel one as base, which make the same
assumptions [1]

[1] tools/testing/selftests/core/close_range_test.c

> 
>> +static int
>> +close_range_unshare_test_fn (void *arg)
>> +{
>> +  close_range_test_common (arg, 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)
>> +{
> 
> I think there could also be a test without CLOSE_RANGE_UNSHARE that
> verifies that the subprocess operators on the shared file descriptor
> table.

Do you mean issue a 	? I may add it, although it would tests
more CLONE_FILES support than close_range.

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

* Re: [PATCH 1/3] Linux: Add close_range
  2020-12-22 11:35   ` Adhemerval Zanella
@ 2020-12-22 11:41     ` Florian Weimer
  2020-12-22 11:47       ` Adhemerval Zanella
  2020-12-23 12:33       ` Christian Brauner
  0 siblings, 2 replies; 19+ messages in thread
From: Florian Weimer @ 2020-12-22 11:41 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: Adhemerval Zanella via Libc-alpha

* Adhemerval Zanella:

>> I think we generally use int for file descriptors, following POSIX.
>
> The Linux interface uses unsigned integer, meaning that negative values
> won't really trigger an invalid usage (kernel will return EINVAL if 
> second argument is larger than first one though).
>
> I would prefer for syscall wrapper to be close as possible of the kernel
> interface, otherwise it would require to add additional semantic to
> handle potential pitfall cases.
>
> On this case, if we go for 'int' as argument should we return EBADF 
> for invalid handles?

Hmm.  I think unsigned int is needed for ~0U to work, which is what you
used in the tests.  If that's what applications use today when issuing
the syscall directly, I think we need to stick to unsigned int.

>> __THROW is incompatible with close_range as a cancellation point.  I'm
>> not sure if it is useful for this function to be a cancellation point,
>> given that it's mostly used for cleanup.  It's true that close can block
>> for an indefinite time for certain descriptors, but I don't know if
>> close_range inherits that behavior.  It certainly does not apply to
>> CLOSE_RANGE_CLOEXEC.
>
> I wasn't sure about making a cancellation entrypoint, so I followed
> current close semantic.  The cancellation entrypoing would act also
> in an early mode, meaning that asynchronous cancellation is enabled
> and thread signaled the cancellation will act prior the syscall 
> execution. 
>
> In the other hand, reading the close_range code it does seen it 
> returns with side-effects due signal interrupt. So maybe not making
> a cancellation entrypoint is indeed a better option.
>
> The FreeBSD implementation does not seem to make close_range a 
> cancellation entrypoint.

Yes, let's do not act upon cancellation.

>>> diff --git a/sysdeps/unix/sysv/linux/tst-clone.h b/sysdeps/unix/sysv/linux/tst-clone.h
>>> new file mode 100644
>>> index 0000000000..2344ac5101
>>> --- /dev/null
>>> +++ b/sysdeps/unix/sysv/linux/tst-clone.h
>>> @@ -0,0 +1,48 @@
>>> +/* Auxiliary wrapper to issue the clone symbol.
>> 
>> It's not clear to me what this means.
>
> Maybe:
>
>   Auxiliary functions to issue the clone syscall. ?

That's better, thanks.

>>> 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..a685e7d359
>>> --- /dev/null
>>> +++ b/sysdeps/unix/sysv/linux/tst-close_range.c
>> 
>>> +static unsigned int
>>> +first_invalid_flag (void)
>>> +{
>>> +  static const unsigned int flags[] = {
>>> +    CLOSE_RANGE_UNSHARE,
>>> +  };
>>> +
>>> +  unsigned int r = 1;
>>> +  for (int i = 0; i < array_length (flags); i++)
>>> +    if ((1U << r) & flags[i])
>>> +      r++;
>>> +  return 1U << r;
>>> +}
>>> +
>>> +enum
>>> +{
>>> +  maximum_fd = 100,
>>> +  half_fd = maximum_fd / 2,
>>> +  gap_1 = maximum_fd - 8,
>>> +  gap_0 = (maximum_fd * 3) / 4
>>> +};
>>> +
>>> +static void
>>> +close_range_test_common (int *fds, unsigned int flags)
>>> +{
>>> +  /* Basic test for invalid flags, bail out if unsupported.  */
>>> +  TEST_COMPARE (close_range (fds[0], fds[half_fd], first_invalid_flag()), -1);
>> 
>> This test is not future-proof at all.  I don't think it's valuable.
>
> But the idea is exactly to raise a warning if the underlying kernel
> supports more flags than the one support by glibc.

But it causes a test failure, not a warning.  I don't think it's valid
to poke for unknown system call flags like this, so even a proper
warning would be hard.

>>> +  if (errno == ENOSYS)
>>> +    FAIL_UNSUPPORTED ("close_range not supported");
>>> +  TEST_COMPARE (errno, EINVAL);
>>> +
>>> +  /* Close half of the descriptors and check result.  */
>>> +  TEST_COMPARE (close_range (fds[0], fds[half_fd], flags), 0);
>>> +  for (int i = 0; i <= half_fd; i++)
>>> +    {
>>> +      TEST_COMPARE (fcntl (fds[i], F_GETFL), -1);
>>> +      TEST_COMPARE (errno, EBADF);
>>> +    }
>> 
>> I have some difficulty figuring out whether you expect the descriptors
>> to be in a continuous range or not.
>> 
>> I think it would make sense to create one specific layout of file
>> descriptors and test with that.
>
> I think it is a fair assumption that descriptors are a continuous range.
> I modeled this tests using the kernel one as base, which make the same
> assumptions [1]
>
> [1] tools/testing/selftests/core/close_range_test.c

The you don't need the fds array.  It's what makes this confusing.

>>> +static int
>>> +close_range_unshare_test_fn (void *arg)
>>> +{
>>> +  close_range_test_common (arg, 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)
>>> +{
>> 
>> I think there could also be a test without CLOSE_RANGE_UNSHARE that
>> verifies that the subprocess operators on the shared file descriptor
>> table.
>
> Do you mean issue a 	? I may add it, although it would tests
> more CLONE_FILES support than close_range.

Sorry?  I meant a test that shows that flags == 0 and flags ==
CLOSE_RANGE_UNSHARE behave differently.

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


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

* Re: [PATCH 1/3] Linux: Add close_range
  2020-12-22 11:41     ` Florian Weimer
@ 2020-12-22 11:47       ` Adhemerval Zanella
  2020-12-23 12:33       ` Christian Brauner
  1 sibling, 0 replies; 19+ messages in thread
From: Adhemerval Zanella @ 2020-12-22 11:47 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Adhemerval Zanella via Libc-alpha



On 22/12/2020 08:41, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>>> I think we generally use int for file descriptors, following POSIX.
>>
>> The Linux interface uses unsigned integer, meaning that negative values
>> won't really trigger an invalid usage (kernel will return EINVAL if 
>> second argument is larger than first one though).
>>
>> I would prefer for syscall wrapper to be close as possible of the kernel
>> interface, otherwise it would require to add additional semantic to
>> handle potential pitfall cases.
>>
>> On this case, if we go for 'int' as argument should we return EBADF 
>> for invalid handles?
> 
> Hmm.  I think unsigned int is needed for ~0U to work, which is what you
> used in the tests.  If that's what applications use today when issuing
> the syscall directly, I think we need to stick to unsigned int.

Ack.

> 
>>> __THROW is incompatible with close_range as a cancellation point.  I'm
>>> not sure if it is useful for this function to be a cancellation point,
>>> given that it's mostly used for cleanup.  It's true that close can block
>>> for an indefinite time for certain descriptors, but I don't know if
>>> close_range inherits that behavior.  It certainly does not apply to
>>> CLOSE_RANGE_CLOEXEC.
>>
>> I wasn't sure about making a cancellation entrypoint, so I followed
>> current close semantic.  The cancellation entrypoing would act also
>> in an early mode, meaning that asynchronous cancellation is enabled
>> and thread signaled the cancellation will act prior the syscall 
>> execution. 
>>
>> In the other hand, reading the close_range code it does seen it 
>> returns with side-effects due signal interrupt. So maybe not making
>> a cancellation entrypoint is indeed a better option.
>>
>> The FreeBSD implementation does not seem to make close_range a 
>> cancellation entrypoint.
> 
> Yes, let's do not act upon cancellation.

Ack.

> 
>>>> diff --git a/sysdeps/unix/sysv/linux/tst-clone.h b/sysdeps/unix/sysv/linux/tst-clone.h
>>>> new file mode 100644
>>>> index 0000000000..2344ac5101
>>>> --- /dev/null
>>>> +++ b/sysdeps/unix/sysv/linux/tst-clone.h
>>>> @@ -0,0 +1,48 @@
>>>> +/* Auxiliary wrapper to issue the clone symbol.
>>>
>>> It's not clear to me what this means.
>>
>> Maybe:
>>
>>   Auxiliary functions to issue the clone syscall. ?
> 
> That's better, thanks.

Ack.

> 
>>>> 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..a685e7d359
>>>> --- /dev/null
>>>> +++ b/sysdeps/unix/sysv/linux/tst-close_range.c
>>>
>>>> +static unsigned int
>>>> +first_invalid_flag (void)
>>>> +{
>>>> +  static const unsigned int flags[] = {
>>>> +    CLOSE_RANGE_UNSHARE,
>>>> +  };
>>>> +
>>>> +  unsigned int r = 1;
>>>> +  for (int i = 0; i < array_length (flags); i++)
>>>> +    if ((1U << r) & flags[i])
>>>> +      r++;
>>>> +  return 1U << r;
>>>> +}
>>>> +
>>>> +enum
>>>> +{
>>>> +  maximum_fd = 100,
>>>> +  half_fd = maximum_fd / 2,
>>>> +  gap_1 = maximum_fd - 8,
>>>> +  gap_0 = (maximum_fd * 3) / 4
>>>> +};
>>>> +
>>>> +static void
>>>> +close_range_test_common (int *fds, unsigned int flags)
>>>> +{
>>>> +  /* Basic test for invalid flags, bail out if unsupported.  */
>>>> +  TEST_COMPARE (close_range (fds[0], fds[half_fd], first_invalid_flag()), -1);
>>>
>>> This test is not future-proof at all.  I don't think it's valuable.
>>
>> But the idea is exactly to raise a warning if the underlying kernel
>> supports more flags than the one support by glibc.
> 
> But it causes a test failure, not a warning.  I don't think it's valid
> to poke for unknown system call flags like this, so even a proper
> warning would be hard.

Alright, I will remove the invalid flag warning.

> 
>>>> +  if (errno == ENOSYS)
>>>> +    FAIL_UNSUPPORTED ("close_range not supported");
>>>> +  TEST_COMPARE (errno, EINVAL);
>>>> +
>>>> +  /* Close half of the descriptors and check result.  */
>>>> +  TEST_COMPARE (close_range (fds[0], fds[half_fd], flags), 0);
>>>> +  for (int i = 0; i <= half_fd; i++)
>>>> +    {
>>>> +      TEST_COMPARE (fcntl (fds[i], F_GETFL), -1);
>>>> +      TEST_COMPARE (errno, EBADF);
>>>> +    }
>>>
>>> I have some difficulty figuring out whether you expect the descriptors
>>> to be in a continuous range or not.
>>>
>>> I think it would make sense to create one specific layout of file
>>> descriptors and test with that.
>>
>> I think it is a fair assumption that descriptors are a continuous range.
>> I modeled this tests using the kernel one as base, which make the same
>> assumptions [1]
>>
>> [1] tools/testing/selftests/core/close_range_test.c
> 
> The you don't need the fds array.  It's what makes this confusing.

Ack, I will remove it.

> 
>>>> +static int
>>>> +close_range_unshare_test_fn (void *arg)
>>>> +{
>>>> +  close_range_test_common (arg, 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)
>>>> +{
>>>
>>> I think there could also be a test without CLOSE_RANGE_UNSHARE that
>>> verifies that the subprocess operators on the shared file descriptor
>>> table.
>>
>> Do you mean issue a 	? I may add it, although it would tests
>> more CLONE_FILES support than close_range.
> 
> Sorry?  I meant a test that shows that flags == 0 and flags ==
> CLOSE_RANGE_UNSHARE behave differently.

My questioning was mangled (the '?' should have been CLOSE_RANGE_UNSHARE).
Alright I will add a clone tests with both flags.

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

* Re: [PATCH 2/3] io: Add closefrom [BZ #10353]
  2020-12-22 10:49   ` Florian Weimer
@ 2020-12-22 11:50     ` Adhemerval Zanella
  2020-12-22 11:57       ` Florian Weimer
  0 siblings, 1 reply; 19+ messages in thread
From: Adhemerval Zanella @ 2020-12-22 11:50 UTC (permalink / raw)
  To: Florian Weimer, Adhemerval Zanella via Libc-alpha



On 22/12/2020 07:49, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
> 
>> diff --git a/NEWS b/NEWS
>> index 9e829841f6..221eb4d98e 100644
>> --- a/NEWS
>> +++ b/NEWS
>> @@ -30,6 +30,10 @@ Major new features:
>>  
>>  * On Linux, the close_range function has been added.
>>  
>> +* The function closefrom has been adeed.  It closes all file descriptors
>> +  greater than given integer.  This function is a GNU extension, although it
>> +  also present in other systems.
> 
> Typo: “adeed”
> 

Ack.

> 
>> diff --git a/io/closefrom.c b/io/closefrom.c
>> new file mode 100644
>> index 0000000000..7e8f5a1ce5
>> --- /dev/null
>> +++ b/io/closefrom.c
>> @@ -0,0 +1,34 @@
> 
>> +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)
>> +      if (__close (i) == -1)
>> +        __fortify_fail ("closefrom failed to close a file descriptor");
>> +}
>> +weak_alias (__closefrom, closefrom)
> 
> Is __getdtablesize accurate on Hurd?  Then I guess this part is okay.

Not sure in fact, it seems so.

> 
> __close should probably be __close_nocancel_nostatus.  The error check
> is incorrect.

Yeah, I figure out after I sent it.  I will chance to __close_nocancel_nostatus.

> 
>> diff --git a/io/tst-closefrom.c b/io/tst-closefrom.c
>> new file mode 100644
>> index 0000000000..6eb97cec10
>> --- /dev/null
>> +++ b/io/tst-closefrom.c
> 
>> +  int fds[maximum_fd + 1];
> 
> Same issue as the other test?  Contiguous set of descriptors or not?

It assumes a contiguous, if you prefer I can remove the array and just use
a maximum value to hold the value.

> 
>> +#include <support/test-driver.c>
>> diff --git a/posix/unistd.h b/posix/unistd.h
>> index 32b8161619..43ddd516aa 100644
>> --- a/posix/unistd.h
>> +++ b/posix/unistd.h
>> @@ -352,6 +352,14 @@ extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence)
>>     __THROW.  */
>>  extern int close (int __fd);
>>  
>> +#ifdef __USE_GNU
>> +/* Close all open file descriptors greater than or equal to LOWFD.
>> +   Negative LOWFD is clamped to 0.
>> +
>> +   Similar to close, this functions is a cancellation point.  */
>> +extern void closefrom (int __lowfd);
>> +#endif
> 
> I think this function should not be a cancellation point, so you can add
> __THROW.
> 

Yeah, from close_range discussion it does seems a better alternative.

>> +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..48815941dd
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/closefrom_fallback.c
> 
>> +/* Fallback code: iterates over /proc/self/fd, closing each file descriptor
>> +   that fall on the criteria.  */
>> +_Bool
>> +__closefrom_fallback (int from)
>> +{
>> +  int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY,
>> +			       0);
>> +  if (dirfd == -1)
>> +    return false;
> 
> You could try to close a few descriptors if the error is ENOENT and try
> again.

Do you mean EMFILE and issue a close on [from, ...] and then try again?
I am not really fan of this heuristics, it might mitigate the failure if
limit of file-descriptors are reached, but it would really depend whether
if 'from' is close of the first open descriptor and the how many close
we issue.

> 
>> +  enum { buffer_size = 1024 };
>> +  char buffer[buffer_size];
>> +  bool ret = true;
> 
> buffer_size is only used once, so I think it's not needed.

Ack.

> 
>> +  while (true)
>> +    {
>> +      ssize_t ret = __getdents64 (dirfd, buffer, sizeof (buffer));
>> +      if (ret == -1)
>> +        goto err;
>> +      else if (ret == 0)
>> +        break;
>> +
>> +      char *begin = buffer, *end = buffer + ret;
>> +      while (begin != end)
>> +	{
>> +          unsigned short int d_reclen;
>> +	  memcpy (&d_reclen, begin + offsetof (struct dirent64, d_reclen),
>> +		  sizeof (d_reclen));
>> +	  const char *dname = begin + offsetof (struct dirent64, d_name);
>> +	  begin += d_reclen;
>> +
>> +	  if (dname[0] == '.')
>> +	    continue;
>> +
>> +	  int fd = 0;
>> +	  for (const char *s = dname; (unsigned int) (*s) - '0' < 10; s++)
>> +	    fd = 10 * fd + (*s - '0');
>> +
>> +	  if (fd == dirfd || fd < from)
>> +	    continue;
>> +
>> +	  if (__close_nocancel (fd) < 0)
>> +	    goto err;
>> +	}
>> +    }
>> +
>> +  ret = true;
>> +err:
>> +  __close_nocancel (dirfd);
>> +  return ret;
>> +}
> 
> I still think it's necessary to seek to position zero after exhausting
> the current buffer and some files have been closed.

Alright, this should only add some overhead; although based on various
current usages it really seems not required.

> 
> The error check for __close_nocancel seems superfluous.  It's possible
> that you get EBADF due to a race with another thread, and that does not
> seem sufficient reason to terminate the process?

Alright, I will remove the check.

> 
> Please also add a brief documentation to the manual (likewise for
> close_range).

Ack.

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

* Re: [PATCH 3/3] posix: Add posix_spawn_file_actions_closefrom
  2020-12-22 11:32   ` Florian Weimer
@ 2020-12-22 11:56     ` Adhemerval Zanella
  2020-12-22 12:00       ` Florian Weimer
  0 siblings, 1 reply; 19+ messages in thread
From: Adhemerval Zanella @ 2020-12-22 11:56 UTC (permalink / raw)
  To: Florian Weimer, Adhemerval Zanella via Libc-alpha



On 22/12/2020 08:32, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
> 
>> +* The posix_spawn_file_actions_closefrom_np has been added, enabling
>> +  posix_spawn and posix_spawnp to close all file descriptors greater than
>> +  a giver interger.  This function is a GNU extension, although Solaris also
>> +  provides a similar function.
> 
> Two typos: “giver interger”

Ack.

> 
>> diff --git a/posix/spawn.h b/posix/spawn.h
>> index be6bd591a3..21ea563425 100644
>> --- a/posix/spawn.h
>> +++ b/posix/spawn.h
>> @@ -213,6 +213,13 @@ extern int posix_spawn_file_actions_addchdir_np (posix_spawn_file_actions_t *
>>  extern int posix_spawn_file_actions_addfchdir_np (posix_spawn_file_actions_t *,
>>  						  int __fd)
>>       __THROW __nonnull ((1));
>> +
>> +/* Add an action to close all file descriptor greater than FROM during
>> +   spawn.  This affects the subsequent file actions.  */
>> +extern int posix_spawn_file_actions_addclosefrom_np (posix_spawn_file_actions_t *,
>> +						     int __from)
>> +     __THROW __nonnull ((1));
>> +
>>  #endif
> 
> Line length issue (but I'm not sure how to avoid that).

Maybe move the argument to next line aligning with __THROW?

extern int posix_spawn_file_actions_addclosefrom_np (
     posix_spawn_file_actions_t *, int __from)
     __THROW __nonnull ((1));

?

> 
>> diff --git a/posix/spawn_faction_addclosefrom.c b/posix/spawn_faction_addclosefrom.c
>> new file mode 100644
>> index 0000000000..3a295580bc
>> --- /dev/null
>> +++ b/posix/spawn_faction_addclosefrom.c
> 
>> +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
>> +  __set_errno (EINVAL);
>> +  return -1;
>> +#endif
>> +}
> 
> Should this return EINVAL for the fallback case?

Indeed, this should not set errno.

> 
>> diff --git a/posix/spawn_int_abi.h b/posix/spawn_int_abi.h
>> new file mode 100644
>> index 0000000000..5fda4d3442
>> --- /dev/null
>> +++ b/posix/spawn_int_abi.h
>> @@ -0,0 +1,27 @@
>> +/* Internal ABI specific for posix_spawn functionality.  Generic version.
>> +   Copyright (C) 2020 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +
>> +   The GNU C Library is free software; you can redistribute it and/or
>> +   modify it under the terms of the GNU Lesser General Public
>> +   License as published by the Free Software Foundation; either
>> +   version 2.1 of the License, or (at your option) any later version.
>> +
>> +   The GNU C Library is distributed in the hope that it will be useful,
>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> +   Lesser General Public License for more details.
>> +
>> +   You should have received a copy of the GNU Lesser General Public
>> +   License along with the GNU C Library; if not, see
>> +   <http://www.gnu.org/licenses/>.  */
>> +
>> +#ifndef _SPAWN_INT_ABI_H
>> +#define _SPAWN_INT_ABI_H
>> +
>> +/* The closefrom file actions requires either a syscall or an arch-specific
>> +   way to interact over all file descriptors and act uppon them (such
>> +   /proc/self/fd on Linux).  */
>> +#define __SPAWN_SUPPOR_CLOSEFROM 0
>> +
>> +#endif /* _SPAWN_INT_H */
> 
> I think Hurd has support for this via __getdtablesize, so perhaps this
> is not needed?
> 
> In any case, ABI is a bit of a misnomer here, and this file is
> uncessary, given the sysdeps/generic file.

Yes, I add the generic one to fix a hurd build fail and I forgot to remove
this one.

> 
>> diff --git a/posix/tst-spawn5.c b/posix/tst-spawn5.c
>> new file mode 100644
>> index 0000000000..1f901d112b
>> --- /dev/null
>> +++ b/posix/tst-spawn5.c
> 
>> +enum
>> +{
>> +  maximum_fd = 100,
>> +  half_fd = maximum_fd / 2,
>> +};
>> +static int fds[maximum_fd + 1];
> 
> The usual comments about file descriptor layout. 8-)

Ack, I will remove the array usage.

> 
>> +static void
>> +do_test_closefrom (void)
>> +{
>> +  for (int i = 0; i < array_length (fds); i++)
>> +    fds[i] = xopen ("/dev/null", O_WRONLY, 0);
> 
> This should perhaps check that the descriptors 57, …, 90 have actually
> been opened, perhaps implicitly by checking that the resulting
> descriptors end up as one block.
> 
>> +  /* Close the remmaining but the last one.  */
> 
> Typo: “remmaining”
> 
>> +  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>
> 
> You could simplify the reinvocation logic by making this a static or a
> container test.

I prefer to keep this exercises this test on some platform where container
tests are not really supported.

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

In fact I cleanup the include range a bit, if you prefer I can remove this
change from this set.

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

* Re: [PATCH 2/3] io: Add closefrom [BZ #10353]
  2020-12-22 11:50     ` Adhemerval Zanella
@ 2020-12-22 11:57       ` Florian Weimer
  2020-12-22 12:41         ` Adhemerval Zanella
  0 siblings, 1 reply; 19+ messages in thread
From: Florian Weimer @ 2020-12-22 11:57 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: Adhemerval Zanella via Libc-alpha

* Adhemerval Zanella:

>>> +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..48815941dd
>>> --- /dev/null
>>> +++ b/sysdeps/unix/sysv/linux/closefrom_fallback.c
>> 
>>> +/* Fallback code: iterates over /proc/self/fd, closing each file descriptor
>>> +   that fall on the criteria.  */
>>> +_Bool
>>> +__closefrom_fallback (int from)
>>> +{
>>> +  int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY,
>>> +			       0);
>>> +  if (dirfd == -1)
>>> +    return false;
>> 
>> You could try to close a few descriptors if the error is ENOENT and try
>> again.
>
> Do you mean EMFILE and issue a close on [from, ...] and then try again?
> I am not really fan of this heuristics, it might mitigate the failure if
> limit of file-descriptors are reached, but it would really depend whether
> if 'from' is close of the first open descriptor and the how many close
> we issue.

Right, but I think it's needed for correctness.  closefrom (3) should
work even if all descriptors are open.

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


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

* Re: [PATCH 3/3] posix: Add posix_spawn_file_actions_closefrom
  2020-12-22 11:56     ` Adhemerval Zanella
@ 2020-12-22 12:00       ` Florian Weimer
  2020-12-22 12:46         ` Adhemerval Zanella
  0 siblings, 1 reply; 19+ messages in thread
From: Florian Weimer @ 2020-12-22 12:00 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: Adhemerval Zanella via Libc-alpha

* Adhemerval Zanella:

>>> diff --git a/posix/spawn.h b/posix/spawn.h
>>> index be6bd591a3..21ea563425 100644
>>> --- a/posix/spawn.h
>>> +++ b/posix/spawn.h
>>> @@ -213,6 +213,13 @@ extern int posix_spawn_file_actions_addchdir_np (posix_spawn_file_actions_t *
>>>  extern int posix_spawn_file_actions_addfchdir_np (posix_spawn_file_actions_t *,
>>>  						  int __fd)
>>>       __THROW __nonnull ((1));
>>> +
>>> +/* Add an action to close all file descriptor greater than FROM during
>>> +   spawn.  This affects the subsequent file actions.  */
>>> +extern int posix_spawn_file_actions_addclosefrom_np (posix_spawn_file_actions_t *,
>>> +						     int __from)
>>> +     __THROW __nonnull ((1));
>>> +
>>>  #endif
>> 
>> Line length issue (but I'm not sure how to avoid that).
>
> Maybe move the argument to next line aligning with __THROW?
>
> extern int posix_spawn_file_actions_addclosefrom_np (
>      posix_spawn_file_actions_t *, int __from)
>      __THROW __nonnull ((1));
>
> ?

I think it's not GNU style.  You could drop the extern, though.

>> You could simplify the reinvocation logic by making this a static or a
>> container test.
>
> I prefer to keep this exercises this test on some platform where container
> tests are not really supported.

Then perhaps make it a static test, or only make it a container test for
the non-hard-coded-paths case?

>>> diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
>>> index f157bfffd2..f496578d19 100644
>>> --- a/sysdeps/unix/sysv/linux/spawni.c
>>> +++ b/sysdeps/unix/sysv/linux/spawni.c
>>> @@ -16,22 +16,17 @@
>>>     License along with the GNU C Library; if not, see
>>>     <https://www.gnu.org/licenses/>.  */
>>>  
>>> -#include <spawn.h>
>>> -#include <fcntl.h>
>>> -#include <paths.h>
>>> -#include <string.h>
>>> -#include <sys/resource.h>
>>> -#include <sys/wait.h>
>>> -#include <sys/param.h>
>>> -#include <sys/mman.h>
>>> -#include <not-cancel.h>
>>> +#include <arch-fd_to_filename.h>
>>> +#include <internal-signals.h>
>>> +#include <ldsodefs.h>
>>>  #include <local-setxid.h>
>>> +#include <not-cancel.h>
>>> +#include <paths.h>
>>>  #include <shlib-compat.h>
>>> -#include <nptl/pthreadP.h>
>>> -#include <dl-sysdep.h>
>>> -#include <libc-pointer-arith.h>
>>> -#include <ldsodefs.h>
>>> -#include "spawn_int.h"
>>> +#include <spawn.h>
>>> +#include <spawn_int.h>
>>> +#include <sysdep.h>
>>> +#include <sys/resource.h>
>> 
>> Suprious changes?
>
> In fact I cleanup the include range a bit, if you prefer I can remove this
> change from this set.

Hmm.  I think <arch-fd_to_filename.h> is not used here?

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


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

* Re: [PATCH 2/3] io: Add closefrom [BZ #10353]
  2020-12-22 11:57       ` Florian Weimer
@ 2020-12-22 12:41         ` Adhemerval Zanella
  2020-12-22 13:17           ` Florian Weimer
  0 siblings, 1 reply; 19+ messages in thread
From: Adhemerval Zanella @ 2020-12-22 12:41 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Adhemerval Zanella via Libc-alpha



On 22/12/2020 08:57, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>>>> +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..48815941dd
>>>> --- /dev/null
>>>> +++ b/sysdeps/unix/sysv/linux/closefrom_fallback.c
>>>
>>>> +/* Fallback code: iterates over /proc/self/fd, closing each file descriptor
>>>> +   that fall on the criteria.  */
>>>> +_Bool
>>>> +__closefrom_fallback (int from)
>>>> +{
>>>> +  int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY,
>>>> +			       0);
>>>> +  if (dirfd == -1)
>>>> +    return false;
>>>
>>> You could try to close a few descriptors if the error is ENOENT and try
>>> again.
>>
>> Do you mean EMFILE and issue a close on [from, ...] and then try again?
>> I am not really fan of this heuristics, it might mitigate the failure if
>> limit of file-descriptors are reached, but it would really depend whether
>> if 'from' is close of the first open descriptor and the how many close
>> we issue.
> 
> Right, but I think it's needed for correctness.  closefrom (3) should
> work even if all descriptors are open.

Alright, I think we can do something like:

  int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY, 0);
  if (dirfd == -1 && errno == EMFILE)
    {
      int maxfd = __getdtablesize ();
      for (int i = lowfd; i < maxfd; i++)
	if (__close_nocancel (i) == 0)
	  break;
      dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY, 0);
      if (dirfd == -1)
        goto err;
    }


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

* Re: [PATCH 3/3] posix: Add posix_spawn_file_actions_closefrom
  2020-12-22 12:00       ` Florian Weimer
@ 2020-12-22 12:46         ` Adhemerval Zanella
  0 siblings, 0 replies; 19+ messages in thread
From: Adhemerval Zanella @ 2020-12-22 12:46 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Adhemerval Zanella via Libc-alpha



On 22/12/2020 09:00, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>>>> diff --git a/posix/spawn.h b/posix/spawn.h
>>>> index be6bd591a3..21ea563425 100644
>>>> --- a/posix/spawn.h
>>>> +++ b/posix/spawn.h
>>>> @@ -213,6 +213,13 @@ extern int posix_spawn_file_actions_addchdir_np (posix_spawn_file_actions_t *
>>>>  extern int posix_spawn_file_actions_addfchdir_np (posix_spawn_file_actions_t *,
>>>>  						  int __fd)
>>>>       __THROW __nonnull ((1));
>>>> +
>>>> +/* Add an action to close all file descriptor greater than FROM during
>>>> +   spawn.  This affects the subsequent file actions.  */
>>>> +extern int posix_spawn_file_actions_addclosefrom_np (posix_spawn_file_actions_t *,
>>>> +						     int __from)
>>>> +     __THROW __nonnull ((1));
>>>> +
>>>>  #endif
>>>
>>> Line length issue (but I'm not sure how to avoid that).
>>
>> Maybe move the argument to next line aligning with __THROW?
>>
>> extern int posix_spawn_file_actions_addclosefrom_np (
>>      posix_spawn_file_actions_t *, int __from)
>>      __THROW __nonnull ((1));
>>
>> ?
> 
> I think it's not GNU style.  You could drop the extern, though.

Ack.

> 
>>> You could simplify the reinvocation logic by making this a static or a
>>> container test.
>>
>> I prefer to keep this exercises this test on some platform where container
>> tests are not really supported.
> 
> Then perhaps make it a static test, or only make it a container test for
> the non-hard-coded-paths case?

Maybe another option would to simplify this setup and add a libsupport
to handle the argument and re-invocation logic.  Meanwhile, I think
issuing the shared case still stresses the most common usage for glibc.

> 
>>>> diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
>>>> index f157bfffd2..f496578d19 100644
>>>> --- a/sysdeps/unix/sysv/linux/spawni.c
>>>> +++ b/sysdeps/unix/sysv/linux/spawni.c
>>>> @@ -16,22 +16,17 @@
>>>>     License along with the GNU C Library; if not, see
>>>>     <https://www.gnu.org/licenses/>.  */
>>>>  
>>>> -#include <spawn.h>
>>>> -#include <fcntl.h>
>>>> -#include <paths.h>
>>>> -#include <string.h>
>>>> -#include <sys/resource.h>
>>>> -#include <sys/wait.h>
>>>> -#include <sys/param.h>
>>>> -#include <sys/mman.h>
>>>> -#include <not-cancel.h>
>>>> +#include <arch-fd_to_filename.h>
>>>> +#include <internal-signals.h>
>>>> +#include <ldsodefs.h>
>>>>  #include <local-setxid.h>
>>>> +#include <not-cancel.h>
>>>> +#include <paths.h>
>>>>  #include <shlib-compat.h>
>>>> -#include <nptl/pthreadP.h>
>>>> -#include <dl-sysdep.h>
>>>> -#include <libc-pointer-arith.h>
>>>> -#include <ldsodefs.h>
>>>> -#include "spawn_int.h"
>>>> +#include <spawn.h>
>>>> +#include <spawn_int.h>
>>>> +#include <sysdep.h>
>>>> +#include <sys/resource.h>
>>>
>>> Suprious changes?
>>
>> In fact I cleanup the include range a bit, if you prefer I can remove this
>> change from this set.
> 
> Hmm.  I think <arch-fd_to_filename.h> is not used here?

Not anymore indeed, I will remove it.

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

* Re: [PATCH 2/3] io: Add closefrom [BZ #10353]
  2020-12-22 12:41         ` Adhemerval Zanella
@ 2020-12-22 13:17           ` Florian Weimer
  2020-12-22 13:28             ` Adhemerval Zanella
  0 siblings, 1 reply; 19+ messages in thread
From: Florian Weimer @ 2020-12-22 13:17 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: Adhemerval Zanella via Libc-alpha

* Adhemerval Zanella:

>> Right, but I think it's needed for correctness.  closefrom (3) should
>> work even if all descriptors are open.
>
> Alright, I think we can do something like:
>
>   int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY, 0);
>   if (dirfd == -1 && errno == EMFILE)
>     {
>       int maxfd = __getdtablesize ();
>       for (int i = lowfd; i < maxfd; i++)
> 	if (__close_nocancel (i) == 0)
> 	  break;
>       dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY, 0);
>       if (dirfd == -1)
>         goto err;
>     }
>

I suggest errno != ENOENT (not mounted /proc), but otherwise looks good.

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


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

* Re: [PATCH 2/3] io: Add closefrom [BZ #10353]
  2020-12-22 13:17           ` Florian Weimer
@ 2020-12-22 13:28             ` Adhemerval Zanella
  2020-12-22 13:34               ` Florian Weimer
  0 siblings, 1 reply; 19+ messages in thread
From: Adhemerval Zanella @ 2020-12-22 13:28 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Adhemerval Zanella via Libc-alpha



On 22/12/2020 10:17, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>>> Right, but I think it's needed for correctness.  closefrom (3) should
>>> work even if all descriptors are open.
>>
>> Alright, I think we can do something like:
>>
>>   int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY, 0);
>>   if (dirfd == -1 && errno == EMFILE)
>>     {
>>       int maxfd = __getdtablesize ();
>>       for (int i = lowfd; i < maxfd; i++)
>> 	if (__close_nocancel (i) == 0)
>> 	  break;
>>       dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY, 0);
>>       if (dirfd == -1)
>>         goto err;
>>     }
>>
> 
> I suggest errno != ENOENT (not mounted /proc), but otherwise looks good.

Do you mean fail with /proc is not mounted? 

  int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY, 0);
  if (dirfd == -1)
    {
      if (errno != EMFILE)
        goto err;

      int maxfd = __getdtablesize ();
      for (int i = lowfd; i < maxfd; i++)
        if (__close_nocancel (i) == 0)
 	  break;
      dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY, 0);
      if (dirfd == -1)
        goto err;
    }

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

* Re: [PATCH 2/3] io: Add closefrom [BZ #10353]
  2020-12-22 13:28             ` Adhemerval Zanella
@ 2020-12-22 13:34               ` Florian Weimer
  0 siblings, 0 replies; 19+ messages in thread
From: Florian Weimer @ 2020-12-22 13:34 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: Adhemerval Zanella via Libc-alpha

* Adhemerval Zanella:

> On 22/12/2020 10:17, Florian Weimer wrote:
>> * Adhemerval Zanella:
>> 
>>>> Right, but I think it's needed for correctness.  closefrom (3) should
>>>> work even if all descriptors are open.
>>>
>>> Alright, I think we can do something like:
>>>
>>>   int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY, 0);
>>>   if (dirfd == -1 && errno == EMFILE)
>>>     {
>>>       int maxfd = __getdtablesize ();
>>>       for (int i = lowfd; i < maxfd; i++)
>>> 	if (__close_nocancel (i) == 0)
>>> 	  break;
>>>       dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY, 0);
>>>       if (dirfd == -1)
>>>         goto err;
>>>     }
>>>
>> 
>> I suggest errno != ENOENT (not mounted /proc), but otherwise looks good.
>
> Do you mean fail with /proc is not mounted?

Yes, and that's what ENOENT corresponds to.  Closing descriptors may
also make ENFILE and ENOMEM errors go away, which is why I'm a bit
doubtful about the EMFILE check.

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


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

* Re: [PATCH 1/3] Linux: Add close_range
  2020-12-22 11:41     ` Florian Weimer
  2020-12-22 11:47       ` Adhemerval Zanella
@ 2020-12-23 12:33       ` Christian Brauner
  1 sibling, 0 replies; 19+ messages in thread
From: Christian Brauner @ 2020-12-23 12:33 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Adhemerval Zanella, Adhemerval Zanella via Libc-alpha

On Tue, Dec 22, 2020 at 12:41:50PM +0100, Florian Weimer via Libc-alpha wrote:
> * Adhemerval Zanella:
> 
> >> I think we generally use int for file descriptors, following POSIX.
> >
> > The Linux interface uses unsigned integer, meaning that negative values
> > won't really trigger an invalid usage (kernel will return EINVAL if 
> > second argument is larger than first one though).
> >
> > I would prefer for syscall wrapper to be close as possible of the kernel
> > interface, otherwise it would require to add additional semantic to
> > handle potential pitfall cases.
> >
> > On this case, if we go for 'int' as argument should we return EBADF 
> > for invalid handles?
> 
> Hmm.  I think unsigned int is needed for ~0U to work, which is what you
> used in the tests.  If that's what applications use today when issuing
> the syscall directly, I think we need to stick to unsigned int.

For the record, the initial reason we chose unsigned int for
close_range() was that the close() syscall uses unsigned int too:

SYSCALL_DEFINE1(close, unsigned int, fd)
SYSCALL_DEFINE3(close_range, unsigned int, fd, unsigned int, max_fd,
		unsigned int, flags)

Furthermore, the kernel doesn't care whether the fd is negative. It
simply checks whether the passed in fd number falls within the possible
range of the fdtable, i.e. fd < fdt->max_fds. If the passed-in fd falls
within the possible range that the fdtable can handle it will check
whether there's a file open at that position in the fdtable, i.e. from
the kernel's perspective "negative" fd values aren't special in any way.

But from what I can tell a lot of (non-libc) userspace isn't aware of
the fact that the kernel uses unsigned int which can lead to some
confusion. A little while ago I had to talk to Lennart about this when
they added support for close_range() which they had been waiting for.
Their syscall wrapper is now documented with:

/* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while
 * userspace exclusively uses signed integers for fds. We don't know just yet how glibc is going to
 * wrap this syscall, but let's assume it's going to be similar to what they do for close(),
 * i.e. make the same unsigned → signed type change from the raw kernel syscall compared to the
 * userspace wrapper. There's only one caveat for this: unlike for close() there's the special
 * UINT_MAX fd value for the 'end_fd' argument. Let's safely map that to -1 here. And let's refuse
 * any other negative values. */
https://github.com/systemd/systemd/commit/441e0fdb900b49888fb6d7901a2b5aa92c0a2017

Christian

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

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

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-21 21:50 [PATCH 1/3] Linux: Add close_range Adhemerval Zanella
2020-12-21 21:50 ` [PATCH 2/3] io: Add closefrom [BZ #10353] Adhemerval Zanella
2020-12-22 10:49   ` Florian Weimer
2020-12-22 11:50     ` Adhemerval Zanella
2020-12-22 11:57       ` Florian Weimer
2020-12-22 12:41         ` Adhemerval Zanella
2020-12-22 13:17           ` Florian Weimer
2020-12-22 13:28             ` Adhemerval Zanella
2020-12-22 13:34               ` Florian Weimer
2020-12-21 21:50 ` [PATCH 3/3] posix: Add posix_spawn_file_actions_closefrom Adhemerval Zanella
2020-12-22 11:32   ` Florian Weimer
2020-12-22 11:56     ` Adhemerval Zanella
2020-12-22 12:00       ` Florian Weimer
2020-12-22 12:46         ` Adhemerval Zanella
2020-12-22  9:05 ` [PATCH 1/3] Linux: Add close_range Florian Weimer
2020-12-22 11:35   ` Adhemerval Zanella
2020-12-22 11:41     ` Florian Weimer
2020-12-22 11:47       ` Adhemerval Zanella
2020-12-23 12:33       ` Christian Brauner

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).