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);
/* Close all other file descriptors. */
closeMostFDs({STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO});
closeExtraFDs();
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__
// 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 {
for (auto & s : readDirectory("/proc/self/fd")) {
auto fd = std::stoi(s.name);
if (!exceptions.count(fd)) {
if (fd > MAX_KEPT_FD) {
debug("closing leaked FD %d", fd);
close(fd);
}
@ -236,9 +247,8 @@ void closeMostFDs(const std::set<int> & exceptions)
int maxFD = 0;
maxFD = sysconf(_SC_OPEN_MAX);
for (int fd = 0; fd < maxFD; ++fd)
if (!exceptions.count(fd))
close(fd); /* ignore result */
for (int fd = MAX_KEPT_FD + 1; fd < maxFD; ++fd)
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.
*/
void closeMostFDs(const std::set<int> & exceptions);
void closeExtraFDs();
/**
* Set the close-on-exec flag for the given file descriptor.