about summary refs log tree commit diff
diff options
context:
space:
mode:
authoraszlig <aszlig@redmoonstudios.org>2016-11-16T11·33+0100
committeraszlig <aszlig@redmoonstudios.org>2016-11-16T15·48+0100
commitb90a43533249a50f238a5e6cc9d77edb0fe6d748 (patch)
treefa11566c91f2618e3de42b99c0c8acad407b8d04
parent1c52e344c48e9cb8cf2b332201d5c96c06e4cf3e (diff)
libstore/build: Forge chown() to return success
What we basically want is a seccomp mode 2 BPF program like this but for
every architecture:

  BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr)),
  BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_chown, 4, 0),
  BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_fchown, 3, 0),
  BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_fchownat, 2, 0),
  BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_lchown, 1, 0),
  BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
  BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ERRNO)

However, on 32 bit architectures we do have chown32, lchown32 and
fchown32, so we'd need to add all the architecture blurb which
libseccomp handles for us.

So we only need to make sure that we add the 32bit seccomp arch while
we're on x86_64 and otherwise we just stay at the native architecture
which was set during seccomp_init(), which more or less replicates
setting 32bit personality during runChild().

The FORCE_SUCCESS() macro here could be a bit less ugly but I think
repeating the seccomp_rule_add() all over the place is way uglier.

Another way would have been to create a vector of syscalls to iterate
over, but that would make error messages uglier because we can either
only print the (libseccomp-internal) syscall number or use
seccomp_syscall_resolve_num_arch() to get the name or even make the
vector a pair number/name, essentially duplicating everything again.

Signed-off-by: aszlig <aszlig@redmoonstudios.org>
-rw-r--r--src/libstore/build.cc41
1 files changed, 41 insertions, 0 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index ed9d48378f00..6c6d0dee36ff 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -54,6 +54,7 @@
 #include <sys/param.h>
 #include <sys/mount.h>
 #include <sys/syscall.h>
+#include <seccomp.h>
 #define pivot_root(new_root, put_old) (syscall(SYS_pivot_root, new_root, put_old))
 #endif
 
@@ -1632,8 +1633,48 @@ void chmod_(const Path & path, mode_t mode)
 }
 
 
+#if __linux__
+
+#define FORCE_SUCCESS(syscall) \
+    if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(0), SCMP_SYS(syscall), 0) != 0) { \
+        seccomp_release(ctx); \
+        throw SysError("unable to add seccomp rule for " #syscall); \
+    }
+
+void setupSeccomp(void) {
+    scmp_filter_ctx ctx;
+
+    if ((ctx = seccomp_init(SCMP_ACT_ALLOW)) == NULL)
+        throw SysError("unable to initialize seccomp mode 2");
+
+#if defined(__x86_64__)
+    if (seccomp_arch_add(ctx, SCMP_ARCH_X86) != 0) {
+        seccomp_release(ctx);
+        throw SysError("unable to add 32bit seccomp architecture");
+    }
+#endif
+
+    FORCE_SUCCESS(chown);
+    FORCE_SUCCESS(fchown);
+    FORCE_SUCCESS(fchownat);
+    FORCE_SUCCESS(lchown);
+
+    if (seccomp_load(ctx) != 0) {
+        seccomp_release(ctx);
+        throw SysError("unable to load seccomp BPF program");
+    }
+
+    seccomp_release(ctx);
+}
+
+#undef FORCE_SUCCESS
+
+#endif
+
+
 int childEntry(void * arg)
 {
+    setupSeccomp();
     ((DerivationGoal *) arg)->runChild();
     return 1;
 }