aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreldritch horrors <pennae@lix.systems>2024-08-09 21:17:52 +0200
committereldritch horrors <pennae@lix.systems>2024-08-09 19:59:17 +0000
commitc7d97802e4f59b8621e67cf62275d6a7fde8fe62 (patch)
tree8798b34ab28dd2b704da20a21659de2ad24fda07
parent35a2f28a46613ad185b96d6e38c3f5d13bfc79b5 (diff)
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
-rw-r--r--src/libstore/build/local-derivation-goal.cc2
-rw-r--r--src/libutil/file-descriptor.cc20
-rw-r--r--src/libutil/file-descriptor.hh4
3 files changed, 18 insertions, 8 deletions
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index 8b640e4ad..246cb68f6 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -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);
diff --git a/src/libutil/file-descriptor.cc b/src/libutil/file-descriptor.cc
index be9f8c889..4807869f9 100644
--- a/src/libutil/file-descriptor.cc
+++ b/src/libutil/file-descriptor.cc
@@ -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 */
}
diff --git a/src/libutil/file-descriptor.hh b/src/libutil/file-descriptor.hh
index a83bc028f..7270b73b5 100644
--- a/src/libutil/file-descriptor.hh
+++ b/src/libutil/file-descriptor.hh
@@ -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.