From 2c48460850186e5fb8152e7882baf9e29bb5e884 Mon Sep 17 00:00:00 2001 From: Alois Wohlschlager Date: Tue, 6 Aug 2024 16:38:32 +0200 Subject: [PATCH] libstore/linux: precompile and cache the seccomp BPF The growth of the seccomp filter in 127ee1a101e3f5ebab39ad98cbe58fefcd52eca5 made its compilation time significant (roughly 10 milliseconds have been measured on one machine). For this reason, it is now precompiled and cached in the parent process so that this overhead is not hit for every single build. It is still not optimal when going through the daemon, because compilation still happens once per client, but it's better than before and doing it only once for the entire daemon requires excessive crimes with the current architecture. Fixes: https://git.lix.systems/lix-project/lix/issues/461 Change-Id: I2277eaaf6bab9bd74bbbfd9861e52392a54b61a3 --- src/libstore/platform/linux.cc | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) 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);