Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

posix: check glibc version for ::close_range function #378

Open
wants to merge 7 commits into
base: develop
Choose a base branch
from
72 changes: 56 additions & 16 deletions include/boost/process/v2/posix/detail/close_handles.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/posix/detail/close_handles.hpp>
// linux has close_range since 5.19
// linux has close_range since 5.9
// see: https://man.archlinux.org/man/close_range.2.en#HISTORY
// https://elixir.bootlin.com/linux/v5.9/source/fs/open.c#L1318


#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
Expand All @@ -31,7 +33,7 @@
#include <unistd.h>
#define BOOST_PROCESS_V2_HAS_CLOSE_RANGE_AND_CLOSEFROM 1

#elif defined(__sun)
#elif defined(__sun) // if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)

/*https://docs.oracle.com/cd/E36784_01/html/E36874/closefrom-3c.html

Expand All @@ -41,22 +43,45 @@ int fdwalk(int (*func)(void *, int), void *cd);
#include <stdlib.h>
#define BOOST_PROCESS_V2_HAS_PDFORK 1

#elif defined(__linux__)
#elif defined(__linux__) // elif defined(__sun)

#include <linux/version.h>
// define BOOST_PROCESS_V2_POSIX_FORCE_DISABLE_CLOSE_RANGE to force disable any usage of ::close_range()


#include <sys/syscall.h>

// All checks here are intended to check whether target system has ::close_range()
// Note that this checks only valid on glibc. MUSL doens't have ::close_range() anyway. So we don't care about any
// MUSL library macroses
#if defined(__GLIBC__)

// On glibc we also must have ::close_range() wrapper around system call.
// If we're building on system with new kernel, BUT without this wrapper (old glibc) the build will be failed
#include <gnu/libc-version.h>
#if (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 34) && !defined(BOOST_PROCESS_V2_POSIX_FORCE_DISABLE_CLOSE_RANGE)
#define BOOST_PROCESS_V2_HAS_CLOSE_RANGE 1
#endif // __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 34

#endif // ifdef __GLIBC__

// glibc version doesn't meet version requirements or we're building with MUSL.
// Just try to check linux version code. If system call is supported we'll use raw system call
#if !defined(BOOST_PROCESS_V2_HAS_CLOSE_RANGE) && defined(SYS_close_range) && !defined(BOOST_PROCESS_V2_POSIX_FORCE_DISABLE_CLOSE_RANGE)
#define BOOST_PROCESS_V2_HAS_CLOSE_RANGE_SYSCALL 1
#endif // if !defined(BOOST_PROCESS_V2_HAS_CLOSE_RANGE) && LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,0)

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,11,0)

// https://man7.org/linux/man-pages/man2/close_range.2.html
#if defined(BOOST_PROCESS_V2_HAS_CLOSE_RANGE) || defined(BOOST_PROCESS_V2_HAS_CLOSE_RANGE_SYSCALL)
#define BOOST_PROCESS_V2_HAS_ANY_CLOSE_RANGE
#include <linux/close_range.h>
#define BOOST_PROCESS_V2_HAS_CLOSE_RANGE 1
#else
#include <sys/syscall.h>

#else // ifdef BOOST_PROCESS_V2_HAS_CLOSE_RANGE || defined(BOOST_PROCESS_V2_HAS_CLOSE_RANGE_SYSCALL)
#include <dirent.h>
#endif // BOOST_PROCESS_V2_HAS_CLOSE_RANGE || defined(BOOST_PROCESS_V2_HAS_CLOSE_RANGE_SYSCALL)

#endif

#else
#else // elif defined(__linux__)

#include <dirent.h>

Expand All @@ -70,6 +95,21 @@ namespace posix
namespace detail
{

#if defined(BOOST_PROCESS_V2_HAS_ANY_CLOSE_RANGE)

/*!
* Just a convenient wrapper around raw system call or glibc function if present
*/
inline int close_range_wrapper(unsigned int first, unsigned int last, unsigned int flags) {
#if defined(BOOST_PROCESS_V2_HAS_CLOSE_RANGE)
return ::close_range(first, last, flags);
#elif defined(BOOST_PROCESS_V2_HAS_CLOSE_RANGE_SYSCALL)
return ::syscall(SYS_close_range, first, last, flags);
#endif
}

#endif

#if defined(BOOST_PROCESS_V2_HAS_PDFORK)

void close_all(const std::vector<int> & whitelist, error_code & ec)
Expand Down Expand Up @@ -114,7 +154,7 @@ void close_all(const std::vector<int> & whitelist, error_code & ec)
::closefrom(0);
}

#elif defined(BOOST_PROCESS_V2_HAS_CLOSE_RANGE)
#elif defined(BOOST_PROCESS_V2_HAS_ANY_CLOSE_RANGE)


// linux impl - whitelist must be ordered
Expand All @@ -125,7 +165,7 @@ void close_all(const std::vector<int> & whitelist, error_code & ec)
if (!whitelist.empty())
{
if (whitelist.front() != 0)
::close_range(0, whitelist.front() - 1, CLOSE_RANGE_UNSHARE);
close_range_wrapper(0, whitelist.front() - 1, CLOSE_RANGE_UNSHARE);

for (std::size_t idx = 0u;
idx < (whitelist.size() - 1u);
Expand All @@ -135,14 +175,14 @@ void close_all(const std::vector<int> & whitelist, error_code & ec)
const auto next = whitelist[idx + 1];
if ((mine + 1) != next && (mine != next))
{
::close_range(mine + 1, next - 1, CLOSE_RANGE_UNSHARE);
close_range_wrapper(mine + 1, next - 1, CLOSE_RANGE_UNSHARE);
}
}

::close_range(whitelist.back() + 1, std::numeric_limits<int>::max(), CLOSE_RANGE_UNSHARE);
close_range_wrapper(whitelist.back() + 1, std::numeric_limits<int>::max(), CLOSE_RANGE_UNSHARE);
}
else
::close_range(0, std::numeric_limits<int>::max(), CLOSE_RANGE_UNSHARE);
close_range_wrapper(0, std::numeric_limits<int>::max(), CLOSE_RANGE_UNSHARE);
}

#else
Expand Down Expand Up @@ -191,4 +231,4 @@ void close_all(const std::vector<int> & whitelist, error_code & ec)

BOOST_PROCESS_V2_END_NAMESPACE

#endif //BOOST_PROCESS_V2_POSIX_DETAIL_CLOSE_HANDLES_IPP
#endif //BOOST_PROCESS_V2_POSIX_DETAIL_CLOSE_HANDLES_IPP