close_range(2) System Calls Manual close_range(2) close_range - C (libc, -lc) #define _GNU_SOURCE /* . feature_test_macros(7) */ #include #include /* Definition of CLOSE_RANGE_* constants */ int close_range(unsigned int first, unsigned int last, int flags); close_range() first last (). . flags - , 0 : CLOSE_RANGE_CLOEXEC ( Linux 5.11) close-on-exec , , . CLOSE_RANGE_UNSHARE Unshare the specified file descriptors from any other processes before closing them, avoiding races with other threads sharing the file descriptor table. close_range() 0. -1 errno . EINVAL flags , first , last. CLOSE_RANGE_UNSHARE ( ): EMFILE The number of open file descriptors exceeds the limit specified in /proc/sys/fs/nr_open (see proc(5)). This error can occur in situations where that limit was lowered before a call to close_range() where the CLOSE_RANGE_UNSHARE flag is specified. ENOMEM . . FreeBSD. Linux 5.9, glibc 2.34. To avoid blindly closing file descriptors in the range of possible file descriptors, this is sometimes implemented (on Linux) by listing open file descriptors in /proc/self/fd/ and calling close(2) on each one. close_range() can take care of this without requiring /proc and within a single system call, which provides significant performance benefits. /* stderr */ close_range(3, ~0U, CLOSE_RANGE_UNSHARE); execve(....); CLOSE_RANGE_UNSHARE unshare(CLONE_FILES); close_range(first, last, 0); but can be more efficient: if the unshared range extends past the current maximum number of file descriptors allocated in the caller's file descriptor table (the common case when last is ~0U), the kernel will unshare a new file descriptor table for the caller up to first, copying as few file descriptors as possible. This avoids subsequent close(2) calls entirely; the whole operation is complete once the table is unshared. This is particularly useful in cases where multiple pre-exec setup steps risk conflicting with each other. For example, setting up a seccomp(2) profile can conflict with a close_range() call: if the file descriptors are closed before the seccomp(2) profile is set up, the profile setup can't use them itself, or control their closure; if the file descriptors are closed afterwards, the seccomp profile can't block the close_range() call or any fallbacks. Using CLOSE_RANGE_CLOEXEC avoids this: the descriptors can be marked before the seccomp(2) profile is set up, and the profile can control access to close_range() without affecting the calling process. The program shown below opens the files named in its command-line arguments, displays the list of files that it has opened (by iterating through the entries in /proc/PID/fd), uses close_range() to close all file descriptors greater than or equal to 3, and then once more displays the process's list of open files. The following example demonstrates the use of the program: $ touch /tmp/a /tmp/b /tmp/c $ ./a.out /tmp/a /tmp/b /tmp/c /tmp/a opened as FD 3 /tmp/b opened as FD 4 /tmp/c opened as FD 5 /proc/self/fd/0 ==> /dev/pts/1 /proc/self/fd/1 ==> /dev/pts/1 /proc/self/fd/2 ==> /dev/pts/1 /proc/self/fd/3 ==> /tmp/a /proc/self/fd/4 ==> /tmp/b /proc/self/fd/5 ==> /tmp/b /proc/self/fd/6 ==> /proc/9005/fd ========= About to call close_range() ======= /proc/self/fd/0 ==> /dev/pts/1 /proc/self/fd/1 ==> /dev/pts/1 /proc/self/fd/2 ==> /dev/pts/1 /proc/self/fd/3 ==> /proc/9005/fd , , /proc/9005/fd, opendir(3). #define _GNU_SOURCE #include #include #include #include #include #include #include /* Show the contents of the symbolic links in /proc/self/fd */ static void show_fds(void) { DIR *dirp; char path[PATH_MAX], target[PATH_MAX]; ssize_t len; struct dirent *dp; dirp = opendir("/proc/self/fd"); if (dirp == NULL) { perror("opendir"); exit(EXIT_FAILURE); } for (;;) { dp = readdir(dirp); if (dp == NULL) break; if (dp->d_type == DT_LNK) { snprintf(path, sizeof(path), "/proc/self/fd/%s", dp->d_name); len = readlink(path, target, sizeof(target)); printf("%s ==> %.*s\n", path, (int) len, target); } } closedir(dirp); } int main(int argc, char *argv[]) { int fd; for (size_t j = 1; j < argc; j++) { fd = open(argv[j], O_RDONLY); if (fd == -1) { perror(argv[j]); exit(EXIT_FAILURE); } printf("%s opened as FD %d\n", argv[j], fd); } show_fds(); printf("========= About to call close_range() =======\n"); if (close_range(3, ~0U, 0) == -1) { perror("close_range"); exit(EXIT_FAILURE); } show_fds(); exit(EXIT_FAILURE); } close(2) () Azamat Hackimov , Dmitriy S. Seregin , Dmitry Bolkhovskikh , Katrin Kutepova , Yuri Kozlov , Kirill Rekhov ; GNU (GNU General Public License - GPL, 3 ) , - . - , , () () () <>. Linux 6.9.1 15 2024 . close_range(2)