From 6aca3716f051b5b6bff63d51fff68b9c7ebc7474 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Mon, 20 Oct 2025 17:14:31 +0200 Subject: ExecFork: Use close_range() if available Use close_range() if we have it in preference to iterating over /proc/self/fd and falling back to closing all possible fds. This builds sets of ranges to close that take into account the APT::Keep-Fds vector, and a test case is provided to ensure correctness of the splitting logic. Preference is given to close_range() over /proc as in the optimal case, this results in a single system call! --- apt-pkg/contrib/fileutl.cc | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) (limited to 'apt-pkg') diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index 85997275c..50b983924 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -85,6 +85,7 @@ #include #if __gnu_linux__ +#include #include #endif @@ -919,8 +920,37 @@ pid_t ExecFork(std::set KeepFDs) signal(SIGCONT,SIG_DFL); signal(SIGTSTP,SIG_DFL); - DIR *dir = opendir("/proc/self/fd"); - if (dir != NULL) +#ifdef CLOSE_RANGE_CLOEXEC + // Close all our file descriptors using close_range() if available. This is substantially + // faster than the naive method and may be faster than the /proc/self/fd one. + { + // Used for testing. + auto DebugCloseRange = _config->FindB("Debug::CloseRange", false); + int first = 3; + for (auto keep : KeepFDs) + { + if (keep > first) + { + if (DebugCloseRange) + std::clog << "close_range(" << first << ", " << keep - 1 << ")" << std::endl; + if (close_range(first, keep - 1, CLOSE_RANGE_CLOEXEC)) + goto err; + } + first = keep + 1; + } + if (DebugCloseRange) + std::clog << "close_range(" << first << ", " << ~0U << ")" << std::endl; + if (close_range(first, ~0U, CLOSE_RANGE_CLOEXEC)) + goto err; + + return Process; + err: + if (DebugCloseRange) + std::clog << "close_range() failed" << std::endl; + // fallthrough + } +#endif + if (DIR *dir = opendir("/proc/self/fd")) { struct dirent *ent; while ((ent = readdir(dir))) -- cgit v1.2.3-70-g09d2