libstore/linux: precompile and cache the seccomp BPF
The growth of the seccomp filter in127ee1a101
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: #461 Change-Id:I2277eaaf6bab9bd74bbbfd9861e52392a54b61a3
This commit is contained in:
parent
403fa9e2b6
commit
2c48460850
|
@ -717,6 +717,12 @@ static std::vector<struct sock_filter> compileSyscallFilter()
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const std::vector<struct sock_filter> &getSyscallFilter()
|
||||||
|
{
|
||||||
|
static auto filter = compileSyscallFilter();
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void LinuxLocalDerivationGoal::setupSyscallFilter()
|
void LinuxLocalDerivationGoal::setupSyscallFilter()
|
||||||
|
@ -727,11 +733,12 @@ void LinuxLocalDerivationGoal::setupSyscallFilter()
|
||||||
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
|
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
|
||||||
throw SysError("PR_SET_NO_NEW_PRIVS failed");
|
throw SysError("PR_SET_NO_NEW_PRIVS failed");
|
||||||
#if HAVE_SECCOMP
|
#if HAVE_SECCOMP
|
||||||
auto seccompBPF = compileSyscallFilter();
|
const auto &seccompBPF = getSyscallFilter();
|
||||||
assert(seccompBPF.size() <= std::numeric_limits<unsigned short>::max());
|
assert(seccompBPF.size() <= std::numeric_limits<unsigned short>::max());
|
||||||
struct sock_fprog fprog = {
|
struct sock_fprog fprog = {
|
||||||
.len = static_cast<unsigned short>(seccompBPF.size()),
|
.len = static_cast<unsigned short>(seccompBPF.size()),
|
||||||
.filter = seccompBPF.data(),
|
// the kernel does not actually write to the filter
|
||||||
|
.filter = const_cast<struct sock_filter *>(seccompBPF.data()),
|
||||||
};
|
};
|
||||||
if (syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &fprog) != 0)
|
if (syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &fprog) != 0)
|
||||||
throw SysError("unable to load seccomp BPF program");
|
throw SysError("unable to load seccomp BPF program");
|
||||||
|
@ -827,6 +834,13 @@ void LinuxLocalDerivationGoal::prepareSandbox()
|
||||||
|
|
||||||
Pid LinuxLocalDerivationGoal::startChild(std::function<void()> openSlave)
|
Pid LinuxLocalDerivationGoal::startChild(std::function<void()> 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 we're not sandboxing no need to faff about, use the fallback
|
||||||
if (!useChroot) {
|
if (!useChroot) {
|
||||||
return LocalDerivationGoal::startChild(openSlave);
|
return LocalDerivationGoal::startChild(openSlave);
|
||||||
|
|
Loading…
Reference in a new issue