diff options
Diffstat (limited to 'src/lib')
27 files changed, 570 insertions, 125 deletions
diff --git a/src/lib/compress/compress.c b/src/lib/compress/compress.c index 83e63905cc..346e77f07d 100644 --- a/src/lib/compress/compress.c +++ b/src/lib/compress/compress.c @@ -66,7 +66,15 @@ tor_compress_is_compression_bomb,(size_t size_in, size_t size_out)) if (size_in == 0 || size_out < CHECK_FOR_COMPRESSION_BOMB_AFTER) return 0; - return (size_out / size_in > MAX_UNCOMPRESSION_FACTOR); + if (size_out / size_in > MAX_UNCOMPRESSION_FACTOR) { + log_warn(LD_GENERAL, + "Detected possible compression bomb with " + "input size = %"TOR_PRIuSZ " and output size = %"TOR_PRIuSZ, + size_in, size_out); + return 1; + } + + return 0; } /** Guess the size that <b>in_len</b> will be after compression or diff --git a/src/lib/crypt_ops/compat_openssl.h b/src/lib/crypt_ops/compat_openssl.h index 0f56f338b5..c5eccdb015 100644 --- a/src/lib/crypt_ops/compat_openssl.h +++ b/src/lib/crypt_ops/compat_openssl.h @@ -20,32 +20,36 @@ * \brief compatibility definitions for working with different openssl forks **/ -#if !defined(LIBRESSL_VERSION_NUMBER) && \ - OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,1) +#if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,1) #error "We require OpenSSL >= 1.0.1" #endif -#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) && \ - ! defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) /* We define this macro if we're trying to build with the majorly refactored * API in OpenSSL 1.1 */ #define OPENSSL_1_1_API #endif /* OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) && ... */ -#ifndef OPENSSL_1_1_API -#define OpenSSL_version(v) SSLeay_version(v) -#define tor_OpenSSL_version_num() SSLeay() +/* LibreSSL claims to be OpenSSL 2.0 but lacks these OpenSSL 1.1 APIs */ +#if !defined(OPENSSL_1_1_API) || defined(LIBRESSL_VERSION_NUMBER) #define RAND_OpenSSL() RAND_SSLeay() #define STATE_IS_SW_SERVER_HELLO(st) \ (((st) == SSL3_ST_SW_SRVR_HELLO_A) || \ ((st) == SSL3_ST_SW_SRVR_HELLO_B)) #define OSSL_HANDSHAKE_STATE int #define CONST_IF_OPENSSL_1_1_API -#else /* defined(OPENSSL_1_1_API) */ -#define tor_OpenSSL_version_num() OpenSSL_version_num() +#else #define STATE_IS_SW_SERVER_HELLO(st) \ ((st) == TLS_ST_SW_SRVR_HELLO) #define CONST_IF_OPENSSL_1_1_API const +#endif + +/* OpenSSL 1.1 and LibreSSL both have these APIs */ +#ifndef OPENSSL_1_1_API +#define OpenSSL_version(v) SSLeay_version(v) +#define tor_OpenSSL_version_num() SSLeay() +#else /* defined(OPENSSL_1_1_API) */ +#define tor_OpenSSL_version_num() OpenSSL_version_num() #endif /* !defined(OPENSSL_1_1_API) */ #endif /* defined(ENABLE_OPENSSL) */ diff --git a/src/lib/crypt_ops/crypto_openssl_mgt.h b/src/lib/crypt_ops/crypto_openssl_mgt.h index c6f63ffa08..96a37721dd 100644 --- a/src/lib/crypt_ops/crypto_openssl_mgt.h +++ b/src/lib/crypt_ops/crypto_openssl_mgt.h @@ -54,8 +54,7 @@ #define DISABLE_ENGINES #endif -#if OPENSSL_VERSION_NUMBER >= OPENSSL_VER(1,1,0,0,5) && \ - !defined(LIBRESSL_VERSION_NUMBER) +#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/crypt_ops/crypto_rsa_openssl.c b/src/lib/crypt_ops/crypto_rsa_openssl.c index a21c4a65cf..544d72e6ca 100644 --- a/src/lib/crypt_ops/crypto_rsa_openssl.c +++ b/src/lib/crypt_ops/crypto_rsa_openssl.c @@ -572,7 +572,9 @@ static bool rsa_private_key_too_long(RSA *rsa, int max_bits) { const BIGNUM *n, *e, *p, *q, *d, *dmp1, *dmq1, *iqmp; -#ifdef OPENSSL_1_1_API +#if defined(OPENSSL_1_1_API) && \ + (!defined(LIBRESSL_VERSION_NUMBER) || \ + LIBRESSL_VERSION_NUMBER >= OPENSSL_V_SERIES(3,5,0)) #if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,1) n = RSA_get0_n(rsa); @@ -591,7 +593,7 @@ rsa_private_key_too_long(RSA *rsa, int max_bits) if (RSA_bits(rsa) > max_bits) return true; -#else /* !defined(OPENSSL_1_1_API) */ +#else /* !defined(OPENSSL_1_1_API) && ... */ n = rsa->n; e = rsa->e; p = rsa->p; @@ -600,7 +602,7 @@ rsa_private_key_too_long(RSA *rsa, int max_bits) dmp1 = rsa->dmp1; dmq1 = rsa->dmq1; iqmp = rsa->iqmp; -#endif /* defined(OPENSSL_1_1_API) */ +#endif /* defined(OPENSSL_1_1_API) && ... */ if (n && BN_num_bits(n) > max_bits) return true; diff --git a/src/lib/dispatch/dispatch_cfg_st.h b/src/lib/dispatch/dispatch_cfg_st.h index 636f2e6df5..503d13e010 100644 --- a/src/lib/dispatch/dispatch_cfg_st.h +++ b/src/lib/dispatch/dispatch_cfg_st.h @@ -24,9 +24,9 @@ struct dispatch_cfg_t { struct smartlist_t *type_by_msg; /** A list of channel_id_t (cast to void*), indexed by msg_t. */ struct smartlist_t *chan_by_msg; - /** A list of dispatch_rcv_t, indexed by msg_type_id_t. */ + /** A list of dispatch_typefns_t, indexed by msg_type_id_t. */ struct smartlist_t *fns_by_type; - /** A list of dispatch_typefns_t, indexed by msg_t. */ + /** A list of dispatch_rcv_t, indexed by msg_t. */ struct smartlist_t *recv_by_msg; }; diff --git a/src/lib/evloop/compat_libevent.c b/src/lib/evloop/compat_libevent.c index fd840f8085..c882d3478e 100644 --- a/src/lib/evloop/compat_libevent.c +++ b/src/lib/evloop/compat_libevent.c @@ -137,10 +137,8 @@ tor_libevent_initialize(tor_libevent_cfg_t *torcfg) (void)torcfg; { - int attempts = 0; struct event_config *cfg; - ++attempts; cfg = event_config_new(); tor_assert(cfg); diff --git a/src/lib/evloop/token_bucket.c b/src/lib/evloop/token_bucket.c index 16452314e2..9bcfeb9367 100644 --- a/src/lib/evloop/token_bucket.c +++ b/src/lib/evloop/token_bucket.c @@ -111,7 +111,9 @@ token_bucket_raw_dec(token_bucket_raw_t *bucket, return becomes_empty; } -/** Convert a rate in bytes per second to a rate in bytes per step */ +/** Convert a rate in bytes per second to a rate in bytes per step. + * This is used for the 'rw' style (tick based) token buckets but not for + * the 'ctr' style buckets which count seconds. */ STATIC uint32_t rate_per_sec_to_rate_per_step(uint32_t rate) { @@ -130,18 +132,18 @@ rate_per_sec_to_rate_per_step(uint32_t rate) /** * Initialize a token bucket in *<b>bucket</b>, set up to allow <b>rate</b> * bytes per second, with a maximum burst of <b>burst</b> bytes. The bucket - * is created such that <b>now_ts</b> is the current timestamp. The bucket - * starts out full. + * is created such that <b>now_ts_stamp</b> is the current time in coarse stamp + * units. The bucket starts out full. */ void token_bucket_rw_init(token_bucket_rw_t *bucket, uint32_t rate, uint32_t burst, - uint32_t now_ts) + uint32_t now_ts_stamp) { memset(bucket, 0, sizeof(token_bucket_rw_t)); token_bucket_rw_adjust(bucket, rate, burst); - token_bucket_rw_reset(bucket, now_ts); + token_bucket_rw_reset(bucket, now_ts_stamp); } /** @@ -161,56 +163,54 @@ token_bucket_rw_adjust(token_bucket_rw_t *bucket, } /** - * Reset <b>bucket</b> to be full, as of timestamp <b>now_ts</b>. + * Reset <b>bucket</b> to be full, as of timestamp <b>now_ts_stamp</b>. */ void token_bucket_rw_reset(token_bucket_rw_t *bucket, - uint32_t now_ts) + uint32_t now_ts_stamp) { token_bucket_raw_reset(&bucket->read_bucket, &bucket->cfg); token_bucket_raw_reset(&bucket->write_bucket, &bucket->cfg); - bucket->last_refilled_at_timestamp = now_ts; + bucket->last_refilled_at_timestamp = now_ts_stamp; } /** * Refill <b>bucket</b> as appropriate, given that the current timestamp - * is <b>now_ts</b>. + * is <b>now_ts_stamp</b> in coarse timestamp units. * * Return a bitmask containing TB_READ iff read bucket was empty and became * nonempty, and TB_WRITE iff the write bucket was empty and became nonempty. */ int token_bucket_rw_refill(token_bucket_rw_t *bucket, - uint32_t now_ts) + uint32_t now_ts_stamp) { const uint32_t elapsed_ticks = - (now_ts - bucket->last_refilled_at_timestamp); - if (elapsed_ticks > UINT32_MAX-(300*1000)) { - /* Either about 48 days have passed since the last refill, or the - * monotonic clock has somehow moved backwards. (We're looking at you, - * Windows.). We accept up to a 5 minute jump backwards as - * "unremarkable". - */ - return 0; - } - const uint32_t elapsed_steps = elapsed_ticks / TICKS_PER_STEP; + (now_ts_stamp - bucket->last_refilled_at_timestamp); + int flags = 0; - if (!elapsed_steps) { - /* Note that if less than one whole step elapsed, we don't advance the - * time in last_refilled_at. That's intentional: we want to make sure - * that we add some bytes to it eventually. */ - return 0; - } + /* Skip over updates that include an overflow or a very large jump. + * This can happen for platform specific reasons, such as the old ~48 + * day windows timer. */ + if (elapsed_ticks <= UINT32_MAX/4) { + const uint32_t elapsed_steps = elapsed_ticks / TICKS_PER_STEP; - int flags = 0; - if (token_bucket_raw_refill_steps(&bucket->read_bucket, - &bucket->cfg, elapsed_steps)) - flags |= TB_READ; - if (token_bucket_raw_refill_steps(&bucket->write_bucket, - &bucket->cfg, elapsed_steps)) - flags |= TB_WRITE; + if (!elapsed_steps) { + /* Note that if less than one whole step elapsed, we don't advance the + * time in last_refilled_at. That's intentional: we want to make sure + * that we add some bytes to it eventually. */ + return 0; + } + + if (token_bucket_raw_refill_steps(&bucket->read_bucket, + &bucket->cfg, elapsed_steps)) + flags |= TB_READ; + if (token_bucket_raw_refill_steps(&bucket->write_bucket, + &bucket->cfg, elapsed_steps)) + flags |= TB_WRITE; + } - bucket->last_refilled_at_timestamp = now_ts; + bucket->last_refilled_at_timestamp = now_ts_stamp; return flags; } @@ -259,15 +259,17 @@ token_bucket_rw_dec(token_bucket_rw_t *bucket, /** Initialize a token bucket in <b>bucket</b>, set up to allow <b>rate</b> * per second, with a maximum burst of <b>burst</b>. The bucket is created - * such that <b>now_ts</b> is the current timestamp. The bucket starts out - * full. */ + * such that <b>now_ts_sec</b> is the current timestamp. The bucket starts + * out full. Note that these counters use seconds instead of approximate + * milliseconds, in order to allow a lower minimum rate than the rw counters. + */ void token_bucket_ctr_init(token_bucket_ctr_t *bucket, uint32_t rate, - uint32_t burst, uint32_t now_ts) + uint32_t burst, uint32_t now_ts_sec) { memset(bucket, 0, sizeof(token_bucket_ctr_t)); token_bucket_ctr_adjust(bucket, rate, burst); - token_bucket_ctr_reset(bucket, now_ts); + token_bucket_ctr_reset(bucket, now_ts_sec); } /** Change the configured rate and burst of the given token bucket object in @@ -280,31 +282,28 @@ token_bucket_ctr_adjust(token_bucket_ctr_t *bucket, uint32_t rate, token_bucket_raw_adjust(&bucket->counter, &bucket->cfg); } -/** Reset <b>bucket</b> to be full, as of timestamp <b>now_ts</b>. */ +/** Reset <b>bucket</b> to be full, as of timestamp <b>now_ts_sec</b>. */ void -token_bucket_ctr_reset(token_bucket_ctr_t *bucket, uint32_t now_ts) +token_bucket_ctr_reset(token_bucket_ctr_t *bucket, uint32_t now_ts_sec) { token_bucket_raw_reset(&bucket->counter, &bucket->cfg); - bucket->last_refilled_at_timestamp = now_ts; + bucket->last_refilled_at_timestamp = now_ts_sec; } /** Refill <b>bucket</b> as appropriate, given that the current timestamp is - * <b>now_ts</b>. */ + * <b>now_ts_sec</b> in seconds. */ void -token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts) +token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts_sec) { - const uint32_t elapsed_ticks = - (now_ts - bucket->last_refilled_at_timestamp); - if (elapsed_ticks > UINT32_MAX-(300*1000)) { - /* Either about 48 days have passed since the last refill, or the - * monotonic clock has somehow moved backwards. (We're looking at you, - * Windows.). We accept up to a 5 minute jump backwards as - * "unremarkable". - */ - return; - } + const uint32_t elapsed_sec = + (now_ts_sec - bucket->last_refilled_at_timestamp); - token_bucket_raw_refill_steps(&bucket->counter, &bucket->cfg, - elapsed_ticks); - bucket->last_refilled_at_timestamp = now_ts; + /* Are we detecting a rollover or a similar extremely large jump? This + * shouldn't generally happen, but if it does for whatever (possibly + * platform-specific) reason, ignore it. */ + if (elapsed_sec <= UINT32_MAX/4) { + token_bucket_raw_refill_steps(&bucket->counter, &bucket->cfg, + elapsed_sec); + } + bucket->last_refilled_at_timestamp = now_ts_sec; } diff --git a/src/lib/evloop/token_bucket.h b/src/lib/evloop/token_bucket.h index b57d704298..d042041e02 100644 --- a/src/lib/evloop/token_bucket.h +++ b/src/lib/evloop/token_bucket.h @@ -66,19 +66,19 @@ typedef struct token_bucket_rw_t { void token_bucket_rw_init(token_bucket_rw_t *bucket, uint32_t rate, uint32_t burst, - uint32_t now_ts); + uint32_t now_ts_stamp); void token_bucket_rw_adjust(token_bucket_rw_t *bucket, uint32_t rate, uint32_t burst); void token_bucket_rw_reset(token_bucket_rw_t *bucket, - uint32_t now_ts); + uint32_t now_ts_stamp); #define TB_READ 1 #define TB_WRITE 2 int token_bucket_rw_refill(token_bucket_rw_t *bucket, - uint32_t now_ts); + uint32_t now_ts_stamp); int token_bucket_rw_dec_read(token_bucket_rw_t *bucket, ssize_t n); @@ -114,11 +114,11 @@ typedef struct token_bucket_ctr_t { } token_bucket_ctr_t; void token_bucket_ctr_init(token_bucket_ctr_t *bucket, uint32_t rate, - uint32_t burst, uint32_t now_ts); + uint32_t burst, uint32_t now_ts_sec); void token_bucket_ctr_adjust(token_bucket_ctr_t *bucket, uint32_t rate, uint32_t burst); -void token_bucket_ctr_reset(token_bucket_ctr_t *bucket, uint32_t now_ts); -void token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts); +void token_bucket_ctr_reset(token_bucket_ctr_t *bucket, uint32_t now_ts_sec); +void token_bucket_ctr_refill(token_bucket_ctr_t *bucket, uint32_t now_ts_sec); static inline bool token_bucket_ctr_dec(token_bucket_ctr_t *bucket, ssize_t n) diff --git a/src/lib/evloop/workqueue.c b/src/lib/evloop/workqueue.c index bc929148eb..9a0c02fbd0 100644 --- a/src/lib/evloop/workqueue.c +++ b/src/lib/evloop/workqueue.c @@ -20,7 +20,10 @@ * The main thread can also queue an "update" that will be handled by all the * workers. This is useful for updating state that all the workers share. * - * In Tor today, there is currently only one thread pool, used in cpuworker.c. + * In Tor today, there is currently only one thread pool, managed + * in cpuworker.c and handling a variety of types of work, from the original + * "onion skin" circuit handshakes, to consensus diff computation, to + * client-side onion service PoW generation. */ #include "orconfig.h" diff --git a/src/lib/geoip/geoip.c b/src/lib/geoip/geoip.c index 686040613d..f13354dbe1 100644 --- a/src/lib/geoip/geoip.c +++ b/src/lib/geoip/geoip.c @@ -387,7 +387,7 @@ geoip_load_file(sa_family_t family, const char *filename, int severity) * be less than geoip_get_n_countries(). To decode it, call * geoip_get_country_name(). */ -int +STATIC int geoip_get_country_by_ipv4(uint32_t ipaddr) { geoip_ipv4_entry_t *ent; @@ -403,7 +403,7 @@ geoip_get_country_by_ipv4(uint32_t ipaddr) * 0 for the 'unknown country'. The return value will always be less than * geoip_get_n_countries(). To decode it, call geoip_get_country_name(). */ -int +STATIC int geoip_get_country_by_ipv6(const struct in6_addr *addr) { geoip_ipv6_entry_t *ent; diff --git a/src/lib/geoip/geoip.h b/src/lib/geoip/geoip.h index 764ed1d5a5..e68573fd1a 100644 --- a/src/lib/geoip/geoip.h +++ b/src/lib/geoip/geoip.h @@ -21,14 +21,14 @@ #ifdef GEOIP_PRIVATE STATIC int geoip_parse_entry(const char *line, sa_family_t family); STATIC void clear_geoip_db(void); + +STATIC int geoip_get_country_by_ipv4(uint32_t ipaddr); +STATIC int geoip_get_country_by_ipv6(const struct in6_addr *addr); #endif /* defined(GEOIP_PRIVATE) */ struct in6_addr; struct tor_addr_t; -int geoip_get_country_by_ipv4(uint32_t ipaddr); -int geoip_get_country_by_ipv6(const struct in6_addr *addr); - /** A per-country GeoIP record. */ typedef struct geoip_country_t { /** A nul-terminated two-letter country-code. */ diff --git a/src/lib/malloc/malloc.h b/src/lib/malloc/malloc.h index cc031f843a..48a3ac32cf 100644 --- a/src/lib/malloc/malloc.h +++ b/src/lib/malloc/malloc.h @@ -11,6 +11,7 @@ #ifndef TOR_UTIL_MALLOC_H #define TOR_UTIL_MALLOC_H +#include <assert.h> #include <stddef.h> #include <stdlib.h> #include "lib/cc/compat_compiler.h" @@ -45,6 +46,9 @@ void tor_free_(void *mem); #ifdef __GNUC__ #define tor_free(p) STMT_BEGIN \ typeof(&(p)) tor_free__tmpvar = &(p); \ + _Static_assert(!__builtin_types_compatible_p(typeof(*tor_free__tmpvar), \ + struct event *), \ + "use tor_event_free for struct event *"); \ raw_free(*tor_free__tmpvar); \ *tor_free__tmpvar=NULL; \ STMT_END diff --git a/src/lib/math/prob_distr.c b/src/lib/math/prob_distr.c index a57fc1020c..9e60b9f37a 100644 --- a/src/lib/math/prob_distr.c +++ b/src/lib/math/prob_distr.c @@ -54,7 +54,7 @@ #ifndef COCCI /** Declare a function that downcasts from a generic dist struct to the actual - * subtype probablity distribution it represents. */ + * subtype probability distribution it represents. */ #define DECLARE_PROB_DISTR_DOWNCAST_FN(name) \ static inline \ const struct name##_t * \ diff --git a/src/lib/math/stats.h b/src/lib/math/stats.h index 14315a2506..7acc6fa43d 100644 --- a/src/lib/math/stats.h +++ b/src/lib/math/stats.h @@ -25,7 +25,7 @@ n_count_ewma_double(double avg, double value, uint64_t N) /* If the average was not previously computed, return value. * The less than is because we have stupid C warning flags that * prevent exact comparison to 0.0, so we can't do an exact - * check for unitialized double values. Yay pedantry! + * check for uninitialized double values. Yay pedantry! * Love it when it introduces surprising edge case bugs like * this will. */ if (avg < 0.0000002) diff --git a/src/lib/metrics/metrics_common.c b/src/lib/metrics/metrics_common.c index f3f7e22d88..5836a581f1 100644 --- a/src/lib/metrics/metrics_common.c +++ b/src/lib/metrics/metrics_common.c @@ -24,6 +24,8 @@ metrics_type_to_str(const metrics_type_t type) return "counter"; case METRICS_TYPE_GAUGE: return "gauge"; + case METRICS_TYPE_HISTOGRAM: + return "histogram"; default: tor_assert_unreached(); } diff --git a/src/lib/metrics/metrics_common.h b/src/lib/metrics/metrics_common.h index 3644ad3d50..6c8e8bdbdc 100644 --- a/src/lib/metrics/metrics_common.h +++ b/src/lib/metrics/metrics_common.h @@ -10,6 +10,7 @@ #define TOR_LIB_METRICS_METRICS_COMMON_H #include "lib/cc/torint.h" +#include "lib/container/smartlist.h" /** Helper macro that must be used to construct the right namespaced metrics * name. A name is a string so stringify the result. */ @@ -28,8 +29,18 @@ typedef enum { METRICS_TYPE_COUNTER, /* Can go up or down. */ METRICS_TYPE_GAUGE, + /* Cumulative counters for multiple observation buckets. */ + METRICS_TYPE_HISTOGRAM, } metrics_type_t; +typedef struct metrics_histogram_bucket_t { + /* The value of the counter of this bucket. */ + uint64_t value; + /* Technically, this should be a floating point value, but in practice, we + * can make do with integer buckets. */ + int64_t bucket; +} metrics_histogram_bucket_t; + /** Metric counter object (METRICS_TYPE_COUNTER). */ typedef struct metrics_counter_t { uint64_t value; @@ -40,6 +51,18 @@ typedef struct metrics_gauge_t { int64_t value; } metrics_gauge_t; +/** Metric histogram object (METRICS_TYPE_HISTOGRAM). */ +typedef struct metrics_histogram_t { + /* The observation buckets. */ + metrics_histogram_bucket_t *buckets; + /* The number of observation buckets. */ + size_t bucket_count; + /* The sum of all observations */ + int64_t sum; + /* The total number of observations */ + uint64_t count; +} metrics_histogram_t; + const char *metrics_type_to_str(const metrics_type_t type); /* Helpers. */ diff --git a/src/lib/metrics/metrics_store.c b/src/lib/metrics/metrics_store.c index b017e97688..db80ca029b 100644 --- a/src/lib/metrics/metrics_store.c +++ b/src/lib/metrics/metrics_store.c @@ -107,7 +107,9 @@ metrics_store_get_all(const metrics_store_t *store, const char *name) * unique identifier. The help string can be omitted. */ metrics_store_entry_t * metrics_store_add(metrics_store_t *store, metrics_type_t type, - const char *name, const char *help) + const char *name, const char *help, size_t bucket_count, + const int64_t *buckets) + { smartlist_t *entries; metrics_store_entry_t *entry; @@ -120,7 +122,7 @@ metrics_store_add(metrics_store_t *store, metrics_type_t type, entries = smartlist_new(); strmap_set(store->entries, name, entries); } - entry = metrics_store_entry_new(type, name, help); + entry = metrics_store_entry_new(type, name, help, bucket_count, buckets); smartlist_add(entries, entry); return entry; diff --git a/src/lib/metrics/metrics_store.h b/src/lib/metrics/metrics_store.h index d85f484bd6..d06c87303c 100644 --- a/src/lib/metrics/metrics_store.h +++ b/src/lib/metrics/metrics_store.h @@ -26,8 +26,10 @@ metrics_store_t *metrics_store_new(void); /* Modifiers. */ metrics_store_entry_t *metrics_store_add(metrics_store_t *store, - metrics_type_t type, - const char *name, const char *help); + metrics_type_t type, const char *name, + const char *help, size_t bucket_count, + const int64_t *buckets); + void metrics_store_reset(metrics_store_t *store); /* Accessors. */ diff --git a/src/lib/metrics/metrics_store_entry.c b/src/lib/metrics/metrics_store_entry.c index 482ec8d7d9..649fd660c3 100644 --- a/src/lib/metrics/metrics_store_entry.c +++ b/src/lib/metrics/metrics_store_entry.c @@ -6,6 +6,7 @@ * @brief Metrics store entry which contains the gathered data. **/ +#include "metrics_common.h" #define METRICS_STORE_ENTRY_PRIVATE #include <string.h> @@ -22,10 +23,11 @@ * Public API. */ -/** Return newly allocated store entry of type COUNTER. */ +/** Return newly allocated store entry of the specified type. */ metrics_store_entry_t * metrics_store_entry_new(const metrics_type_t type, const char *name, - const char *help) + const char *help, size_t bucket_count, + const int64_t *buckets) { metrics_store_entry_t *entry = tor_malloc_zero(sizeof(*entry)); @@ -38,6 +40,18 @@ metrics_store_entry_new(const metrics_type_t type, const char *name, entry->help = tor_strdup(help); } + if (type == METRICS_TYPE_HISTOGRAM && bucket_count > 0) { + tor_assert(buckets); + + entry->u.histogram.bucket_count = bucket_count; + entry->u.histogram.buckets = + tor_malloc_zero(sizeof(metrics_histogram_bucket_t) * bucket_count); + + for (size_t i = 0; i < bucket_count; ++i) { + entry->u.histogram.buckets[i].bucket = buckets[i]; + } + } + return entry; } @@ -52,6 +66,11 @@ metrics_store_entry_free_(metrics_store_entry_t *entry) smartlist_free(entry->labels); tor_free(entry->name); tor_free(entry->help); + + if (entry->type == METRICS_TYPE_HISTOGRAM) { + tor_free(entry->u.histogram.buckets); + } + tor_free(entry); } @@ -61,6 +80,11 @@ metrics_store_entry_update(metrics_store_entry_t *entry, const int64_t value) { tor_assert(entry); + /* Histogram values are updated using metrics_store_hist_entry_update */ + if (BUG(entry->type == METRICS_TYPE_HISTOGRAM)) { + return; + } + switch (entry->type) { case METRICS_TYPE_COUNTER: /* Counter can ONLY be positive. */ @@ -73,6 +97,43 @@ metrics_store_entry_update(metrics_store_entry_t *entry, const int64_t value) /* Gauge can increment or decrement. And can be positive or negative. */ entry->u.gauge.value += value; break; + case METRICS_TYPE_HISTOGRAM: + tor_assert_unreached(); + } +} + +/** Update a store entry with value for the specified observation obs. + * + * Note: entry **must** be a histogram. */ +void +metrics_store_hist_entry_update(metrics_store_entry_t *entry, + const int64_t value, const int64_t obs) +{ + if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) { + return; + } + + /* Counter can ONLY be positive for histograms. */ + if (BUG(value < 0)) { + return; + } + + /* If we're about to overflow or underflow the sum, reset all counters back + * to 0 before recording the observation. */ + if (PREDICT_UNLIKELY( + (obs > 0 && entry->u.histogram.sum > INT64_MAX - obs) || + (obs < 0 && entry->u.histogram.sum < INT64_MIN - obs))) { + metrics_store_entry_reset(entry); + } + + entry->u.histogram.count += value; + entry->u.histogram.sum += obs; + + for (size_t i = 0; i < entry->u.histogram.bucket_count; ++i) { + metrics_histogram_bucket_t *hb = &entry->u.histogram.buckets[i]; + if (obs <= hb->bucket) { + hb->value += value; + } } } @@ -81,8 +142,22 @@ void metrics_store_entry_reset(metrics_store_entry_t *entry) { tor_assert(entry); - /* Everything back to 0. */ - memset(&entry->u, 0, sizeof(entry->u)); + + switch (entry->type) { + case METRICS_TYPE_COUNTER: FALLTHROUGH; + case METRICS_TYPE_GAUGE: + /* Everything back to 0. */ + memset(&entry->u, 0, sizeof(entry->u)); + break; + case METRICS_TYPE_HISTOGRAM: + for (size_t i = 0; i < entry->u.histogram.bucket_count; ++i) { + metrics_histogram_bucket_t *hb = &entry->u.histogram.buckets[i]; + hb->value = 0; + } + entry->u.histogram.sum = 0; + entry->u.histogram.count = 0; + break; + } } /** Return store entry value. */ @@ -91,6 +166,11 @@ metrics_store_entry_get_value(const metrics_store_entry_t *entry) { tor_assert(entry); + /* Histogram values are accessed using metrics_store_hist_entry_get_value. */ + if (BUG(entry->type == METRICS_TYPE_HISTOGRAM)) { + return 0; + } + switch (entry->type) { case METRICS_TYPE_COUNTER: if (entry->u.counter.value > INT64_MAX) { @@ -99,6 +179,9 @@ metrics_store_entry_get_value(const metrics_store_entry_t *entry) return entry->u.counter.value; case METRICS_TYPE_GAUGE: return entry->u.gauge.value; + case METRICS_TYPE_HISTOGRAM: + tor_assert_unreached(); + return 0; } // LCOV_EXCL_START @@ -106,6 +189,35 @@ metrics_store_entry_get_value(const metrics_store_entry_t *entry) // LCOV_EXCL_STOP } +/** Return store entry value for the specified bucket. + * + * Note: entry **must** be a histogram. */ +uint64_t +metrics_store_hist_entry_get_value(const metrics_store_entry_t *entry, + const int64_t bucket) +{ + tor_assert(entry); + + if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) { + return 0; + } + + for (size_t i = 0; i <= entry->u.histogram.bucket_count; ++i) { + metrics_histogram_bucket_t hb = entry->u.histogram.buckets[i]; + if (bucket == hb.bucket) { + if (hb.value > INT64_MAX) { + return INT64_MAX; + } else { + return hb.value; + } + } + } + + tor_assertf_nonfatal(false, "attempted to get the value of non-existent " + "bucket %" PRId64, bucket); + return 0; +} + /** Add a label into the given entry.*/ void metrics_store_entry_add_label(metrics_store_entry_t *entry, @@ -127,3 +239,60 @@ metrics_store_entry_has_label(const metrics_store_entry_t *entry, return smartlist_contains_string(entry->labels, label); } + +/** Return the first entry that has the given label, or NULL if none + * of the entries have the label. */ +metrics_store_entry_t * +metrics_store_find_entry_with_label(const smartlist_t *entries, + const char *label) +{ + tor_assert(entries); + tor_assert(label); + + SMARTLIST_FOREACH_BEGIN(entries, metrics_store_entry_t *, entry) { + tor_assert(entry); + + if (smartlist_contains_string(entry->labels, label)) { + return entry; + } + } SMARTLIST_FOREACH_END(entry); + + return NULL; +} + +/** Return true iff the specified entry is a histogram. */ +bool +metrics_store_entry_is_histogram(const metrics_store_entry_t *entry) +{ + if (entry->type == METRICS_TYPE_HISTOGRAM) { + return true; + } + + return false; +} + +/** Return the total number of observations for the specified histogram. */ +uint64_t +metrics_store_hist_entry_get_count(const metrics_store_entry_t *entry) +{ + tor_assert(entry); + + if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) { + return 0; + } + + return entry->u.histogram.count; +} + +/** Return the sum of all observations for the specified histogram. */ +int64_t +metrics_store_hist_entry_get_sum(const metrics_store_entry_t *entry) +{ + tor_assert(entry); + + if (BUG(entry->type != METRICS_TYPE_HISTOGRAM)) { + return 0; + } + + return entry->u.histogram.sum; +} diff --git a/src/lib/metrics/metrics_store_entry.h b/src/lib/metrics/metrics_store_entry.h index e4dc7a8b9a..53fa437406 100644 --- a/src/lib/metrics/metrics_store_entry.h +++ b/src/lib/metrics/metrics_store_entry.h @@ -12,6 +12,7 @@ #include "lib/cc/torint.h" #include "lib/metrics/metrics_common.h" +#include "lib/container/smartlist.h" #ifdef METRICS_STORE_ENTRY_PRIVATE @@ -37,6 +38,7 @@ struct metrics_store_entry_t { union { metrics_counter_t counter; metrics_gauge_t gauge; + metrics_histogram_t histogram; } u; }; @@ -47,7 +49,9 @@ typedef struct metrics_store_entry_t metrics_store_entry_t; /* Allocators. */ metrics_store_entry_t *metrics_store_entry_new(const metrics_type_t type, const char *name, - const char *help); + const char *help, + size_t bucket_count, + const int64_t *buckets); void metrics_store_entry_free_(metrics_store_entry_t *entry); #define metrics_store_entry_free(entry) \ @@ -55,8 +59,16 @@ void metrics_store_entry_free_(metrics_store_entry_t *entry); /* Accessors. */ int64_t metrics_store_entry_get_value(const metrics_store_entry_t *entry); +uint64_t metrics_store_hist_entry_get_value(const metrics_store_entry_t *entry, + const int64_t bucket); bool metrics_store_entry_has_label(const metrics_store_entry_t *entry, const char *label); +metrics_store_entry_t *metrics_store_find_entry_with_label( + const smartlist_t *entries, const char *label); +bool metrics_store_entry_is_histogram(const metrics_store_entry_t *entry); +uint64_t metrics_store_hist_entry_get_count( + const metrics_store_entry_t *entry); +int64_t metrics_store_hist_entry_get_sum(const metrics_store_entry_t *entry); /* Modifiers. */ void metrics_store_entry_add_label(metrics_store_entry_t *entry, @@ -64,5 +76,7 @@ void metrics_store_entry_add_label(metrics_store_entry_t *entry, void metrics_store_entry_reset(metrics_store_entry_t *entry); void metrics_store_entry_update(metrics_store_entry_t *entry, const int64_t value); +void metrics_store_hist_entry_update(metrics_store_entry_t *entry, + const int64_t value, const int64_t obs); #endif /* !defined(TOR_LIB_METRICS_METRICS_STORE_ENTRY_H) */ diff --git a/src/lib/metrics/prometheus.c b/src/lib/metrics/prometheus.c index aac23ac92e..2f98f8ebb6 100644 --- a/src/lib/metrics/prometheus.c +++ b/src/lib/metrics/prometheus.c @@ -17,6 +17,8 @@ #include "lib/metrics/prometheus.h" +#include <string.h> + /** Return a static buffer containing all the labels properly formatted * for the output as a string. * @@ -33,13 +35,54 @@ format_labels(smartlist_t *labels) } line = smartlist_join_strings(labels, ",", 0, NULL); - tor_snprintf(buf, sizeof(buf), "{%s}", line); + tor_snprintf(buf, sizeof(buf), "%s", line); end: tor_free(line); return buf; } +/** Write the string representation of the histogram entry to the specified + * buffer. + * + * Note: entry **must** be a histogram. + */ +static void +format_histogram(const metrics_store_entry_t *entry, buf_t *data) +{ + tor_assert(entry->type == METRICS_TYPE_HISTOGRAM); + + const char *labels = format_labels(entry->labels); + + for (size_t i = 0; i < entry->u.histogram.bucket_count; ++i) { + metrics_histogram_bucket_t hb = entry->u.histogram.buckets[i]; + if (strlen(labels) > 0) { + buf_add_printf(data, "%s_bucket{%s,le=\"%.2f\"} %" PRIi64 "\n", + entry->name, labels, (double)hb.bucket, hb.value); + } else { + buf_add_printf(data, "%s_bucket{le=\"%.2f\"} %" PRIi64 "\n", + entry->name, (double)hb.bucket, hb.value); + } + } + + if (strlen(labels) > 0) { + buf_add_printf(data, "%s_bucket{%s,le=\"+Inf\"} %" PRIi64 "\n", + entry->name, labels, + metrics_store_hist_entry_get_count(entry)); + buf_add_printf(data, "%s_sum{%s} %" PRIi64 "\n", entry->name, labels, + metrics_store_hist_entry_get_sum(entry)); + buf_add_printf(data, "%s_count{%s} %" PRIi64 "\n", entry->name, labels, + metrics_store_hist_entry_get_count(entry)); + } else { + buf_add_printf(data, "%s_bucket{le=\"+Inf\"} %" PRIi64 "\n", entry->name, + metrics_store_hist_entry_get_count(entry)); + buf_add_printf(data, "%s_sum %" PRIi64 "\n", entry->name, + metrics_store_hist_entry_get_sum(entry)); + buf_add_printf(data, "%s_count %" PRIi64 "\n", entry->name, + metrics_store_hist_entry_get_count(entry)); + } +} + /** Format the given entry in to the buffer data. */ void prometheus_format_store_entry(const metrics_store_entry_t *entry, buf_t *data, @@ -53,7 +96,26 @@ prometheus_format_store_entry(const metrics_store_entry_t *entry, buf_t *data, 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)); + + switch (entry->type) { + case METRICS_TYPE_COUNTER: FALLTHROUGH; + case METRICS_TYPE_GAUGE: + { + const char *labels = format_labels(entry->labels); + if (strlen(labels) > 0) { + buf_add_printf(data, "%s{%s} %" PRIi64 "\n", entry->name, + labels, + metrics_store_entry_get_value(entry)); + } else { + buf_add_printf(data, "%s %" PRIi64 "\n", entry->name, + metrics_store_entry_get_value(entry)); + } + break; + } + case METRICS_TYPE_HISTOGRAM: + format_histogram(entry, data); + break; + default: + tor_assert_unreached(); + } } diff --git a/src/lib/osinfo/libc.c b/src/lib/osinfo/libc.c index f52dea41aa..f7cfde8642 100644 --- a/src/lib/osinfo/libc.c +++ b/src/lib/osinfo/libc.c @@ -26,11 +26,18 @@ #define STR_IMPL(x) #x #define STR(x) STR_IMPL(x) +#if defined(__BSD_VISIBLE) || defined(__NETBSD_SOURCE) +#include <sys/param.h> +#endif /* defined(__BSD_VISIBLE) || defined(__NETBSD_SOURCE) */ + /** Return the name of the compile time libc. Returns NULL if we * cannot identify the libc. */ const char * tor_libc_get_name(void) { +#if defined(__BSD_VISIBLE) || defined(__NETBSD_SOURCE) + return "BSD"; +#endif /* defined(__BSD_VISIBLE) || defined(__NETBSD_SOURCE) */ #ifdef __GLIBC__ return "Glibc"; #else /* !defined(__GLIBC__) */ @@ -43,6 +50,18 @@ tor_libc_get_name(void) const char * tor_libc_get_version_str(void) { +#ifdef __DragonFly_version + return STR(__DragonFly_version); +#endif +#ifdef __FreeBSD__ + return STR(__FreeBSD_version); +#endif +#ifdef __NetBSD_Version__ + return STR(__NetBSD_Version__); +#endif +#ifdef OpenBSD + return STR(OpenBSD); +#endif #ifdef CHECK_LIBC_VERSION const char *version = gnu_get_libc_version(); if (version == NULL) diff --git a/src/lib/process/process_win32.c b/src/lib/process/process_win32.c index dfcb17a480..6458f93752 100644 --- a/src/lib/process/process_win32.c +++ b/src/lib/process/process_win32.c @@ -888,7 +888,7 @@ process_win32_read_from_handle(process_win32_handle_t *handle, /* Check if we have been asked to read from a handle that have already told * us that we have reached the end of the file. */ - if (BUG(handle->reached_eof)) + if (handle->reached_eof) return 0; /* This cast should be safe since our buffer can be at maximum up to diff --git a/src/lib/sandbox/sandbox.c b/src/lib/sandbox/sandbox.c index 5dace3a8a2..8ac07abfc9 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. @@ -439,7 +441,14 @@ sb_mmap2(scmp_filter_ctx ctx, sandbox_cfg_t *filter) rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2), SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE), - SCMP_CMP(3, SCMP_CMP_EQ,MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK)); + SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK)); + if (rc) { + return rc; + } + + rc = seccomp_rule_add_2(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap2), + SCMP_CMP(2, SCMP_CMP_EQ, PROT_NONE), + SCMP_CMP(3, SCMP_CMP_EQ, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK)); if (rc) { return rc; } @@ -520,14 +529,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 <b>use_openat</b> is true, * we're using a libc that remaps all the opens into openats. */ static int @@ -535,7 +536,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), @@ -616,6 +617,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) @@ -668,6 +695,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. @@ -700,6 +753,39 @@ sb_rename(scmp_filter_ctx ctx, sandbox_cfg_t *filter) } /** + * 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. */ @@ -716,7 +802,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)); @@ -1328,7 +1414,9 @@ static sandbox_filter_func_t filter_func[] = { #else sb_chown, #endif + sb_fchownat, sb_chmod, + sb_fchmodat, sb_open, sb_openat, sb_opendir, @@ -1336,6 +1424,7 @@ static sandbox_filter_func_t filter_func[] = { sb_ptrace, #endif sb_rename, + sb_renameat, #ifdef __NR_fcntl64 sb_fcntl64, #endif @@ -1603,10 +1692,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 @@ -1644,7 +1747,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; @@ -1670,7 +1773,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; diff --git a/src/lib/time/compat_time.c b/src/lib/time/compat_time.c index eb716259c4..57a1e45b84 100644 --- a/src/lib/time/compat_time.c +++ b/src/lib/time/compat_time.c @@ -812,6 +812,12 @@ monotime_absolute_msec(void) return monotime_absolute_nsec() / ONE_MILLION; } +uint64_t +monotime_absolute_sec(void) +{ + return monotime_absolute_nsec() / ONE_BILLION; +} + #ifdef MONOTIME_COARSE_FN_IS_DIFFERENT uint64_t monotime_coarse_absolute_nsec(void) @@ -836,6 +842,17 @@ monotime_coarse_absolute_msec(void) { return monotime_coarse_absolute_nsec() / ONE_MILLION; } + +uint64_t +monotime_coarse_absolute_sec(void) +{ + /* Note: Right now I'm not too concerned about 64-bit division, but if this + * ever becomes a hotspot we need to optimize, we can modify this to grab + * tv_sec directly from CLOCK_MONOTONIC_COARSE on linux at least. Right now + * I'm choosing to make this simpler and easier to test, but this + * optimization is available easily if we need it. */ + return monotime_coarse_absolute_nsec() / ONE_BILLION; +} #else /* !defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ #define initialized_at_coarse initialized_at #endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ diff --git a/src/lib/time/compat_time.h b/src/lib/time/compat_time.h index da96023894..eaf676ae84 100644 --- a/src/lib/time/compat_time.h +++ b/src/lib/time/compat_time.h @@ -89,6 +89,13 @@ * A: In general, regular monotime uses something that requires a system call. * On platforms where system calls are cheap, you win! Otherwise, you lose. * + * XXX: This hasn't been true for a long time. Expect both coarse and fine + * monotime won't require a syscall, but they will have different + * costs in terms of low-level synchronization inside the vDSO and + * the hardware. The basic guidelines here still apply, but we aren't + * really worrying about system calls any more, and the integer div + * concerns are becoming nearly unimportant as well. + * * On Windows, monotonic time uses QuereyPerformanceCounter. Storing * monotime_t costs 8 bytes. * @@ -232,7 +239,12 @@ MOCK_DECL(uint64_t, monotime_absolute_usec,(void)); * Fractional units are truncated, not rounded. */ uint64_t monotime_absolute_msec(void); - +/** + * Return the number of seconds since the timer system was initialized. + * The returned value may be equal to zero. + * Fractional units are truncated, not rounded. + */ +uint64_t monotime_absolute_sec(void); /** * Set <b>out</b> to zero. */ @@ -259,11 +271,13 @@ void monotime_coarse_get(monotime_coarse_t *out); uint64_t monotime_coarse_absolute_nsec(void); uint64_t monotime_coarse_absolute_usec(void); uint64_t monotime_coarse_absolute_msec(void); +uint64_t monotime_coarse_absolute_sec(void); #else /* !defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ #define monotime_coarse_get monotime_get #define monotime_coarse_absolute_nsec monotime_absolute_nsec #define monotime_coarse_absolute_usec monotime_absolute_usec #define monotime_coarse_absolute_msec monotime_absolute_msec +#define monotime_coarse_absolute_sec monotime_absolute_sec #endif /* defined(MONOTIME_COARSE_FN_IS_DIFFERENT) */ /** diff --git a/src/lib/tls/tortls_openssl.c b/src/lib/tls/tortls_openssl.c index 77de2d6a11..c0a89ac272 100644 --- a/src/lib/tls/tortls_openssl.c +++ b/src/lib/tls/tortls_openssl.c @@ -340,8 +340,10 @@ tor_tls_init(void) SSL_load_error_strings(); #endif /* defined(OPENSSL_1_1_API) */ -#if (SIZEOF_VOID_P >= 8 && \ - OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1)) +#if (SIZEOF_VOID_P >= 8 && \ + OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,0,1) && \ + (!defined(LIBRESSL_VERSION_NUMBER) || \ + LIBRESSL_VERSION_NUMBER < 0x3080000fL)) long version = tor_OpenSSL_version_num(); /* LCOV_EXCL_START : we can't test these lines on the same machine */ @@ -1734,8 +1736,7 @@ tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out, * issue 7712. */ openssl_bug_7712_is_present = 1; log_warn(LD_GENERAL, "Detected OpenSSL bug 7712: disabling TLS 1.3 on " - "future connections. A fix is expected to appear in OpenSSL " - "1.1.1b."); + "future connections."); } } if (openssl_bug_7712_is_present) |