gc: Read arguments on darwin

This commit is contained in:
Artemis Tosini 2024-03-30 21:17:28 -04:00
parent 8ce48856e8
commit b02f1564d3

View file

@ -24,6 +24,7 @@
#ifdef __APPLE__ #ifdef __APPLE__
#include <sys/proc_info.h> #include <sys/proc_info.h>
#include <sys/sysctl.h>
#include <libproc.h> #include <libproc.h>
#endif #endif
@ -427,6 +428,8 @@ static void readProcfsRoots(const Path & storeDir, UncheckedRoots & unchecked)
#ifdef __APPLE__ #ifdef __APPLE__
static void readLibprocRoots(const Path & storeDir, UncheckedRoots & unchecked) static void readLibprocRoots(const Path & storeDir, UncheckedRoots & unchecked)
{ {
auto storePathRegex = std::regex(quoteRegexChars(storeDir) + R"(/[0-9a-z]+[0-9a-zA-Z\+\-\._\?=]*)");
int pidBufSize = proc_listpids(PROC_ALL_PIDS, 0, nullptr, 0); int pidBufSize = proc_listpids(PROC_ALL_PIDS, 0, nullptr, 0);
if (pidBufSize <= 0 || pidBufSize % sizeof(int) != 0) if (pidBufSize <= 0 || pidBufSize % sizeof(int) != 0)
throw SysError("Listing PIDs"); throw SysError("Listing PIDs");
@ -497,12 +500,40 @@ static void readLibprocRoots(const Path & storeDir, UncheckedRoots & unchecked)
if ((errno == ESRCH) || (errno == EINVAL) || (errno == EPERM)) break; if ((errno == ESRCH) || (errno == EINVAL) || (errno == EPERM)) break;
throw SysError("Getting pid %1% region path", pid); throw SysError("Getting pid %1% region path", pid);
} }
unchecked[std::string(regionInfo.prp_vip.vip_path)].emplace("{libproc/region}"); unchecked[std::string(regionInfo.prp_vip.vip_path)].emplace("{libproc/region}");
nextAddr = regionInfo.prp_prinfo.pri_address + regionInfo.prp_prinfo.pri_size; nextAddr = regionInfo.prp_prinfo.pri_address + regionInfo.prp_prinfo.pri_size;
} }
// Arguments and environment variables
// We can't read environment variables of binaries with with entitlements unless
// nix has the `com.apple.private.read-environment-variables` entitlement or SIP is off
// We can read arguments for all applications though.
// Yes, it's a sysctl, the proc_info and sysctl APIs are mostly similar,
// but both have exclusive capabilities
// We don't care about what is args and what is environment so we could use
// KERN_PROCARGS, but KERN_PROCARGS2 saves about 20ms in my testing
int sysctlName[3] = {CTL_KERN, KERN_PROCARGS2, pid};
size_t argsSize = 0;
if (sysctl(sysctlName, 3, nullptr, &argsSize, nullptr, 0) < 0) {
throw SysError("Reading pid %1% arguments");
}
std::vector<char> args(argsSize);
if (sysctl(sysctlName, 3, args.data(), &argsSize, nullptr, 0) < 0) {
throw SysError("Reading pid %1% arguments");
}
if (argsSize < args.size())
args.resize(argsSize);
auto env_end = std::sregex_iterator{};
for (auto i = std::sregex_iterator{args.begin(), args.end(), storePathRegex}; i != env_end; ++i)
unchecked[i->str()].emplace("{libproc/args}");
// TODO: per-thread cwds (apparently exist but I don't see them much) // TODO: per-thread cwds (apparently exist but I don't see them much)
} }