$RodHat_
Syscall reference · File descriptors

close_range(2)

Close, or mark close-on-exec, every file descriptor in a range in one call.

Since
Linux 5.9check your kernel →
glibc
glibc 2.34
System
Linux
Man page
close_range(2)

Synopsis

#define _GNU_SOURCE
#include <unistd.h>
#include <linux/close_range.h>

int close_range(unsigned int first, unsigned int last, int flags);

Rod's take

The pre-exec loop that calls close() on every number up to _SC_OPEN_MAX is a million syscalls returning EBADF, and it's sitting in code you depend on right now. close_range(3, ~0U, 0) does it in one. CLOSE_RANGE_UNSHARE does the work on a private copy of the fd table, so sibling threads don't get their descriptors yanked mid-use. CLOSE_RANGE_CLOEXEC is the clever one: leave everything open here, guarantee none of it leaks across exec. The BSDs had closefrom for years. Linux showed up late, but it brought flags.

Flags and arguments that matter

NameWhat it does
CLOSE_RANGE_UNSHAREUnshare the fd table first, so closing doesn't race other threads sharing it.
CLOSE_RANGE_CLOEXECLinux 5.11Set close-on-exec on the range instead of closing the descriptors.
last = ~0UPass UINT_MAX as last to cover everything from first upward.

Errors you will actually hit

errnoMeaning
EINVALflags is not valid, or first is greater than last.
EMFILEWith CLOSE_RANGE_UNSHARE: open fds exceed /proc/sys/fs/nr_open when building the new table.
ENOMEMWith CLOSE_RANGE_UNSHARE: insufficient kernel memory for the new table.

Example

/* in the child, right before exec: nothing above stderr survives */
if (close_range(3, ~0U, CLOSE_RANGE_UNSHARE) < 0)
    err(1, "close_range");
execvp(argv[0], argv);

/* or: keep fds open here, but stop them leaking into children */
close_range(3, ~0U, CLOSE_RANGE_CLOEXEC);
dup2(pipe_wr, 3);   /* dup2 clears FD_CLOEXEC on fd 3 */

Trimmed from the full walkthrough in close_range: one syscall instead of a million EBADFs.

BSD equivalent

FreeBSD: close_range(2) with CLOSE_RANGE_CLOEXEC (FreeBSD 12.2) and closefrom(2) (FreeBSD 8.0). OpenBSD: closefrom(2) (OpenBSD 3.5).

The long version, from the console

Sources

  1. close_range(2), man7.org
  2. closefrom(2), FreeBSD
  3. closefrom(2), OpenBSD

Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.