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>
This commit is contained in:
aszlig 2016-11-16 12:33:42 +01:00
parent 1c52e344c4
commit b90a435332
No known key found for this signature in database
GPG key ID: 1DE8E48E57DB5436

View file

@ -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;
}