libutil: rename and optimize closeMostFDs

this is only used to close non-stdio files in derivation sandboxes. we
may as well encode that in its name, drop the unnecessary integer set,
and use close_range to deal with the actual closing of files. not only
is this clearer, it also makes sandbox setup on linux fast by 1ms each

Change-Id: Id90e259a49c7bc896189e76bfbbf6ef2c0bcd3b2
This commit is contained in:
eldritch horrors 2024-08-09 21:17:52 +02:00
parent 35a2f28a46
commit c7d97802e4
3 changed files with 18 additions and 8 deletions

View file

@ -1618,7 +1618,7 @@ void LocalDerivationGoal::runChild()
throw SysError("changing into '%1%'", tmpDir); throw SysError("changing into '%1%'", tmpDir);
/* Close all other file descriptors. */ /* Close all other file descriptors. */
closeMostFDs({STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}); closeExtraFDs();
setPersonality(drv->platform); setPersonality(drv->platform);

View file

@ -218,13 +218,24 @@ void Pipe::close()
} }
void closeMostFDs(const std::set<int> & exceptions) void closeExtraFDs()
{ {
constexpr int MAX_KEPT_FD = 2;
static_assert(std::max({STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}) == MAX_KEPT_FD);
#if __linux__ #if __linux__
// first try to close_range everything we don't care about. if this
// returns an error with these parameters we're running on a kernel
// that does not implement close_range (i.e. pre 5.9) and fall back
// to the old method. we should remove that though, in some future.
if (close_range(3, ~0U, 0) == 0) {
return;
}
try { try {
for (auto & s : readDirectory("/proc/self/fd")) { for (auto & s : readDirectory("/proc/self/fd")) {
auto fd = std::stoi(s.name); auto fd = std::stoi(s.name);
if (!exceptions.count(fd)) { if (fd > MAX_KEPT_FD) {
debug("closing leaked FD %d", fd); debug("closing leaked FD %d", fd);
close(fd); close(fd);
} }
@ -236,8 +247,7 @@ void closeMostFDs(const std::set<int> & exceptions)
int maxFD = 0; int maxFD = 0;
maxFD = sysconf(_SC_OPEN_MAX); maxFD = sysconf(_SC_OPEN_MAX);
for (int fd = 0; fd < maxFD; ++fd) for (int fd = MAX_KEPT_FD + 1; fd < maxFD; ++fd)
if (!exceptions.count(fd))
close(fd); /* ignore result */ close(fd); /* ignore result */
} }

View file

@ -66,10 +66,10 @@ public:
}; };
/** /**
* Close all file descriptors except those listed in the given set. * Close all file descriptors except stdio fds (ie 0, 1, 2).
* Good practice in child processes. * Good practice in child processes.
*/ */
void closeMostFDs(const std::set<int> & exceptions); void closeExtraFDs();
/** /**
* Set the close-on-exec flag for the given file descriptor. * Set the close-on-exec flag for the given file descriptor.