diff --git a/src/libstore/platform/linux.cc b/src/libstore/platform/linux.cc index ad8b4e322..03b8bc0be 100644 --- a/src/libstore/platform/linux.cc +++ b/src/libstore/platform/linux.cc @@ -717,6 +717,12 @@ static std::vector compileSyscallFilter() return filter; } +static const std::vector &getSyscallFilter() +{ + static auto filter = compileSyscallFilter(); + return filter; +} + #endif void LinuxLocalDerivationGoal::setupSyscallFilter() @@ -727,11 +733,12 @@ void LinuxLocalDerivationGoal::setupSyscallFilter() if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) throw SysError("PR_SET_NO_NEW_PRIVS failed"); #if HAVE_SECCOMP - auto seccompBPF = compileSyscallFilter(); + const auto &seccompBPF = getSyscallFilter(); assert(seccompBPF.size() <= std::numeric_limits::max()); struct sock_fprog fprog = { .len = static_cast(seccompBPF.size()), - .filter = seccompBPF.data(), + // the kernel does not actually write to the filter + .filter = const_cast(seccompBPF.data()), }; if (syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &fprog) != 0) throw SysError("unable to load seccomp BPF program"); @@ -827,6 +834,13 @@ void LinuxLocalDerivationGoal::prepareSandbox() Pid LinuxLocalDerivationGoal::startChild(std::function openSlave) { +#if HAVE_SECCOMP + // Our seccomp filter program is surprisingly expensive to compile (~10ms). + // For this reason, we precompile it once and then cache it. + // This has to be done in the parent so that all builds get to use the same cache. + getSyscallFilter(); +#endif + // If we're not sandboxing no need to faff about, use the fallback if (!useChroot) { return LocalDerivationGoal::startChild(openSlave);