diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/crypt_ops/crypto_openssl_mgt.c | 5 | ||||
-rw-r--r-- | src/lib/crypt_ops/crypto_openssl_mgt.h | 5 | ||||
-rw-r--r-- | src/lib/fs/files.c | 10 | ||||
-rw-r--r-- | src/lib/log/.may_include | 2 | ||||
-rw-r--r-- | src/lib/log/log.c | 6 | ||||
-rw-r--r-- | src/lib/log/log_sys.c | 29 | ||||
-rw-r--r-- | src/lib/log/util_bug.c | 27 | ||||
-rw-r--r-- | src/lib/log/util_bug.h | 29 | ||||
-rw-r--r-- | src/lib/sandbox/sandbox.c | 241 | ||||
-rw-r--r-- | src/lib/string/util_string.c | 2 |
10 files changed, 294 insertions, 62 deletions
diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.c b/src/lib/crypt_ops/crypto_openssl_mgt.c index 6c01cb6aa8..ca12a82518 100644 --- a/src/lib/crypt_ops/crypto_openssl_mgt.c +++ b/src/lib/crypt_ops/crypto_openssl_mgt.c @@ -40,6 +40,11 @@ ENABLE_GCC_WARNING("-Wredundant-decls") #include <string.h> +#ifdef OPENSSL_NO_ENGINE +/* Android's OpenSSL seems to have removed all of its Engine support. */ +#define DISABLE_ENGINES +#endif + #ifndef NEW_THREAD_API /** A number of preallocated mutexes for use by OpenSSL. */ static tor_mutex_t **openssl_mutexes_ = NULL; diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.h b/src/lib/crypt_ops/crypto_openssl_mgt.h index 96a37721dd..eac0ec1977 100644 --- a/src/lib/crypt_ops/crypto_openssl_mgt.h +++ b/src/lib/crypt_ops/crypto_openssl_mgt.h @@ -49,11 +49,6 @@ #define OPENSSL_V_SERIES(a,b,c) \ OPENSSL_VER((a),(b),(c),0,0) -#ifdef OPENSSL_NO_ENGINE -/* Android's OpenSSL seems to have removed all of its Engine support. */ -#define DISABLE_ENGINES -#endif - #if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) /* OpenSSL as of 1.1.0pre4 has an "new" thread API, which doesn't require * setting up various callbacks. diff --git a/src/lib/fs/files.c b/src/lib/fs/files.c index 55f20dd49e..914a8b8e72 100644 --- a/src/lib/fs/files.c +++ b/src/lib/fs/files.c @@ -85,7 +85,8 @@ tor_open_cloexec(const char *path, int flags, unsigned mode) FILE * tor_fopen_cloexec(const char *path, const char *mode) { - FILE *result = fopen(path, mode); + const char *p = sandbox_intern_string(path); + FILE *result = fopen(p, mode); #ifdef FD_CLOEXEC if (result != NULL) { if (fcntl(fileno(result), F_SETFD, FD_CLOEXEC) == -1) { @@ -572,9 +573,10 @@ write_bytes_to_new_file(const char *fname, const char *str, size_t len, /** * Read the contents of the open file <b>fd</b> presuming it is a FIFO * (or similar) file descriptor for which the size of the file isn't - * known ahead of time. Return NULL on failure, and a NUL-terminated - * string on success. On success, set <b>sz_out</b> to the number of - * bytes read. + * known ahead of time. + * Return NULL on failure, and a NUL-terminated string on success. + * On success, set <b>sz_out</b> to the number of bytes read (not including + * the final NULL, which wasn't read from <b>fd</fd>). */ char * read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out) diff --git a/src/lib/log/.may_include b/src/lib/log/.may_include index 54d96324db..09e2b90282 100644 --- a/src/lib/log/.may_include +++ b/src/lib/log/.may_include @@ -9,8 +9,10 @@ lib/intmath/*.h lib/lock/*.h lib/log/*.h lib/malloc/*.h +lib/metrics/*.h lib/string/*.h lib/subsys/*.h lib/testsupport/*.h +lib/thread/threads.h lib/version/*.h lib/wallclock/*.h diff --git a/src/lib/log/log.c b/src/lib/log/log.c index db57ee61a2..aecd838c5d 100644 --- a/src/lib/log/log.c +++ b/src/lib/log/log.c @@ -33,6 +33,7 @@ #define LOG_PRIVATE #include "lib/log/log.h" #include "lib/log/log_sys.h" +#include "lib/log/util_bug.h" #include "lib/version/git_revision.h" #include "lib/log/ratelim.h" #include "lib/lock/compat_mutex.h" @@ -706,6 +707,8 @@ log_fn_(int severity, log_domain_mask_t domain, const char *fn, const char *format, ...) { va_list ap; + if (domain & LD_BUG) + tor_bug_increment_count_(); if (severity > log_global_min_severity_) return; va_start(ap,format); @@ -718,6 +721,8 @@ log_fn_ratelim_(ratelim_t *ratelim, int severity, log_domain_mask_t domain, { va_list ap; char *m; + if (domain & LD_BUG) + tor_bug_increment_count_(); if (severity > log_global_min_severity_) return; m = rate_limit_log(ratelim, approx_time()); @@ -912,6 +917,7 @@ init_logging(int disable_startup_queue) { if (!log_mutex_initialized) { tor_mutex_init(&log_mutex); + tor_bug_init_counter(); log_mutex_initialized = 1; } #ifdef __GNUC__ diff --git a/src/lib/log/log_sys.c b/src/lib/log/log_sys.c index 33609f5288..ac76d9bdbb 100644 --- a/src/lib/log/log_sys.c +++ b/src/lib/log/log_sys.c @@ -11,11 +11,16 @@ #include "lib/log/escape.h" #include "lib/log/log.h" #include "lib/log/log_sys.h" +#include "lib/log/util_bug.h" +#include "lib/metrics/metrics_store.h" + +static metrics_store_t *the_store; static int subsys_logging_initialize(void) { init_logging(0); + the_store = metrics_store_new(); return 0; } @@ -26,6 +31,29 @@ subsys_logging_shutdown(void) escaped(NULL); } +static const smartlist_t * +logging_metrics_get_stores(void) +{ + static smartlist_t *stores_list = NULL; + + metrics_store_reset(the_store); + + metrics_store_entry_t *sentry = metrics_store_add( + the_store, + METRICS_TYPE_COUNTER, + METRICS_NAME(bug_reached_count), + "Total number of BUG() and similar assertion reached", + 0, NULL); + metrics_store_entry_update(sentry, tor_bug_get_count()); + + if (!stores_list) { + stores_list = smartlist_new(); + smartlist_add(stores_list, the_store); + } + + return stores_list; +} + const subsys_fns_t sys_logging = { .name = "log", SUBSYS_DECLARE_LOCATION(), @@ -35,4 +63,5 @@ const subsys_fns_t sys_logging = { .level = -90, .initialize = subsys_logging_initialize, .shutdown = subsys_logging_shutdown, + .get_metrics = logging_metrics_get_stores, }; diff --git a/src/lib/log/util_bug.c b/src/lib/log/util_bug.c index 34b41324af..d2dbb0a7a5 100644 --- a/src/lib/log/util_bug.c +++ b/src/lib/log/util_bug.c @@ -18,6 +18,7 @@ #endif #include "lib/malloc/malloc.h" #include "lib/string/printf.h" +#include "lib/thread/threads.h" #include <string.h> #include <stdlib.h> @@ -101,6 +102,27 @@ tor_assertion_failed_(const char *fname, unsigned int line, tor_free(buf); } +static atomic_counter_t total_bug_reached; + +void +tor_bug_init_counter(void) +{ + atomic_counter_init(&total_bug_reached); +} + +/** Helper to update BUG count in metrics. */ +void +tor_bug_increment_count_(void) +{ + atomic_counter_add(&total_bug_reached, 1); +} + +size_t +tor_bug_get_count(void) +{ + return atomic_counter_get(&total_bug_reached); +} + /** Helper for tor_assert_nonfatal: report the assertion failure. */ void tor_bug_occurred_(const char *fname, unsigned int line, @@ -110,6 +132,11 @@ tor_bug_occurred_(const char *fname, unsigned int line, char *buf = NULL; const char *once_str = once ? " (Future instances of this warning will be silenced.)": ""; + if (! once) { + // _once assertions count from the macro directly so we count them as many + // time as they are reached, and not just once. + tor_bug_increment_count_(); + } if (! expr) { if (capturing_bugs()) { add_captured_bug("This line should not have been reached."); diff --git a/src/lib/log/util_bug.h b/src/lib/log/util_bug.h index dd82981e08..5ea198f7ff 100644 --- a/src/lib/log/util_bug.h +++ b/src/lib/log/util_bug.h @@ -39,6 +39,7 @@ #include "orconfig.h" #include "lib/cc/compat_compiler.h" #include "lib/log/log.h" +#include "lib/smartlist_core/smartlist_core.h" #include "lib/testsupport/testsupport.h" /* Replace assert() with a variant that sends failures to the log before @@ -191,6 +192,7 @@ STMT_END #define tor_assert_nonfatal_unreached_once() STMT_BEGIN \ static int warning_logged__ = 0; \ + tor_bug_increment_count_(); \ if (!warning_logged__) { \ warning_logged__ = 1; \ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, NULL, 1, NULL); \ @@ -198,10 +200,12 @@ STMT_END #define tor_assert_nonfatal_once(cond) STMT_BEGIN \ static int warning_logged__ = 0; \ - if (ASSERT_PREDICT_LIKELY_(cond)) { \ - } else if (!warning_logged__) { \ - warning_logged__ = 1; \ - tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1, NULL);\ + if (!ASSERT_PREDICT_LIKELY_(cond)) { \ + tor_bug_increment_count_(); \ + if (!warning_logged__) { \ + warning_logged__ = 1; \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, #cond, 1, NULL);\ + } \ } \ STMT_END #define BUG(cond) \ @@ -215,18 +219,22 @@ if (( { \ static int var = 0; \ int bool_result = !!(cond); \ - if (bool_result && !var) { \ - var = 1; \ - tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \ - ("!("#cond")"), 1, NULL); \ + if (bool_result) { \ + tor_bug_increment_count_(); \ + if (!var) { \ + var = 1; \ + tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \ + ("!("#cond")"), 1, NULL); \ + } \ } \ bool_result; } )) #else /* !defined(__GNUC__) */ #define IF_BUG_ONCE__(cond,var) \ static int var = 0; \ if ((cond) ? \ - (var ? 1 : \ + (var ? (tor_bug_increment_count_(), 1) : \ (var=1, \ + tor_bug_increment_count_(), \ tor_bug_occurred_(SHORT_FILE__, __LINE__, __func__, \ ("!("#cond")"), 1, NULL), \ 1)) \ @@ -273,12 +281,15 @@ void tor_assertion_failed_(const char *fname, unsigned int line, const char *func, const char *expr, const char *fmt, ...) CHECK_PRINTF(5,6); +void tor_bug_increment_count_(void); +size_t tor_bug_get_count(void); void tor_bug_occurred_(const char *fname, unsigned int line, const char *func, const char *expr, int once, const char *fmt, ...) CHECK_PRINTF(6,7); void tor_abort_(void) ATTR_NORETURN; +void tor_bug_init_counter(void); #ifdef _WIN32 #define SHORT_FILE__ (tor_fix_source_file(__FILE__)) diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index 8ac07abfc9..08322e17d4 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.*/ @@ -263,8 +272,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), @@ -335,6 +345,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); @@ -516,18 +528,33 @@ 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) */ } +/* 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 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) */ } +#endif /* !(defined(ENABLE_FRAGILE_HARDENING) && + defined(ARCH_USES_GENERIC_SYSCALLS)) */ /** Allow a single file to be opened. If <b>use_openat</b> is true, * we're using a libc that remaps all the opens into openats. */ @@ -557,10 +584,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 " @@ -572,7 +614,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) { @@ -592,6 +635,33 @@ sb_open(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#ifdef ARCH_USES_GENERIC_SYSCALLS +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; +} +#else static int sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { @@ -616,9 +686,11 @@ sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#endif /* defined(ARCH_USES_GENERIC_SYSCALLS) */ +#if defined(ARCH_USES_GENERIC_SYSCALLS) static int -sb_fchmodat(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; @@ -628,12 +700,12 @@ 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_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 fchmodat syscall, received " + log_err(LD_BUG,"(Sandbox) failed to add fchownat syscall, received " "libseccomp error %d", rc); return rc; } @@ -642,8 +714,7 @@ sb_fchmodat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } - -#ifdef __i386__ +#elif defined(__i386__) static int sb_chown32(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { @@ -693,10 +764,15 @@ sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } -#endif /* defined(__i386__) */ +#endif /* defined(ARCH_USES_GENERIC_SYSCALLS) || defined(__i386__) */ +#if defined(__NR_rename) +/** + * Function responsible for setting up the rename syscall for + * the seccomp filter sandbox. + */ static int -sb_fchownat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +sb_rename(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { int rc; sandbox_cfg_t *elem = NULL; @@ -705,13 +781,14 @@ sb_fchownat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) 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 (param != NULL && param->prot == 1 && + param->syscall == SCMP_SYS(rename)) { + + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rename), + SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value), + SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value2)); if (rc != 0) { - log_err(LD_BUG,"(Sandbox) failed to add fchownat syscall, received " + log_err(LD_BUG,"(Sandbox) failed to add rename syscall, received " "libseccomp error %d", rc); return rc; } @@ -720,13 +797,13 @@ sb_fchownat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } - +#elif defined(__NR_renameat) /** - * Function responsible for setting up the rename syscall for + * Function responsible for setting up the renameat syscall for * the seccomp filter sandbox. */ static int -sb_rename(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +sb_renameat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { int rc; sandbox_cfg_t *elem = NULL; @@ -736,13 +813,15 @@ sb_rename(scmp_filter_ctx ctx, sandbox_cfg_t *filter) smp_param_t *param = elem->param; if (param != NULL && param->prot == 1 && - param->syscall == SCMP_SYS(rename)) { + param->syscall == SCMP_SYS(renameat)) { - rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rename), - SCMP_CMP_STR(0, SCMP_CMP_EQ, param->value), - SCMP_CMP_STR(1, SCMP_CMP_EQ, param->value2)); + 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 rename syscall, received " + log_err(LD_BUG,"(Sandbox) failed to add renameat syscall, received " "libseccomp error %d", rc); return rc; } @@ -751,13 +830,13 @@ sb_rename(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } - +#else /** - * Function responsible for setting up the renameat syscall for + * Function responsible for setting up the renameat2 syscall for * the seccomp filter sandbox. */ static int -sb_renameat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +sb_renameat2(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { int rc; sandbox_cfg_t *elem = NULL; @@ -767,15 +846,16 @@ sb_renameat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) smp_param_t *param = elem->param; if (param != NULL && param->prot == 1 && - param->syscall == SCMP_SYS(renameat)) { + param->syscall == SCMP_SYS(renameat2)) { - rc = seccomp_rule_add_4(ctx, SCMP_ACT_ALLOW, SCMP_SYS(renameat), + 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_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 renameat syscall, received " + log_err(LD_BUG,"(Sandbox) failed to add renameat2 syscall, received " "libseccomp error %d", rc); return rc; } @@ -784,7 +864,19 @@ sb_renameat(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#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. @@ -840,6 +932,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 /** @@ -859,9 +953,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; @@ -1351,6 +1453,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 @@ -1409,22 +1545,33 @@ 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, - sb_chmod, +#if defined(ARCH_USES_GENERIC_SYSCALLS) sb_fchmodat, +#else + 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 +#if defined(__NR_rename) sb_rename, +#elif defined(__NR_renameat) sb_renameat, +#else + sb_renameat2, +#endif #ifdef __NR_fcntl64 sb_fcntl64, #endif @@ -1434,7 +1581,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 @@ -1690,27 +1839,31 @@ 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 -#if defined(__aarch64__) && defined(__LP64__) +#if defined(ARCH_USES_GENERIC_SYSCALLS) #define SCMP_chmod SCMP_SYS(fchmodat) #else #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 +#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) diff --git a/src/lib/string/util_string.c b/src/lib/string/util_string.c index b1c0a11439..60b5933e4d 100644 --- a/src/lib/string/util_string.c +++ b/src/lib/string/util_string.c @@ -31,6 +31,8 @@ tor_memmem(const void *_haystack, size_t hlen, { #if defined(HAVE_MEMMEM) && (!defined(__GNUC__) || __GNUC__ >= 2) raw_assert(nlen); + if (nlen > hlen) + return NULL; return memmem(_haystack, hlen, _needle, nlen); #else /* This isn't as fast as the GLIBC implementation, but it doesn't need to |