From 1a40f64be11bce6bf143b76f4af0aa03f3c57845 Mon Sep 17 00:00:00 2001 From: Simon South Date: Mon, 6 Sep 2021 09:13:40 -0400 Subject: sandbox: Assume "openat" syscall is used where "open" is unavailable On architectures where Linux does not provide the legacy "open" syscall glibc necessarily uses "openat" instead. Omit the unnecessary glibc-version check on these systems. --- src/lib/sandbox/sandbox.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index 7c024d7e37..728092c591 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -505,7 +505,11 @@ is_libc_at_least(int major, int minor) static int libc_uses_openat_for_open(void) { +#ifdef __NR_open return is_libc_at_least(2, 26); +#else + return 1; +#endif /* defined(__NR_open) */ } /* Return true if we think we're running with a libc that uses openat for the @@ -513,9 +517,13 @@ libc_uses_openat_for_open(void) static int libc_uses_openat_for_opendir(void) { +#ifdef __NR_open // libc 2.27 and above or between 2.15 (inclusive) and 2.22 (exclusive) return is_libc_at_least(2, 27) || (is_libc_at_least(2, 15) && !is_libc_at_least(2, 22)); +#else + return 1; +#endif /* defined(__NR_open) */ } /** Allow a single file to be opened. If use_openat is true, -- cgit v1.2.3-54-g00ecf From d0297d878d4b105cfdac59c8cd088067035e840b Mon Sep 17 00:00:00 2001 From: Simon South Date: Mon, 30 Aug 2021 09:15:38 -0400 Subject: sandbox: Filter "renameat", "renameat2" where "rename" unavailable On architectures where Linux does not provide the legacy "rename" syscall it offers one or both of "renameat" and "renameat2" instead. Follow glibc's logic in selecting which syscall to filter. --- src/lib/sandbox/sandbox.c | 51 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index 728092c591..c6ba63bb6d 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -331,6 +331,8 @@ static int filter_nopar_gen[] = { seccomp_rule_add((ctx),(act),(call),3,(f1),(f2),(f3)) #define seccomp_rule_add_4(ctx,act,call,f1,f2,f3,f4) \ seccomp_rule_add((ctx),(act),(call),4,(f1),(f2),(f3),(f4)) +#define seccomp_rule_add_5(ctx,act,call,f1,f2,f3,f4,f5) \ + seccomp_rule_add((ctx),(act),(call),4,(f1),(f2),(f3),(f4),(f5)) static const char *sandbox_get_interned_string(const char *str); @@ -718,6 +720,7 @@ sb_fchownat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#if defined(__NR_rename) /** * Function responsible for setting up the rename syscall for * the seccomp filter sandbox. @@ -748,7 +751,7 @@ sb_rename(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } - +#elif defined(__NR_renameat) /** * Function responsible for setting up the renameat syscall for * the seccomp filter sandbox. @@ -781,6 +784,41 @@ sb_renameat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#else +/** + * Function responsible for setting up the renameat2 syscall for + * the seccomp filter sandbox. + */ +static int +sb_renameat2(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(renameat2)) { + + rc = seccomp_rule_add_5(ctx, SCMP_ACT_ALLOW, SCMP_SYS(renameat2), + 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), + SCMP_CMP(4, SCMP_CMP_EQ, 0)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add renameat2 syscall, received " + "libseccomp error %d", rc); + return rc; + } + } + } + + return 0; +} +#endif /* defined(__NR_rename) || defined(__NR_renameat) */ /** * Function responsible for setting up the openat syscall for @@ -1411,8 +1449,13 @@ static sandbox_filter_func_t filter_func[] = { #ifdef ENABLE_FRAGILE_HARDENING sb_ptrace, #endif +#if defined(__NR_rename) sb_rename, +#elif defined(__NR_renameat) sb_renameat, +#else + sb_renameat2, +#endif #ifdef __NR_fcntl64 sb_fcntl64, #endif @@ -1692,10 +1735,12 @@ new_element(int syscall, char *value) #define SCMP_chmod SCMP_SYS(chmod) #endif -#if defined(__aarch64__) && defined(__LP64__) +#if defined(__NR_rename) +#define SCMP_rename SCMP_SYS(rename) +#elif defined(__NR_renameat) #define SCMP_rename SCMP_SYS(renameat) #else -#define SCMP_rename SCMP_SYS(rename) +#define SCMP_rename SCMP_SYS(renameat2) #endif #ifdef __NR_stat64 -- cgit v1.2.3-54-g00ecf From cac7bec130d8655888470c40582dfdbfcce9ced8 Mon Sep 17 00:00:00 2001 From: Simon South Date: Mon, 30 Aug 2021 12:06:58 -0400 Subject: sandbox: Filter "newfstatat" on systems using generic syscalls On architectures that use Linux's generic syscall interface the legacy "stat" and "stat64" calls may not be available; on these systems glibc uses "newfstatat" instead. Modify the sandbox implementation to match. Note that on these architectures as on others glibc 2.33 uses "newfstatat" in a way the sandbox cannot filter, so preserve in add_noparam_filter() the code that allows the use of this syscall without restriction when glibc version 2.33 is in use. --- src/lib/sandbox/sandbox.c | 54 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index c6ba63bb6d..20214fa862 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -125,6 +125,15 @@ #define SYSCALL_NAME_DEBUGGING #endif +/** + * On newer architectures Linux provides a standardized, generic set of system + * calls (defined in Linux's include/uapi/asm-generic/unistd.h), which omits a + * number of legacy calls used by glibc on other platforms. + */ +#if defined(__aarch64__) || defined(__riscv) +#define ARCH_USES_GENERIC_SYSCALLS +#endif + /**Determines if at least one sandbox is active.*/ static int sandbox_active = 0; /** Holds the parameter list configuration for the sandbox.*/ @@ -259,8 +268,9 @@ static int filter_nopar_gen[] = { #ifdef __NR_sigreturn SCMP_SYS(sigreturn), #endif +#if defined(__NR_stat) SCMP_SYS(stat), -#if defined(__i386__) && defined(__NR_statx) +#elif defined(__i386__) && defined(__NR_statx) SCMP_SYS(statx), #endif SCMP_SYS(uname), @@ -1377,6 +1387,40 @@ sb_mremap(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#ifdef ARCH_USES_GENERIC_SYSCALLS +/** + * Function responsible for setting up the newfstatat syscall for + * the seccomp filter sandbox. + */ +static int +sb_newfstatat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + int rc = 0; + + 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(open) + || param->syscall == PHONY_OPENDIR_SYSCALL + || param->syscall == SCMP_SYS(newfstatat))) { + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(newfstatat), + 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 newfstatat syscall, received " + "libseccomp error %d", rc); + return rc; + } + } + } + + return 0; +} +#endif /* defined(ARCH_USES_GENERIC_SYSCALLS) */ + #ifdef __NR_stat64 /** * Function responsible for setting up the stat64 syscall for @@ -1465,7 +1509,9 @@ static sandbox_filter_func_t filter_func[] = { sb_flock, sb_futex, sb_mremap, -#ifdef __NR_stat64 +#if defined(ARCH_USES_GENERIC_SYSCALLS) + sb_newfstatat, +#elif defined(__NR_stat64) sb_stat64, #endif @@ -1743,7 +1789,9 @@ new_element(int syscall, char *value) #define SCMP_rename SCMP_SYS(renameat2) #endif -#ifdef __NR_stat64 +#if defined(ARCH_USES_GENERIC_SYSCALLS) +#define SCMP_stat SCMP_SYS(newfstatat) +#elif defined(__NR_stat64) #define SCMP_stat SCMP_SYS(stat64) #else #define SCMP_stat SCMP_SYS(stat) -- cgit v1.2.3-54-g00ecf From da6b55b6f47efacf20f525c644b349666bbe77aa Mon Sep 17 00:00:00 2001 From: Simon South Date: Mon, 6 Sep 2021 09:21:16 -0400 Subject: sandbox: Filter "fchmodat" on systems using generic syscalls On architectures that use Linux's generic syscall interface the legacy "chmod" call is not available; on these systems glibc uses "fchmodat" instead. Modify the sandbox implementation to match. --- src/lib/sandbox/sandbox.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index 20214fa862..f3f5706273 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -601,8 +601,9 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#ifdef ARCH_USES_GENERIC_SYSCALLS static int -sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +sb_fchmodat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { int rc; sandbox_cfg_t *elem = NULL; @@ -612,11 +613,12 @@ sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter) smp_param_t *param = elem->param; if (param != NULL && param->prot == 1 && param->syscall - == SCMP_SYS(chmod)) { - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chmod), - SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value)); + == 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 chmod syscall, received " + log_err(LD_BUG,"(Sandbox) failed to add fchmodat syscall, received " "libseccomp error %d", rc); return rc; } @@ -625,9 +627,9 @@ sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } - +#else static int -sb_fchmodat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { int rc; sandbox_cfg_t *elem = NULL; @@ -637,12 +639,11 @@ sb_fchmodat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) 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)); + == SCMP_SYS(chmod)) { + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chmod), + SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value)); if (rc != 0) { - log_err(LD_BUG,"(Sandbox) failed to add fchmodat syscall, received " + log_err(LD_BUG,"(Sandbox) failed to add chmod syscall, received " "libseccomp error %d", rc); return rc; } @@ -651,6 +652,7 @@ sb_fchmodat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#endif /* defined(ARCH_USES_GENERIC_SYSCALLS) */ #ifdef __i386__ static int @@ -1485,8 +1487,11 @@ static sandbox_filter_func_t filter_func[] = { sb_chown, #endif sb_fchownat, - sb_chmod, +#if defined(ARCH_USES_GENERIC_SYSCALLS) sb_fchmodat, +#else + sb_chmod, +#endif sb_open, sb_openat, sb_opendir, @@ -1775,7 +1780,7 @@ new_element(int syscall, char *value) #define SCMP_chown SCMP_SYS(chown) #endif -#if defined(__aarch64__) && defined(__LP64__) +#if defined(ARCH_USES_GENERIC_SYSCALLS) #define SCMP_chmod SCMP_SYS(fchmodat) #else #define SCMP_chmod SCMP_SYS(chmod) -- cgit v1.2.3-54-g00ecf From 6a004380c90671f210e8e96239826159ec894a11 Mon Sep 17 00:00:00 2001 From: Simon South Date: Mon, 6 Sep 2021 09:22:46 -0400 Subject: sandbox: Filter "fchownat" on systems using generic syscalls On architectures that use Linux's generic syscall interface the legacy "chown" call is not available; on these systems glibc uses "fchownat" instead. Modify the sandbox implementation to match. --- src/lib/sandbox/sandbox.c | 49 ++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index f3f5706273..b09fdcb89c 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -654,9 +654,9 @@ sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter) } #endif /* defined(ARCH_USES_GENERIC_SYSCALLS) */ -#ifdef __i386__ +#if defined(ARCH_USES_GENERIC_SYSCALLS) static int -sb_chown32(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +sb_fchownat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { int rc; sandbox_cfg_t *elem = NULL; @@ -666,11 +666,12 @@ sb_chown32(scmp_filter_ctx ctx, sandbox_cfg_t *filter) smp_param_t *param = elem->param; if (param != NULL && param->prot == 1 && param->syscall - == SCMP_SYS(chown32)) { - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chown32), - SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value)); + == 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 chown32 syscall, received " + log_err(LD_BUG,"(Sandbox) failed to add fchownat syscall, received " "libseccomp error %d", rc); return rc; } @@ -679,9 +680,9 @@ sb_chown32(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } -#else +#elif defined(__i386__) static int -sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +sb_chown32(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { int rc; sandbox_cfg_t *elem = NULL; @@ -691,11 +692,11 @@ sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter) smp_param_t *param = elem->param; if (param != NULL && param->prot == 1 && param->syscall - == SCMP_SYS(chown)) { - rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chown), + == SCMP_SYS(chown32)) { + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chown32), SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value)); if (rc != 0) { - log_err(LD_BUG,"(Sandbox) failed to add chown syscall, received " + log_err(LD_BUG,"(Sandbox) failed to add chown32 syscall, received " "libseccomp error %d", rc); return rc; } @@ -704,10 +705,9 @@ sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } -#endif /* defined(__i386__) */ - +#else static int -sb_fchownat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { int rc; sandbox_cfg_t *elem = NULL; @@ -717,12 +717,11 @@ sb_fchownat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) 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)); + == SCMP_SYS(chown)) { + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(chown), + SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value)); if (rc != 0) { - log_err(LD_BUG,"(Sandbox) failed to add fchownat syscall, received " + log_err(LD_BUG,"(Sandbox) failed to add chown syscall, received " "libseccomp error %d", rc); return rc; } @@ -731,6 +730,7 @@ sb_fchownat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#endif /* defined(ARCH_USES_GENERIC_SYSCALLS) || defined(__i386__) */ #if defined(__NR_rename) /** @@ -1481,12 +1481,13 @@ static sandbox_filter_func_t filter_func[] = { #ifdef __NR_mmap2 sb_mmap2, #endif -#ifdef __i386__ +#if defined(ARCH_USES_GENERIC_SYSCALLS) + sb_fchownat, +#elif defined(__i386__) sb_chown32, #else sb_chown, #endif - sb_fchownat, #if defined(ARCH_USES_GENERIC_SYSCALLS) sb_fchmodat, #else @@ -1772,10 +1773,10 @@ new_element(int syscall, char *value) return new_element2(syscall, value, NULL); } -#ifdef __i386__ -#define SCMP_chown SCMP_SYS(chown32) -#elif defined(__aarch64__) && defined(__LP64__) +#if defined(ARCH_USES_GENERIC_SYSCALLS) #define SCMP_chown SCMP_SYS(fchownat) +#elif defined(__i386__) +#define SCMP_chown SCMP_SYS(chown32) #else #define SCMP_chown SCMP_SYS(chown) #endif -- cgit v1.2.3-54-g00ecf From 0d87dc1ee79daea085de5a542cedee69d2122955 Mon Sep 17 00:00:00 2001 From: Simon South Date: Thu, 30 Sep 2021 11:33:23 -0400 Subject: sandbox: Allow use with fragile hardening on AArch64 and elsewhere Update the sandbox implementation to allow its use with fragile hardening enabled on AArch64 (ARM64) and other architectures that use Linux's generic syscall interface. Note that in this configuration the sandbox is completely unable to filter requests to open files and directories. Update the sandbox unit tests to match. --- src/lib/sandbox/sandbox.c | 52 ++++++++++++++++++++++++++++++++++++++++++++--- src/test/test_sandbox.c | 8 ++++---- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index b09fdcb89c..1573362774 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -524,6 +524,11 @@ libc_uses_openat_for_open(void) #endif /* defined(__NR_open) */ } +/* Calls to opendir() cannot be filtered by the sandbox when built with fragile + * hardening for an architecture that uses Linux's generic syscall interface, + * so prevent a compiler warning by omitting this function along with + * sb_opendir(). */ +#if !(defined(ENABLE_FRAGILE_HARDENING) && defined(ARCH_USES_GENERIC_SYSCALLS)) /* Return true if we think we're running with a libc that uses openat for the * opendir function on linux. */ static int @@ -537,6 +542,8 @@ libc_uses_openat_for_opendir(void) return 1; #endif /* defined(__NR_open) */ } +#endif /* !(defined(ENABLE_FRAGILE_HARDENING) && + defined(ARCH_USES_GENERIC_SYSCALLS)) */ /** Allow a single file to be opened. If use_openat is true, * we're using a libc that remaps all the opens into openats. */ @@ -566,10 +573,25 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter) int use_openat = libc_uses_openat_for_open(); #ifdef ENABLE_FRAGILE_HARDENING - /* AddressSanitizer uses the "open" syscall to access information about the - * running process via the filesystem, so that call must be allowed without + /* AddressSanitizer uses either the "open" or the "openat" syscall (depending + * on the architecture) to access information about the running process via + * the filesystem, so the appropriate call must be allowed without * restriction or the sanitizer will be unable to execute normally when the * process terminates. */ +#ifdef ARCH_USES_GENERIC_SYSCALLS + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), + SCMP_CMP_LOWER32_EQ(0, AT_FDCWD)); + if (rc != 0) { + log_err(LD_BUG,"(Sandbox) failed to add openat syscall, received " + "libseccomp error %d", rc); + return rc; + } + + /* The "open" syscall is not defined on this architecture, so any other + * requests to open files will necessarily use "openat" as well and there is + * no need to consider any additional rules. */ + return 0; +#else rc = seccomp_rule_add_0(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open)); if (rc != 0) { log_err(LD_BUG,"(Sandbox) failed to add open syscall, received " @@ -581,7 +603,8 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter) * there is no need to consider any additional rules. */ if (!use_openat) return 0; -#endif +#endif /* defined(ARCH_USES_GENERIC_SYSCALLS) */ +#endif /* defined(ENABLE_FRAGILE_HARDENING) */ // for each dynamic parameter filters for (elem = filter; elem != NULL; elem = elem->next) { @@ -832,6 +855,17 @@ sb_renameat2(scmp_filter_ctx ctx, sandbox_cfg_t *filter) } #endif /* defined(__NR_rename) || defined(__NR_renameat) */ +/* If Tor is built with fragile hardening for an architecture that uses Linux's + * generic syscall interface a rule allowing the "openat" syscall without + * restriction will have already been added by sb_open(), so there is no need + * to consider adding additional, more restrictive rules here as they will + * simply be ignored. + * + * Also, since the "open" syscall is not defined on these architectures, glibc + * will necessarily use "openat" for its implementation of opendir() as well. + * This means neither of the following two functions will have any effect and + * both can be omitted. */ +#if !(defined(ENABLE_FRAGILE_HARDENING) && defined(ARCH_USES_GENERIC_SYSCALLS)) /** * Function responsible for setting up the openat syscall for * the seccomp filter sandbox. @@ -887,6 +921,8 @@ sb_opendir(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#endif /* !(defined(ENABLE_FRAGILE_HARDENING) && + defined(ARCH_USES_GENERIC_SYSCALLS)) */ #ifdef ENABLE_FRAGILE_HARDENING /** @@ -906,9 +942,17 @@ sb_ptrace(scmp_filter_ctx ctx, sandbox_cfg_t *filter) if (rc) return rc; + /* AddressSanitizer uses "PTRACE_GETREGSET" on AArch64 (ARM64) and + * System/390, "PTRACE_GETREGS" everywhere else. */ +#if defined(__aarch64__) || defined(__s390__) + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ptrace), + SCMP_CMP(0, SCMP_CMP_EQ, PTRACE_GETREGSET), + SCMP_CMP(1, SCMP_CMP_EQ, pid)); +#else rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ptrace), SCMP_CMP(0, SCMP_CMP_EQ, PTRACE_GETREGS), SCMP_CMP(1, SCMP_CMP_EQ, pid)); +#endif /* defined(__aarch64__) || defined(__s390__) */ if (rc) return rc; @@ -1494,8 +1538,10 @@ static sandbox_filter_func_t filter_func[] = { sb_chmod, #endif sb_open, +#if !(defined(ENABLE_FRAGILE_HARDENING) && defined(ARCH_USES_GENERIC_SYSCALLS)) sb_openat, sb_opendir, +#endif #ifdef ENABLE_FRAGILE_HARDENING sb_ptrace, #endif diff --git a/src/test/test_sandbox.c b/src/test/test_sandbox.c index 7ec08a3546..28b60e9f3e 100644 --- a/src/test/test_sandbox.c +++ b/src/test/test_sandbox.c @@ -310,22 +310,22 @@ test_sandbox_stat_filename(void *arg) struct testcase_t sandbox_tests[] = { SANDBOX_TEST(is_active, TT_FORK), -/* When Tor is built with fragile compiler-hardening the sandbox is unable to - * filter requests to open files or directories (on systems where glibc uses - * the "open" system call to provide this functionality), as doing so would +/* When Tor is built with fragile compiler-hardening the sandbox is usually + * unable to filter requests to open files or directories, as doing so would * interfere with the address sanitizer as it retrieves information about the * running process via the filesystem. Skip these tests in that case as the * corresponding functions are likely to have no effect and this will cause the * tests to fail. */ #ifdef ENABLE_FRAGILE_HARDENING SANDBOX_TEST_SKIPPED(open_filename), + SANDBOX_TEST_SKIPPED(openat_filename), SANDBOX_TEST_SKIPPED(opendir_dirname), #else SANDBOX_TEST_IN_SANDBOX(open_filename), + SANDBOX_TEST_IN_SANDBOX(openat_filename), SANDBOX_TEST_IN_SANDBOX(opendir_dirname), #endif /* defined(ENABLE_FRAGILE_HARDENING) */ - SANDBOX_TEST_IN_SANDBOX(openat_filename), SANDBOX_TEST_IN_SANDBOX(chmod_filename), SANDBOX_TEST_IN_SANDBOX(chown_filename), SANDBOX_TEST_IN_SANDBOX(rename_filename), -- cgit v1.2.3-54-g00ecf From a187fde7f4852049c7d639267f5a8316e0c6e7d0 Mon Sep 17 00:00:00 2001 From: Simon South Date: Mon, 30 May 2022 08:32:43 -0400 Subject: changes: Add file for tickets 40465, 40599 --- changes/bug40465 | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changes/bug40465 diff --git a/changes/bug40465 b/changes/bug40465 new file mode 100644 index 0000000000..d07470f18f --- /dev/null +++ b/changes/bug40465 @@ -0,0 +1,6 @@ + o Major bugfixes (sandbox): + - Fix sandbox to work on architectures that use Linux's generic syscall + interface, extending support for AArch64 (ARM64) and adding support for + RISC-V, allowing test_include.sh and the sandbox unit tests to pass on + these systems even when building with fragile hardening enabled. Fixes + bugs 40465 and 40599; bugfix on 0.2.5.1-alpha. -- cgit v1.2.3-54-g00ecf