From patchwork Tue Jul 6 14:58:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 44176 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A55B9388E825 for ; Tue, 6 Jul 2021 15:13:17 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A55B9388E825 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1625584397; bh=zRRl/KeRrgK9FKFzGg+4ZIA/UUG6tqBku6liQ9iWvbU=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=Oh912J1I3iUfn7KJKcnKQL51FJFZdCaC5qDCiAbB/434M6YklulFxKK5qA2DfBd64 tEBLEf5xpMJwTYOcitIQGX20pBlNnYoBmUcvDN3oW3ewmJVmGxlGEESBlbp6LSyk3+ dsV/kc8DUIu+fXK/O0gsT92fcHE5kJ/zO+jqJFFs= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pf1-x42d.google.com (mail-pf1-x42d.google.com [IPv6:2607:f8b0:4864:20::42d]) by sourceware.org (Postfix) with ESMTPS id 3BBDA388E83C for ; Tue, 6 Jul 2021 14:58:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 3BBDA388E83C Received: by mail-pf1-x42d.google.com with SMTP id y2so6574257pff.11 for ; Tue, 06 Jul 2021 07:58:50 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=zRRl/KeRrgK9FKFzGg+4ZIA/UUG6tqBku6liQ9iWvbU=; b=un1lpaFo6DXLq7F+iW/nvoJs4gShYJ9kgNjwPxG/h+XKQ3RRRzcpXNXlx7QBjPJd8l m0hF1qlRWS6DXaSc2Isl7AVSADyhd4A8akkDfepgxJ2Ha9NZ3dFHIz4+qjn0zRGJfFN8 EdvrYLtfqe4u15cJ9RDIR32vZxhSiSuXlgjS1YwPd4zsXGZ/V51zVvK34deWKghMCSOL Fr7pKHrxJXb40zkI0zRq+KRUCZUZRFLtHVCSFEDRM/JnQ/4NRCybBRIlQgA5TcEKNFb2 wp+fw4vBdO6mUEg7N4QOq8oR1noxXOZ5xM9xFNqq8Aru6MASI/uVms+jq4wO28apivpA Tq2w== X-Gm-Message-State: AOAM53162ZkwZfdA2WwMxngLIYh6f4aQsiQ0vjezz81KK9sLyImOeOmA 6Wj4FiUdvwr0y3AQLxRljRLzxG2bypDw+w== X-Google-Smtp-Source: ABdhPJxQ2ceps2oOI4axIN0JCUa4EnojXq7AQWrzLoTOvWP4kLgW02sWQrPNrE65FIZxArJcxgreKA== X-Received: by 2002:a63:1542:: with SMTP id 2mr21318856pgv.329.1625583528914; Tue, 06 Jul 2021 07:58:48 -0700 (PDT) Received: from birita.. ([177.194.59.218]) by smtp.gmail.com with ESMTPSA id n23sm19018488pgv.76.2021.07.06.07.58.47 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Jul 2021 07:58:48 -0700 (PDT) To: libc-alpha@sourceware.org Subject: [PATCH v7 3/4] io: Add closefrom [BZ #10353] Date: Tue, 6 Jul 2021 11:58:38 -0300 Message-Id: <20210706145839.1658623-4-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210706145839.1658623-1-adhemerval.zanella@linaro.org> References: <20210706145839.1658623-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Adhemerval Zanella via Libc-alpha From: Adhemerval Zanella Reply-To: Adhemerval Zanella Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" The function closes all open file descriptors greater than or equal to input argument. Negative values are clamped to 0, i.e, it will close all file descriptors. As indicated by the bug report, this is a common symbol provided by different systems (Solaris, OpenBSD, NetBSD, FreeBSD) and, although its has inherent issues with not taking in consideration internal libc file descriptors (such as syslog), this is also a common feature used in multiple projects [1][2][3][4][5]. The Linux fallback implementation iterates over /proc and close all file descriptors sequentially. Although it was raised the questioning whether getdents on /proc/self/fd might return disjointed entries when file descriptor are closed; it does not seems the case on my testing on multiple kernel (v4.18, v5.4, v5.9) and the same strategy is used on different projects [1][2][3][5]. Also, the interface is set a fail-safe meaning that a failure in the fallback results in a process abort. Checked on x86_64-linux-gnu on kernel v5.11 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 | 4 +- io/Versions | 3 + io/closefrom.c | 34 ++++ io/tst-closefrom.c | 152 ++++++++++++++++++ manual/llio.texi | 10 ++ posix/unistd.h | 6 + sysdeps/mach/hurd/i386/libc.abilist | 1 + sysdeps/unix/sysv/linux/Makefile | 3 +- sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 + sysdeps/unix/sysv/linux/arc/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/le/libc.abilist | 1 + sysdeps/unix/sysv/linux/closefrom.c | 35 ++++ sysdeps/unix/sysv/linux/closefrom_fallback.c | 97 +++++++++++ sysdeps/unix/sysv/linux/csky/libc.abilist | 1 + sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 + sysdeps/unix/sysv/linux/i386/libc.abilist | 1 + sysdeps/unix/sysv/linux/ia64/libc.abilist | 1 + .../sysv/linux/m68k/coldfire/libc.abilist | 1 + .../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 + .../sysv/linux/microblaze/be/libc.abilist | 1 + .../sysv/linux/microblaze/le/libc.abilist | 1 + .../sysv/linux/mips/mips32/fpu/libc.abilist | 1 + .../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 + .../sysv/linux/mips/mips64/n32/libc.abilist | 1 + .../sysv/linux/mips/mips64/n64/libc.abilist | 1 + sysdeps/unix/sysv/linux/nios2/libc.abilist | 1 + .../linux/powerpc/powerpc32/fpu/libc.abilist | 1 + .../powerpc/powerpc32/nofpu/libc.abilist | 1 + .../linux/powerpc/powerpc64/be/libc.abilist | 1 + .../linux/powerpc/powerpc64/le/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv32/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv64/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-32/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-64/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/le/libc.abilist | 1 + .../sysv/linux/sparc/sparc32/libc.abilist | 1 + .../sysv/linux/sparc/sparc64/libc.abilist | 1 + .../unix/sysv/linux/x86_64/64/libc.abilist | 1 + .../unix/sysv/linux/x86_64/x32/libc.abilist | 1 + 44 files changed, 380 insertions(+), 2 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 be04b217fe..e01a245ac5 100644 --- a/NEWS +++ b/NEWS @@ -63,6 +63,10 @@ Major new features: * On Linux, the close_range function has been added. It allows efficiently closing a range of file descriptors on recent kernels (version 5.9). +* The function closefrom has been added. It closes all file descriptors + greater than given integer. This function is a GNU extension, although it + also present in other systems. + Deprecated and removed features, and other changes affecting compatibility: * The function pthread_mutex_consistent_np has been deprecated; programs diff --git a/include/unistd.h b/include/unistd.h index 691405a945..114a43128e 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -158,6 +158,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 1a16990205..ebb7d56d67 100644 --- a/io/Makefile +++ b/io/Makefile @@ -56,7 +56,8 @@ routines := \ sendfile sendfile64 copy_file_range \ utimensat futimens file_change_detection \ fts64-time64 \ - ftw64-time64 + ftw64-time64 \ + closefrom others := pwd test-srcs := ftwtest ftwtest-time64 @@ -77,6 +78,7 @@ tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ tst-lutimes \ tst-futimens \ tst-utimensat \ + tst-closefrom \ tests-time64 := \ tst-futimens-time64 \ diff --git a/io/Versions b/io/Versions index 88caf76bbc..4e19540885 100644 --- a/io/Versions +++ b/io/Versions @@ -137,6 +137,9 @@ libc { stat; stat64; fstat; fstat64; lstat; lstat64; fstatat; fstatat64; mknod; mknodat; } + GLIBC_2.34 { + closefrom; + } GLIBC_PRIVATE { __libc_fcntl64; __fcntl_nocancel; diff --git a/io/closefrom.c b/io/closefrom.c new file mode 100644 index 0000000000..01660a7531 --- /dev/null +++ b/io/closefrom.c @@ -0,0 +1,34 @@ +/* Close a range of file descriptors. + Copyright (C) 2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +void +__closefrom (int lowfd) +{ + int maxfd = __getdtablesize (); + if (maxfd == -1) + __fortify_fail ("closefrom failed to get the file descriptor table size"); + + for (int i = 0; i < maxfd; i++) + if (i >= lowfd) + __close_nocancel_nostatus (i); +} +weak_alias (__closefrom, closefrom) diff --git a/io/tst-closefrom.c b/io/tst-closefrom.c new file mode 100644 index 0000000000..d4c187073c --- /dev/null +++ b/io/tst-closefrom.c @@ -0,0 +1,152 @@ +/* Smoke test for the closefrom. + Copyright (C) 2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define NFDS 100 + +static int +open_multiple_temp_files (void) +{ + /* Check if the temporary file descriptor has no no gaps. */ + int lowfd = xopen ("/dev/null", O_RDONLY, 0600); + for (int i = 1; i <= NFDS; i++) + TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), lowfd + i); + return lowfd; +} + +static int +closefrom_test (void) +{ + struct support_descriptors *descrs = support_descriptors_list (); + + int lowfd = open_multiple_temp_files (); + + const int maximum_fd = lowfd + NFDS; + const int half_fd = lowfd + NFDS / 2; + const int gap = maximum_fd / 4; + + /* Close half of the descriptors and check result. */ + closefrom (half_fd); + + for (int i = half_fd; i <= maximum_fd; i++) + { + TEST_COMPARE (fcntl (i, F_GETFL), -1); + TEST_COMPARE (errno, EBADF); + } + for (int i = 0; i < half_fd; i++) + TEST_VERIFY (fcntl (i, F_GETFL) > -1); + + /* Create some gaps, close up to a threshold, and check result. */ + xclose (lowfd + 35); + xclose (lowfd + 38); + xclose (lowfd + 42); + xclose (lowfd + 46); + + /* Close half of the descriptors and check result. */ + closefrom (gap); + for (int i = gap + 1; i < maximum_fd; i++) + { + TEST_COMPARE (fcntl (i, F_GETFL), -1); + TEST_COMPARE (errno, EBADF); + } + for (int i = 0; i < gap; i++) + TEST_VERIFY (fcntl (i, F_GETFL) > -1); + + /* Close the remmaining but the last one. */ + closefrom (lowfd + 1); + for (int i = lowfd + 1; i <= maximum_fd; i++) + { + TEST_COMPARE (fcntl (i, F_GETFL), -1); + TEST_COMPARE (errno, EBADF); + } + TEST_VERIFY (fcntl (lowfd, F_GETFL) > -1); + + /* Close the last one. */ + closefrom (lowfd); + TEST_COMPARE (fcntl (lowfd, F_GETFL), -1); + TEST_COMPARE (errno, EBADF); + + /* Double check by check the /proc. */ + support_descriptors_check (descrs); + support_descriptors_free (descrs); + + return 0; +} + +/* Check if closefrom works even when no new file descriptors can be + created. */ +static int +closefrom_test_file_desc_limit (void) +{ + int max_fd = NFDS; + { + struct rlimit rl; + if (getrlimit (RLIMIT_NOFILE, &rl) == -1) + FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m"); + + max_fd = (rl.rlim_cur < max_fd ? rl.rlim_cur : max_fd); + rl.rlim_cur = max_fd; + + if (setrlimit (RLIMIT_NOFILE, &rl) == 1) + FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m"); + } + + /* Exhauste the file descriptor limit. */ + int lowfd = xopen ("/dev/null", O_RDONLY, 0600); + for (;;) + { + int fd = open ("/dev/null", O_RDONLY, 0600); + if (fd == -1) + { + if (errno != EMFILE) + FAIL_EXIT1 ("open: %m"); + break; + } + TEST_VERIFY_EXIT (fd < max_fd); + } + + closefrom (lowfd); + for (int i = lowfd; i < NFDS; i++) + { + TEST_COMPARE (fcntl (i, F_GETFL), -1); + TEST_COMPARE (errno, EBADF); + } + + return 0; +} + +static int +do_test (void) +{ + closefrom_test (); + closefrom_test_file_desc_limit (); + + return 0; +} + +#include diff --git a/manual/llio.texi b/manual/llio.texi index ea6d34dd5a..d1ed9e6490 100644 --- a/manual/llio.texi +++ b/manual/llio.texi @@ -332,6 +332,16 @@ The kernel does not implement the required functionality. @end table @end deftypefun +@deftypefun void closefrom (int @var{lowfd}) +@standards{GNU, unistd.h} +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}} + +The function @code{closefrom} closes all file descriptors larger than or equal +to @var{lowfd} then @var{lowfd}. This function is similar to call +@code{close} applied to the specified file descriptor range. + +Already closed file descriptors are ignored. +@end deftypefun @node I/O Primitives @section Input and Output Primitives diff --git a/posix/unistd.h b/posix/unistd.h index 217c6c5363..3dca65732f 100644 --- a/posix/unistd.h +++ b/posix/unistd.h @@ -357,6 +357,12 @@ extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence) __THROW. */ extern int close (int __fd); +#ifdef __USE_MISC +/* Close all open file descriptors greater than or equal to LOWFD. + Negative LOWFD is clamped to 0. */ +extern void closefrom (int __lowfd) __THROW; +#endif + /* Read NBYTES into BUF from FD. Return the number read, -1 for errors or 0 for EOF. diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist index fcfe64f26b..475bf2d6e9 100644 --- a/sysdeps/mach/hurd/i386/libc.abilist +++ b/sysdeps/mach/hurd/i386/libc.abilist @@ -2225,6 +2225,7 @@ GLIBC_2.34 _Fork F GLIBC_2.34 __isnanf128 F GLIBC_2.34 __libc_start_main F GLIBC_2.34 _hurd_libc_proc_init F +GLIBC_2.34 closefrom F GLIBC_2.34 dladdr F GLIBC_2.34 dladdr1 F GLIBC_2.34 dlclose F diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index e308711168..d45a16af8b 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -64,7 +64,8 @@ sysdep_routines += adjtimex clone umount umount2 readahead sysctl \ pselect32 \ xstat fxstat lxstat xstat64 fxstat64 lxstat64 \ fxstatat fxstatat64 \ - xmknod xmknodat convert_scm_timestamps + xmknod xmknodat convert_scm_timestamps \ + 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 c32f5898fe..5f6c9768c5 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2410,6 +2410,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index cb10eadbb9..5fcf38ad44 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -2509,6 +2509,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist index a697c930e1..0903ec5b27 100644 --- a/sysdeps/unix/sysv/linux/arc/libc.abilist +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist @@ -2169,6 +2169,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist index 7dbe38dcb7..38f56b13a7 100644 --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist @@ -303,6 +303,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist index 0ee69506ea..3b8522f297 100644 --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist @@ -300,6 +300,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/closefrom.c b/sysdeps/unix/sysv/linux/closefrom.c new file mode 100644 index 0000000000..f5d7342c2c --- /dev/null +++ b/sysdeps/unix/sysv/linux/closefrom.c @@ -0,0 +1,35 @@ +/* Close a range of file descriptors. Linux version. + Copyright (C) 2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +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..61e71d388d --- /dev/null +++ b/sysdeps/unix/sysv/linux/closefrom_fallback.c @@ -0,0 +1,97 @@ +/* Close a range of file descriptors. Linux version. + Copyright (C) 2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +/* Fallback code: iterates over /proc/self/fd, closing each file descriptor + that fall on the criteria. */ +_Bool +__closefrom_fallback (int from) +{ + bool ret = false; + + int dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY, + 0); + if (dirfd == -1) + { + /* The closefrom should work even when process can't open new files. */ + if (errno == ENOENT) + goto err; + + for (int i = from; i < INT_MAX; i++) + { + int r = __close_nocancel (i); + if (r == 0 || (r == -1 && errno != EBADF)) + break; + } + + dirfd = __open_nocancel (FD_TO_FILENAME_PREFIX, O_RDONLY | O_DIRECTORY, + 0); + if (dirfd == -1) + goto err; + } + + char buffer[1024]; + while (true) + { + ssize_t ret = __getdents64 (dirfd, buffer, sizeof (buffer)); + if (ret == -1) + goto err; + else if (ret == 0) + break; + + /* If any file descriptor is closed it resets the /proc/self position + read again from the start (to obtain any possible kernel update). */ + bool closed = false; + char *begin = buffer, *end = buffer + ret; + while (begin != end) + { + unsigned short int d_reclen; + memcpy (&d_reclen, begin + offsetof (struct dirent64, d_reclen), + sizeof (d_reclen)); + const char *dname = begin + offsetof (struct dirent64, d_name); + begin += d_reclen; + + if (dname[0] == '.') + continue; + + int fd = 0; + for (const char *s = dname; (unsigned int) (*s) - '0' < 10; s++) + fd = 10 * fd + (*s - '0'); + + if (fd == dirfd || fd < from) + continue; + + /* We ignore close errors because EBADF, EINTR, and EIO means the + descriptor has been released. */ + __close_nocancel (fd); + closed = true; + } + + if (closed && __lseek (dirfd, 0, SEEK_SET) < 0) + goto err; + } + + ret = true; +err: + __close_nocancel (dirfd); + return ret; +} diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist index c5849e1da2..0552d47461 100644 --- a/sysdeps/unix/sysv/linux/csky/libc.abilist +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist @@ -2435,6 +2435,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index 9368379d9d..ed3defc560 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -2388,6 +2388,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index e4a16d0bcf..ad59582311 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -2572,6 +2572,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist index f7a29d00de..2b54a7abec 100644 --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist @@ -2347,6 +2347,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index 7a1b38fe81..3089cd413a 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -304,6 +304,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index 64591d99cc..d1714c6adc 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2515,6 +2515,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist index 1769dc5c80..66e19a4c27 100644 --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist @@ -2486,6 +2486,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist index 4373d181fb..7ffe575d6b 100644 --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist @@ -2483,6 +2483,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index c714662ff3..b1e177971a 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -2480,6 +2480,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist index d6d9f3b5f6..bbb5849961 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist @@ -2478,6 +2478,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index 287fc03201..cfd0d2733b 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -2486,6 +2486,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index 92dc711ee2..79bcb1bedb 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -2398,6 +2398,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist index b1c4e54a70..54048ea725 100644 --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist @@ -2525,6 +2525,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index 1ed9e1c9a7..300c1a187e 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -2542,6 +2542,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist index 953e05cc33..7f00f9ec7c 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -2575,6 +2575,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist index e6bcab06d5..26fd4762ad 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist @@ -2311,6 +2311,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist index 525cb85de2..02581f12cc 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist @@ -2606,6 +2606,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist index a1d89d2f14..6f01f5df0d 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist @@ -2171,6 +2171,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist index 84f7a8561a..d69e1589b7 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2371,6 +2371,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index edd1dbbbdb..b9440770af 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -2540,6 +2540,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index 19160f33ba..274c743a2a 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -2348,6 +2348,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist index 8e99b18060..42138cba69 100644 --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist @@ -2395,6 +2395,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist index f876e152b7..57f7df559c 100644 --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist @@ -2392,6 +2392,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index a6fa1a1b29..1929d5801d 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -2535,6 +2535,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index 4f6166a8f1..8fe2d5a9d9 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2370,6 +2370,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index e12670c1a4..3412dcaf69 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2326,6 +2326,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index 9b524d7b72..04d540e619 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2425,6 +2425,7 @@ GLIBC_2.34 aio_write F GLIBC_2.34 aio_write64 F GLIBC_2.34 call_once F GLIBC_2.34 close_range F +GLIBC_2.34 closefrom F GLIBC_2.34 cnd_broadcast F GLIBC_2.34 cnd_destroy F GLIBC_2.34 cnd_init F