mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-15 02:36:16 +02:00
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
(cherry-picked and adapted from
c7d97802e4
)
Co-authored-by: Eelco Dolstra <edolstra@gmail.com>
Co-authored-by: Cole Helbling <cole.e.helbling@outlook.com>
Co-authored-by: John Ericson <git@JohnEricson.me>
This commit is contained in:
parent
af26fe3934
commit
03b258bf97
3 changed files with 28 additions and 8 deletions
|
@ -1993,7 +1993,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. */
|
||||||
unix::closeMostFDs({STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO});
|
unix::closeExtraFDs();
|
||||||
|
|
||||||
#if __linux__
|
#if __linux__
|
||||||
linux::setPersonality(drv->platform);
|
linux::setPersonality(drv->platform);
|
||||||
|
|
|
@ -143,10 +143,10 @@ public:
|
||||||
namespace unix {
|
namespace unix {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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<Descriptor> & 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.
|
||||||
|
|
|
@ -120,14 +120,35 @@ void Pipe::create()
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void unix::closeMostFDs(const std::set<int> & exceptions)
|
#if __linux__ || __FreeBSD__
|
||||||
|
// In future we can use a syscall wrapper, but at the moment musl and older glibc version don't support it.
|
||||||
|
static int unix_close_range(unsigned int first, unsigned int last, int flags)
|
||||||
{
|
{
|
||||||
|
return syscall(SYS_close_range, first, last, (unsigned int)flags);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void unix::closeExtraFDs()
|
||||||
|
{
|
||||||
|
constexpr int MAX_KEPT_FD = 2;
|
||||||
|
static_assert(std::max({STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}) == MAX_KEPT_FD);
|
||||||
|
|
||||||
|
#if __linux__ || __FreeBSD__
|
||||||
|
// 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 (unix_close_range(MAX_KEPT_FD + 1, ~0U, 0) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if __linux__
|
#if __linux__
|
||||||
try {
|
try {
|
||||||
for (auto & s : std::filesystem::directory_iterator{"/proc/self/fd"}) {
|
for (auto & s : std::filesystem::directory_iterator{"/proc/self/fd"}) {
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
auto fd = std::stoi(s.path().filename());
|
auto fd = std::stoi(s.path().filename());
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -142,9 +163,8 @@ void unix::closeMostFDs(const std::set<int> & exceptions)
|
||||||
#if HAVE_SYSCONF
|
#if HAVE_SYSCONF
|
||||||
maxFD = sysconf(_SC_OPEN_MAX);
|
maxFD = sysconf(_SC_OPEN_MAX);
|
||||||
#endif
|
#endif
|
||||||
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 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue