summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/crypt_ops/compat_openssl.h22
-rw-r--r--src/lib/crypt_ops/crypto_openssl_mgt.h3
-rw-r--r--src/lib/crypt_ops/crypto_rsa_openssl.c8
-rw-r--r--src/lib/dispatch/dispatch_cfg_st.h4
-rw-r--r--src/lib/evloop/compat_libevent.c2
-rw-r--r--src/lib/evloop/token_bucket.c111
-rw-r--r--src/lib/evloop/token_bucket.h12
-rw-r--r--src/lib/evloop/workqueue.c5
-rw-r--r--src/lib/geoip/geoip.c4
-rw-r--r--src/lib/geoip/geoip.h6
-rw-r--r--src/lib/malloc/malloc.h4
-rw-r--r--src/lib/math/prob_distr.c2
-rw-r--r--src/lib/math/stats.h2
-rw-r--r--src/lib/metrics/metrics_common.c2
-rw-r--r--src/lib/metrics/metrics_common.h23
-rw-r--r--src/lib/metrics/metrics_store.c6
-rw-r--r--src/lib/metrics/metrics_store.h6
-rw-r--r--src/lib/metrics/metrics_store_entry.c177
-rw-r--r--src/lib/metrics/metrics_store_entry.h16
-rw-r--r--src/lib/metrics/prometheus.c70
-rw-r--r--src/lib/osinfo/libc.c19
-rw-r--r--src/lib/process/process_win32.c2
-rw-r--r--src/lib/sandbox/sandbox.c137
-rw-r--r--src/lib/time/compat_time.c17
-rw-r--r--src/lib/time/compat_time.h16
-rw-r--r--src/lib/tls/tortls_openssl.c9
26 files changed, 561 insertions, 124 deletions
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)