diff --git a/changes/aarch64_sandbox b/changes/aarch64_sandbox new file mode 100644 index 0000000000..d1d64d6e6c --- /dev/null +++ b/changes/aarch64_sandbox @@ -0,0 +1,5 @@ + o Minor bugfixes (sandbox): + - Fix sandbox support on AArch64 systems. More "*at" variants of syscalls + are now supported. Signed 32 bit syscall parameters are checked more + precisely, which should lead to lower likelihood of breakages with future + compiler and libc releases. Fixes bug 40599; bugfix on 0.4.4.3-alpha. diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index e87edd8e21..b734977c3a 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -141,10 +141,12 @@ static sandbox_cfg_t *filter_dynamic = NULL; * the high bits of the value might get masked out improperly. */ #define SCMP_CMP_MASKED(a,b,c) \ SCMP_CMP4((a), SCMP_CMP_MASKED_EQ, ~(scmp_datum_t)(b), (c)) -/* For negative constants, the rule to add depends on the glibc version. */ -#define SCMP_CMP_NEG(a,op,b) (libc_negative_constant_needs_cast() ? \ - (SCMP_CMP((a), (op), (unsigned int)(b))) : \ - (SCMP_CMP_STR((a), (op), (b)))) +/* Negative constants aren't consistently sign extended or zero extended. + * Different compilers, libc, and architectures behave differently. For cases + * where the kernel ABI uses a 32 bit integer, this macro can be used to + * mask-compare only the lower 32 bits of the value. */ +#define SCMP_CMP_LOWER32_EQ(a,b) \ + SCMP_CMP4((a), SCMP_CMP_MASKED_EQ, 0xFFFFFFFF, (unsigned int)(b)) /** Variable used for storing all syscall numbers that will be allowed with the * stage 1 general Tor sandbox. @@ -513,14 +515,6 @@ libc_uses_openat_for_opendir(void) (is_libc_at_least(2, 15) && !is_libc_at_least(2, 22)); } -/* Return true if we think we're running with a libc that needs to cast - * negative arguments like AT_FDCWD for seccomp rules. */ -static int -libc_negative_constant_needs_cast(void) -{ - return is_libc_at_least(2, 27); -} - /** Allow a single file to be opened. If use_openat is true, * we're using a libc that remaps all the opens into openats. */ static int @@ -528,7 +522,7 @@ allow_file_open(scmp_filter_ctx ctx, int use_openat, const char *file) { if (use_openat) { return seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), - SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD), + SCMP_CMP_LOWER32_EQ(0, AT_FDCWD), SCMP_CMP_STR(1, SCMP_CMP_EQ, file)); } else { return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), @@ -609,6 +603,32 @@ sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +static int +sb_fchmodat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + int rc; + sandbox_cfg_t *elem = NULL; + + // for each dynamic parameter filters + for (elem = filter; elem != NULL; elem = elem->next) { + smp_param_t *param = elem->param; + + if (param != NULL && param->prot == 1 && param->syscall + == SCMP_SYS(fchmodat)) { + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fchmodat), + SCMP_CMP_LOWER32_EQ(0, AT_FDCWD), + SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add fchmodat syscall, received " + "libseccomp error %d", rc); + return rc; + } + } + } + + return 0; +} + #ifdef __i386__ static int sb_chown32(scmp_filter_ctx ctx, sandbox_cfg_t *filter) @@ -661,6 +681,32 @@ sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter) } #endif /* defined(__i386__) */ +static int +sb_fchownat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + int rc; + sandbox_cfg_t *elem = NULL; + + // for each dynamic parameter filters + for (elem = filter; elem != NULL; elem = elem->next) { + smp_param_t *param = elem->param; + + if (param != NULL && param->prot == 1 && param->syscall + == SCMP_SYS(fchownat)) { + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fchownat), + SCMP_CMP_LOWER32_EQ(0, AT_FDCWD), + SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add fchownat syscall, received " + "libseccomp error %d", rc); + return rc; + } + } + } + + return 0; +} + /** * Function responsible for setting up the rename syscall for * the seccomp filter sandbox. @@ -692,6 +738,39 @@ sb_rename(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +/** + * Function responsible for setting up the renameat syscall for + * the seccomp filter sandbox. + */ +static int +sb_renameat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + int rc; + sandbox_cfg_t *elem = NULL; + + // for each dynamic parameter filters + for (elem = filter; elem != NULL; elem = elem->next) { + smp_param_t *param = elem->param; + + if (param != NULL && param->prot == 1 && + param->syscall == SCMP_SYS(renameat)) { + + rc = seccomp_rule_add_4(ctx, SCMP_ACT_ALLOW, SCMP_SYS(renameat), + SCMP_CMP_LOWER32_EQ(0, AT_FDCWD), + SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value), + SCMP_CMP_LOWER32_EQ(2, AT_FDCWD), + SCMP_CMP_STR(3, SCMP_CMP_EQ, param->value2)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add renameat syscall, received " + "libseccomp error %d", rc); + return rc; + } + } + } + + return 0; +} + /** * Function responsible for setting up the openat syscall for * the seccomp filter sandbox. @@ -709,7 +788,7 @@ sb_openat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) if (param != NULL && param->prot == 1 && param->syscall == SCMP_SYS(openat)) { rc = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), - SCMP_CMP_NEG(0, SCMP_CMP_EQ, AT_FDCWD), + SCMP_CMP_LOWER32_EQ(0, AT_FDCWD), SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value), SCMP_CMP(2, SCMP_CMP_EQ, O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY| O_CLOEXEC)); @@ -1312,7 +1391,9 @@ static sandbox_filter_func_t filter_func[] = { #else sb_chown, #endif + sb_fchownat, sb_chmod, + sb_fchmodat, sb_open, sb_openat, sb_opendir, @@ -1320,6 +1401,7 @@ static sandbox_filter_func_t filter_func[] = { sb_ptrace, #endif sb_rename, + sb_renameat, #ifdef __NR_fcntl64 sb_fcntl64, #endif @@ -1587,10 +1669,24 @@ new_element(int syscall, char *value) #ifdef __i386__ #define SCMP_chown SCMP_SYS(chown32) +#elif defined(__aarch64__) && defined(__LP64__) +#define SCMP_chown SCMP_SYS(fchownat) #else #define SCMP_chown SCMP_SYS(chown) #endif +#if defined(__aarch64__) && defined(__LP64__) +#define SCMP_chmod SCMP_SYS(fchmodat) +#else +#define SCMP_chmod SCMP_SYS(chmod) +#endif + +#if defined(__aarch64__) && defined(__LP64__) +#define SCMP_rename SCMP_SYS(renameat) +#else +#define SCMP_rename SCMP_SYS(rename) +#endif + #ifdef __NR_stat64 #define SCMP_stat SCMP_SYS(stat64) #else @@ -1628,7 +1724,7 @@ sandbox_cfg_allow_chmod_filename(sandbox_cfg_t **cfg, char *file) { sandbox_cfg_t *elem = NULL; - elem = new_element(SCMP_SYS(chmod), file); + elem = new_element(SCMP_chmod, file); elem->next = *cfg; *cfg = elem; @@ -1654,7 +1750,7 @@ sandbox_cfg_allow_rename(sandbox_cfg_t **cfg, char *file1, char *file2) { sandbox_cfg_t *elem = NULL; - elem = new_element2(SCMP_SYS(rename), file1, file2); + elem = new_element2(SCMP_rename, file1, file2); elem->next = *cfg; *cfg = elem;