aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/platform
diff options
context:
space:
mode:
authorAlois Wohlschlager <alois1@gmx-topmail.de>2024-08-06 16:38:32 +0200
committerAlois Wohlschlager <alois1@gmx-topmail.de>2024-08-06 18:31:40 +0200
commit403fa9e2b6743e57cea0c8f0fa940c683af8081f (patch)
treecb81133818e3da77b020e8585cc13839585a0744 /src/libstore/platform
parent741d3b441c479a07596aadf9a6ac8f90b115d363 (diff)
libstore/linux: compile the seccomp BPF explicitly
This is a preparation for precompiling the filter, which is done separately. The behaviour should be unchanged for now. Change-Id: I899aa7242962615949208597aca88913feba1cb8
Diffstat (limited to 'src/libstore/platform')
-rw-r--r--src/libstore/platform/linux.cc42
1 files changed, 31 insertions, 11 deletions
diff --git a/src/libstore/platform/linux.cc b/src/libstore/platform/linux.cc
index bfe8ea29c..ad8b4e322 100644
--- a/src/libstore/platform/linux.cc
+++ b/src/libstore/platform/linux.cc
@@ -11,6 +11,7 @@
#include <sys/prctl.h>
#if HAVE_SECCOMP
+#include <linux/filter.h>
#include <seccomp.h>
#endif
@@ -146,11 +147,8 @@ static void allowSyscall(scmp_filter_ctx ctx, int syscall) {
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), syscall, 1, SCMP_A##modePos(SCMP_CMP_MASKED_EQ, S_ISGID, S_ISGID)) != 0) \
throw SysError("unable to add seccomp rule");
-#endif
-
-void LinuxLocalDerivationGoal::setupSyscallFilter()
+static std::vector<struct sock_filter> compileSyscallFilter()
{
-#if HAVE_SECCOMP
scmp_filter_ctx ctx;
// Pretend that syscalls we don't yet know about don't exist.
@@ -703,18 +701,40 @@ void LinuxLocalDerivationGoal::setupSyscallFilter()
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(fsetxattr), 0) != 0)
throw SysError("unable to add seccomp rule");
+ Pipe filterPipe;
+ filterPipe.create();
+ auto filterBytes_ = std::async([&]() {
+ return drainFD(filterPipe.readSide.get());
+ });
+ if (seccomp_export_bpf(ctx, filterPipe.writeSide.get()) != 0)
+ throw SysError("unable to compile seccomp BPF program");
+ filterPipe.writeSide.close();
+ auto filterBytes = filterBytes_.get();
+
+ assert(filterBytes.size() % sizeof(struct sock_filter) == 0);
+ std::vector<struct sock_filter> filter(filterBytes.size() / sizeof(struct sock_filter));
+ std::memcpy(filter.data(), filterBytes.data(), filterBytes.size());
+ return filter;
+}
+
+#endif
+
+void LinuxLocalDerivationGoal::setupSyscallFilter()
+{
// Set the NO_NEW_PRIVS prctl flag.
// This both makes loading seccomp filters work for unprivileged users,
// and is an additional security measure in its own right.
- if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, 1) != 0)
- throw SysError("unable to set 'no new privileges' seccomp attribute");
-
- if (seccomp_load(ctx) != 0)
- throw SysError("unable to load seccomp BPF program");
-#else
- // Still set the no-new-privileges flag if libseccomp is not available.
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();
+ assert(seccompBPF.size() <= std::numeric_limits<unsigned short>::max());
+ struct sock_fprog fprog = {
+ .len = static_cast<unsigned short>(seccompBPF.size()),
+ .filter = seccompBPF.data(),
+ };
+ if (syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &fprog) != 0)
+ throw SysError("unable to load seccomp BPF program");
#endif
}