From b90a43533249a50f238a5e6cc9d77edb0fe6d748 Mon Sep 17 00:00:00 2001 From: aszlig Date: Wed, 16 Nov 2016 12:33:42 +0100 Subject: [PATCH] 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 --- src/libstore/build.cc | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/libstore/build.cc b/src/libstore/build.cc index ed9d48378..6c6d0dee3 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -54,6 +54,7 @@ #include #include #include +#include #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; }