diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/cc/compat_compiler.h | 31 | ||||
-rw-r--r-- | src/lib/metrics/metrics_common.c | 13 | ||||
-rw-r--r-- | src/lib/metrics/metrics_common.h | 3 | ||||
-rw-r--r-- | src/lib/metrics/metrics_store.c | 21 | ||||
-rw-r--r-- | src/lib/metrics/metrics_store.h | 1 | ||||
-rw-r--r-- | src/lib/metrics/prometheus.c | 11 | ||||
-rw-r--r-- | src/lib/metrics/prometheus.h | 2 | ||||
-rw-r--r-- | src/lib/net/address.c | 22 | ||||
-rw-r--r-- | src/lib/sandbox/sandbox.c | 130 | ||||
-rw-r--r-- | src/lib/string/printf.c | 4 |
10 files changed, 207 insertions, 31 deletions
diff --git a/src/lib/cc/compat_compiler.h b/src/lib/cc/compat_compiler.h index 50bfedffba..991b33d9e7 100644 --- a/src/lib/cc/compat_compiler.h +++ b/src/lib/cc/compat_compiler.h @@ -15,6 +15,15 @@ #include "orconfig.h" #include <inttypes.h> +#if defined(__MINGW32__) || defined(__MINGW64__) +#define MINGW_ANY +#endif + +#ifdef MINGW_ANY +/* We need this for __MINGW_PRINTF_FORMAT, alas. */ +#include <stdio.h> +#endif + #if defined(__has_feature) # if __has_feature(address_sanitizer) /* Some of the fancy glibc strcmp() macros include references to memory that @@ -36,16 +45,30 @@ #error "It seems that you encode characters in something other than ASCII." #endif +/* Use the right magic attribute on mingw, which might be printf, gnu_printf, + * or ms_printf, depending on how we're set up to build. + */ +#ifdef __MINGW_PRINTF_FORMAT +#define PRINTF_FORMAT_ATTR __MINGW_PRINTF_FORMAT +#else +#define PRINTF_FORMAT_ATTR printf +#endif +#ifdef __MINGW_SCANF_FORMAT +#define SCANF_FORMAT_ATTR __MINGW_SCANF_FORMAT +#else +#define SCANF_FORMAT_ATTR scanf +#endif + /* GCC can check printf and scanf types on arbitrary functions. */ #ifdef __GNUC__ #define CHECK_PRINTF(formatIdx, firstArg) \ - __attribute__ ((format(printf, formatIdx, firstArg))) + __attribute__ ((format(PRINTF_FORMAT_ATTR, formatIdx, firstArg))) #else #define CHECK_PRINTF(formatIdx, firstArg) #endif /* defined(__GNUC__) */ #ifdef __GNUC__ #define CHECK_SCANF(formatIdx, firstArg) \ - __attribute__ ((format(scanf, formatIdx, firstArg))) + __attribute__ ((format(SCANF_FORMAT_ATTR, formatIdx, firstArg))) #else #define CHECK_SCANF(formatIdx, firstArg) #endif /* defined(__GNUC__) */ @@ -191,10 +214,6 @@ #define OP_EQ == #define OP_NE != -#if defined(__MINGW32__) || defined(__MINGW64__) -#define MINGW_ANY -#endif - /** Macro: yield a pointer to the field at position <b>off</b> within the * structure <b>st</b>. Example: * <pre> diff --git a/src/lib/metrics/metrics_common.c b/src/lib/metrics/metrics_common.c index 5941a4d892..f3f7e22d88 100644 --- a/src/lib/metrics/metrics_common.c +++ b/src/lib/metrics/metrics_common.c @@ -11,6 +11,7 @@ #include "orconfig.h" #include "lib/log/util_bug.h" +#include "lib/string/printf.h" #include "lib/metrics/metrics_common.h" @@ -27,3 +28,15 @@ metrics_type_to_str(const metrics_type_t type) tor_assert_unreached(); } } + +/** Return a static buffer pointer that contains a formatted label on the form + * of key=value. + * + * Subsequent call to this function invalidates the previous buffer. */ +const char * +metrics_format_label(const char *key, const char *value) +{ + static char buf[128]; + tor_snprintf(buf, sizeof(buf), "%s=\"%s\"", key, value); + return buf; +} diff --git a/src/lib/metrics/metrics_common.h b/src/lib/metrics/metrics_common.h index 59aa9c0e90..3644ad3d50 100644 --- a/src/lib/metrics/metrics_common.h +++ b/src/lib/metrics/metrics_common.h @@ -42,4 +42,7 @@ typedef struct metrics_gauge_t { const char *metrics_type_to_str(const metrics_type_t type); +/* Helpers. */ +const char *metrics_format_label(const char *key, const char *value); + #endif /* !defined(TOR_LIB_METRICS_METRICS_COMMON_H) */ diff --git a/src/lib/metrics/metrics_store.c b/src/lib/metrics/metrics_store.c index 4cab5245f3..33b1780438 100644 --- a/src/lib/metrics/metrics_store.c +++ b/src/lib/metrics/metrics_store.c @@ -34,7 +34,8 @@ struct metrics_store_t { }; /** Function pointer to the format function of a specific driver. */ -typedef void (fmt_driver_fn_t)(const metrics_store_entry_t *, buf_t *); +typedef void (fmt_driver_fn_t)(const metrics_store_entry_t *, buf_t *, + bool no_comment); /** Helper: Free a single entry in a metrics_store_t taking a void pointer * parameter. */ @@ -47,6 +48,8 @@ metrics_store_free_void(void *p) smartlist_free(list); } +#include <stdio.h> + /** Put the given store output in the buffer data and use the format function * given in fmt to get it for each entry. */ static void @@ -57,8 +60,11 @@ get_output(const metrics_store_t *store, buf_t *data, fmt_driver_fn_t fmt) tor_assert(fmt); STRMAP_FOREACH(store->entries, key, const smartlist_t *, entries) { + /* Indicate that we've formatted the coment already for the entries. */ + bool comment_formatted = false; SMARTLIST_FOREACH_BEGIN(entries, const metrics_store_entry_t *, entry) { - fmt(entry, data); + fmt(entry, data, comment_formatted); + comment_formatted = true; } SMARTLIST_FOREACH_END(entry); } STRMAP_FOREACH_END; } @@ -138,3 +144,14 @@ metrics_store_get_output(const metrics_format_t fmt, // LCOV_EXCL_STOP } } + +/** Reset a store as in free its content. */ +void +metrics_store_reset(metrics_store_t *store) +{ + if (store == NULL) { + return; + } + strmap_free(store->entries, metrics_store_free_void); + store->entries = strmap_new(); +} diff --git a/src/lib/metrics/metrics_store.h b/src/lib/metrics/metrics_store.h index 42bc56e8fd..d85f484bd6 100644 --- a/src/lib/metrics/metrics_store.h +++ b/src/lib/metrics/metrics_store.h @@ -28,6 +28,7 @@ metrics_store_t *metrics_store_new(void); metrics_store_entry_t *metrics_store_add(metrics_store_t *store, metrics_type_t type, const char *name, const char *help); +void metrics_store_reset(metrics_store_t *store); /* Accessors. */ smartlist_t *metrics_store_get_all(const metrics_store_t *store, diff --git a/src/lib/metrics/prometheus.c b/src/lib/metrics/prometheus.c index 65241ed6c1..aac23ac92e 100644 --- a/src/lib/metrics/prometheus.c +++ b/src/lib/metrics/prometheus.c @@ -42,14 +42,17 @@ format_labels(smartlist_t *labels) /** Format the given entry in to the buffer data. */ void -prometheus_format_store_entry(const metrics_store_entry_t *entry, buf_t *data) +prometheus_format_store_entry(const metrics_store_entry_t *entry, buf_t *data, + bool no_comment) { tor_assert(entry); tor_assert(data); - buf_add_printf(data, "# HELP %s %s\n", entry->name, entry->help); - buf_add_printf(data, "# TYPE %s %s\n", entry->name, - metrics_type_to_str(entry->type)); + if (!no_comment) { + buf_add_printf(data, "# HELP %s %s\n", entry->name, entry->help); + buf_add_printf(data, "# TYPE %s %s\n", entry->name, + metrics_type_to_str(entry->type)); + } buf_add_printf(data, "%s%s %" PRIi64 "\n", entry->name, format_labels(entry->labels), metrics_store_entry_get_value(entry)); diff --git a/src/lib/metrics/prometheus.h b/src/lib/metrics/prometheus.h index 19770e7911..faa7681daa 100644 --- a/src/lib/metrics/prometheus.h +++ b/src/lib/metrics/prometheus.h @@ -13,6 +13,6 @@ #include "lib/metrics/metrics_store_entry.h" void prometheus_format_store_entry(const metrics_store_entry_t *entry, - buf_t *data); + buf_t *data, bool no_comment); #endif /* !defined(TOR_LIB_METRICS_PROMETHEUS_H) */ diff --git a/src/lib/net/address.c b/src/lib/net/address.c index 26b155bc4c..085eb8c458 100644 --- a/src/lib/net/address.c +++ b/src/lib/net/address.c @@ -2005,20 +2005,15 @@ parse_port_range(const char *port, uint16_t *port_min_out, char *endptr = NULL; port_min = (int)tor_parse_long(port, 10, 0, 65535, &ok, &endptr); if (!ok) { - log_warn(LD_GENERAL, - "Malformed port %s on address range; rejecting.", - escaped(port)); - return -1; - } else if (endptr && *endptr == '-') { + goto malformed_port; + } else if (endptr && *endptr != '\0') { + if (*endptr != '-') + goto malformed_port; port = endptr+1; endptr = NULL; port_max = (int)tor_parse_long(port, 10, 1, 65535, &ok, &endptr); - if (!ok) { - log_warn(LD_GENERAL, - "Malformed port %s on address range; rejecting.", - escaped(port)); - return -1; - } + if (!ok) + goto malformed_port; } else { port_max = port_min; } @@ -2037,6 +2032,11 @@ parse_port_range(const char *port, uint16_t *port_min_out, *port_max_out = (uint16_t) port_max; return 0; + malformed_port: + log_warn(LD_GENERAL, + "Malformed port %s on address range; rejecting.", + escaped(port)); + return -1; } /** Given a host-order <b>addr</b>, call tor_inet_ntop() on it diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index 02222e5a1c..a15f99ad76 100644 --- a/src/lib/sandbox/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -58,6 +58,10 @@ #include <linux/futex.h> #include <sys/file.h> +#ifdef ENABLE_FRAGILE_HARDENING +#include <sys/ptrace.h> +#endif + #include <stdarg.h> #include <seccomp.h> #include <signal.h> @@ -148,7 +152,11 @@ static sandbox_cfg_t *filter_dynamic = NULL; static int filter_nopar_gen[] = { SCMP_SYS(access), SCMP_SYS(brk), +#ifdef __NR_clock_gettime64 + SCMP_SYS(clock_gettime64), +#else SCMP_SYS(clock_gettime), +#endif SCMP_SYS(close), SCMP_SYS(clone), SCMP_SYS(dup), @@ -191,6 +199,9 @@ static int filter_nopar_gen[] = { SCMP_SYS(getgid32), #endif SCMP_SYS(getpid), +#ifdef ENABLE_FRAGILE_HARDENING + SCMP_SYS(getppid), +#endif #ifdef __NR_getrlimit SCMP_SYS(getrlimit), #endif @@ -241,6 +252,9 @@ static int filter_nopar_gen[] = { SCMP_SYS(sigreturn), #endif SCMP_SYS(stat), +#if defined(__i386__) && defined(__NR_statx) + SCMP_SYS(statx), +#endif SCMP_SYS(uname), SCMP_SYS(wait4), SCMP_SYS(write), @@ -339,6 +353,7 @@ sb_rt_sigaction(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return rc; } +#ifdef __NR_time /** * Function responsible for setting up the time syscall for * the seccomp filter sandbox. @@ -347,13 +362,11 @@ static int sb_time(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { (void) filter; -#ifdef __NR_time + return seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(time), SCMP_CMP(0, SCMP_CMP_EQ, 0)); -#else - return 0; -#endif /* defined(__NR_time) */ } +#endif /* defined(__NR_time) */ /** * Function responsible for setting up the accept4 syscall for @@ -532,6 +545,24 @@ 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 + * restriction or the sanitizer will be unable to execute normally when the + * process terminates. */ + 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 " + "libseccomp error %d", rc); + return rc; + } + + /* If glibc also uses only the "open" syscall to open files on this system + * there is no need to consider any additional rules. */ + if (!use_openat) + return 0; +#endif + // for each dynamic parameter filters for (elem = filter; elem != NULL; elem = elem->next) { smp_param_t *param = elem->param; @@ -575,6 +606,32 @@ sb_chmod(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#ifdef __i386__ +static int +sb_chown32(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(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 chown32 syscall, received " + "libseccomp error %d", rc); + return rc; + } + } + } + + return 0; +} +#else static int sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter) { @@ -599,6 +656,7 @@ sb_chown(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#endif /* defined(__i386__) */ /** * Function responsible for setting up the rename syscall for @@ -687,6 +745,34 @@ sb_opendir(scmp_filter_ctx ctx, sandbox_cfg_t *filter) return 0; } +#ifdef ENABLE_FRAGILE_HARDENING +/** + * Function responsible for setting up the ptrace syscall for + * the seccomp filter sandbox. + */ +static int +sb_ptrace(scmp_filter_ctx ctx, sandbox_cfg_t *filter) +{ + int rc; + pid_t pid = getpid(); + (void) filter; + + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ptrace), + SCMP_CMP(0, SCMP_CMP_EQ, PTRACE_ATTACH), + SCMP_CMP(1, SCMP_CMP_EQ, pid)); + if (rc) + return rc; + + 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)); + if (rc) + return rc; + + return 0; +} +#endif + /** * Function responsible for setting up the socket syscall for * the seccomp filter sandbox. @@ -1009,6 +1095,18 @@ sb_prctl(scmp_filter_ctx ctx, sandbox_cfg_t *filter) int rc = 0; (void) filter; +#ifdef ENABLE_FRAGILE_HARDENING + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), + SCMP_CMP(0, SCMP_CMP_EQ, PR_GET_DUMPABLE)); + if (rc) + return rc; + + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), + SCMP_CMP(0, SCMP_CMP_EQ, PR_SET_PTRACER)); + if (rc) + return rc; +#endif + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), SCMP_CMP(0, SCMP_CMP_EQ, PR_SET_DUMPABLE)); if (rc) @@ -1053,6 +1151,13 @@ sb_rt_sigprocmask(scmp_filter_ctx ctx, sandbox_cfg_t *filter) int rc = 0; (void) filter; +#ifdef ENABLE_FRAGILE_HARDENING + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), + SCMP_CMP(0, SCMP_CMP_EQ, SIG_BLOCK)); + if (rc) + return rc; +#endif + rc = seccomp_rule_add_1(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigprocmask), SCMP_CMP(0, SCMP_CMP_EQ, SIG_UNBLOCK)); if (rc) @@ -1192,16 +1297,25 @@ sb_kill(scmp_filter_ctx ctx, sandbox_cfg_t *filter) static sandbox_filter_func_t filter_func[] = { sb_rt_sigaction, sb_rt_sigprocmask, +#ifdef __NR_time sb_time, +#endif sb_accept4, #ifdef __NR_mmap2 sb_mmap2, #endif +#ifdef __i386__ + sb_chown32, +#else sb_chown, +#endif sb_chmod, sb_open, sb_openat, sb_opendir, +#ifdef ENABLE_FRAGILE_HARDENING + sb_ptrace, +#endif sb_rename, #ifdef __NR_fcntl64 sb_fcntl64, @@ -1468,6 +1582,12 @@ new_element(int syscall, char *value) return new_element2(syscall, value, NULL); } +#ifdef __i386__ +#define SCMP_chown SCMP_SYS(chown32) +#else +#define SCMP_chown SCMP_SYS(chown) +#endif + #ifdef __NR_stat64 #define SCMP_stat SCMP_SYS(stat64) #else @@ -1518,7 +1638,7 @@ sandbox_cfg_allow_chown_filename(sandbox_cfg_t **cfg, char *file) { sandbox_cfg_t *elem = NULL; - elem = new_element(SCMP_SYS(chown), file); + elem = new_element(SCMP_chown, file); elem->next = *cfg; *cfg = elem; diff --git a/src/lib/string/printf.c b/src/lib/string/printf.c index 62758093a7..bd35b76d1b 100644 --- a/src/lib/string/printf.c +++ b/src/lib/string/printf.c @@ -8,9 +8,9 @@ * \brief Compatibility wrappers around snprintf and its friends **/ +#include "lib/cc/torint.h" #include "lib/string/printf.h" #include "lib/err/torerr.h" -#include "lib/cc/torint.h" #include "lib/malloc/malloc.h" #include <stdlib.h> @@ -45,7 +45,7 @@ tor_vsnprintf(char *str, size_t size, const char *format, va_list args) return -1; /* no place for the NUL */ if (size > SIZE_T_CEILING) return -1; -#ifdef _WIN32 +#if defined(_WIN32) && !defined(HAVE_VSNPRINTF) r = _vsnprintf(str, size, format, args); #else r = vsnprintf(str, size, format, args); |