This is an automated email from the git hooks/post-receive script.
dgoulet pushed a change to branch main in repository tor.
from 9976da9367 Merge branch 'tor-gitlab/mr/709' new c71b6a14a3 equix: avoid a coverity warning in hashx_alloc() new a3ff3155c2 test_crypto: avoid memory leak in some hashx test failures new 23f4a28f97 token_bucket_ctr: replace 32-bit wallclock time with monotime new a2ec9a1199 Merge branch 'tor-gitlab/mr/711'
The 4 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "add" were already present in the repository and have only been added to this reference.
Summary of changes: src/core/or/dos.c | 6 ++- src/ext/equix/hashx/src/context.c | 1 + src/feature/hs/hs_circuit.c | 3 +- src/feature/hs/hs_dos.c | 5 +- src/feature/hs/hs_intropoint.c | 3 +- src/feature/hs/hs_service.c | 3 +- src/lib/evloop/token_bucket.c | 111 +++++++++++++++++++------------------- src/lib/evloop/token_bucket.h | 12 ++--- src/lib/time/compat_time.c | 17 ++++++ src/lib/time/compat_time.h | 16 +++++- src/test/test_bwmgt.c | 24 ++++++++- src/test/test_crypto.c | 9 ++-- src/test/test_dos.c | 15 ++++-- src/test/test_hs_dos.c | 18 ++++--- src/test/test_hs_intropoint.c | 3 +- 15 files changed, 160 insertions(+), 86 deletions(-)
This is an automated email from the git hooks/post-receive script.
dgoulet pushed a commit to branch main in repository tor.
commit c71b6a14a391769261a08e96d0a1d90b5d1c9e11 Author: Micah Elizabeth Scott beth@torproject.org AuthorDate: Thu May 11 11:10:15 2023 -0700
equix: avoid a coverity warning in hashx_alloc()
This addresses one of the warnings in issue #40792. As far as I can tell this is a false positive, since the use of "ctx->type" in hashx_free() can only be hit after the unioned code/program pointer is non-NULL. It's no big deal to zero this value explicitly to silence the warning though.
Signed-off-by: Micah Elizabeth Scott beth@torproject.org --- src/ext/equix/hashx/src/context.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/src/ext/equix/hashx/src/context.c b/src/ext/equix/hashx/src/context.c index de2144d46c..8548fb7ffa 100644 --- a/src/ext/equix/hashx/src/context.c +++ b/src/ext/equix/hashx/src/context.c @@ -41,6 +41,7 @@ hashx_ctx* hashx_alloc(hashx_type type) { goto failure; } ctx->code = NULL; + ctx->type = 0; if (type & HASHX_COMPILED) { if (!hashx_compiler_init(ctx)) { goto failure;
This is an automated email from the git hooks/post-receive script.
dgoulet pushed a commit to branch main in repository tor.
commit a3ff3155c22e7cf093667c6c32166a8f9c77a79a Author: Micah Elizabeth Scott beth@torproject.org AuthorDate: Thu May 11 11:17:43 2023 -0700
test_crypto: avoid memory leak in some hashx test failures
This should fix one of the warnings in issue #40792.
I was sloppy with freeing memory in the failure cases for test_crypto_hashx. ASAN didn't notice but coverity did. Okay, I'll eat my vegetables and put hashx_ctx's deinit in an upper scope and use 'goto done' correctly like a properly diligent C programmer.
Signed-off-by: Micah Elizabeth Scott beth@torproject.org --- src/test/test_crypto.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index 82a9d5d642..926d4178c1 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -2990,6 +2990,7 @@ test_crypto_hashx(void *arg)
const unsigned num_vectors = sizeof vectors / sizeof vectors[0]; const unsigned num_variations = sizeof variations / sizeof variations[0]; + hashx_ctx *ctx = NULL;
for (unsigned vec_i = 0; vec_i < num_vectors; vec_i++) { const char *seed_literal = vectors[vec_i].seed_literal; @@ -3008,7 +3009,9 @@ test_crypto_hashx(void *arg) for (unsigned vari_i = 0; vari_i < num_variations; vari_i++) { uint8_t out_actual[HASHX_SIZE] = { 0 };
- hashx_ctx *ctx = hashx_alloc(variations[vari_i].type); + hashx_free(ctx); + ctx = hashx_alloc(variations[vari_i].type); + tt_ptr_op(ctx, OP_NE, NULL); tt_ptr_op(ctx, OP_NE, HASHX_NOTSUPP); retval = hashx_make(ctx, seed_literal, seed_len); @@ -3017,13 +3020,11 @@ test_crypto_hashx(void *arg) memset(out_actual, 0xa5, sizeof out_actual); hashx_exec(ctx, hash_input, out_actual); tt_mem_op(out_actual, OP_EQ, out_expected, sizeof out_actual); - - hashx_free(ctx); } }
done: - ; + hashx_free(ctx); }
/* We want the likelihood that the random buffer exhibits any regular pattern
This is an automated email from the git hooks/post-receive script.
dgoulet pushed a commit to branch main in repository tor.
commit 23f4a28f9755a228ab295d5358298f1a72f8aff1 Author: Micah Elizabeth Scott beth@torproject.org AuthorDate: Tue May 16 16:28:26 2023 -0700
token_bucket_ctr: replace 32-bit wallclock time with monotime
This started as a response to ticket #40792 where Coverity is complaining about a potential year 2038 bug where we cast time_t from approx_time() to uint32_t for use in token_bucket_ctr.
There was a larger can of worms though, since token_bucket really doesn't want to be using wallclock time here. I audited the call sites for approx_time() and changed any that used a 32-bit cast or made inappropriate use of wallclock time. Things like certificate lifetime, consensus intervals, etc. need wallclock time. Measurements of rates over time, however, are better served with a monotonic timer that does not try and sync with wallclock ever.
Looking closer at token_bucket, its design is a bit odd because it was initially intended for use with tick units but later forked into token_bucket_rw which uses ticks to count bytes per second, and token_bucket_ctr which uses seconds to count slower events. The rates represented by either token bucket can't be lower than 1 per second, so the slower timer in 'ctr' is necessary to represent the slower rates of things like connections or introduction packets or rendezvous attempts.
I considered modifying token_bucket to use 64-bit timestamps overall instead of 32-bit, but that seemed like an unnecessarily invasive change that would grant some peace of mind but probably not help much. I was more interested in removing the dependency on wallclock time. The token_bucket_rw timer already uses monotonic time. This patch converts token_bucket_ctr to use monotonic time as well. It introduces a new monotime_coarse_absolute_sec(), which is currently the same as nsec divided by a billion but could be optimized easily if we ever need to.
This patch also might fix a rollover bug.. I haven't tested this extensively but I don't think the previous version of the rollover code on either token bucket was correct, and I would expect it to get stuck after the first rollover.
Signed-off-by: Micah Elizabeth Scott beth@torproject.org --- src/core/or/dos.c | 6 ++- src/feature/hs/hs_circuit.c | 3 +- src/feature/hs/hs_dos.c | 5 +- src/feature/hs/hs_intropoint.c | 3 +- src/feature/hs/hs_service.c | 3 +- src/lib/evloop/token_bucket.c | 111 ++++++++++++++++++++--------------------- src/lib/evloop/token_bucket.h | 12 ++--- src/lib/time/compat_time.c | 17 +++++++ src/lib/time/compat_time.h | 16 +++++- src/test/test_bwmgt.c | 24 ++++++++- src/test/test_dos.c | 15 ++++-- src/test/test_hs_dos.c | 18 ++++--- src/test/test_hs_intropoint.c | 3 +- 13 files changed, 154 insertions(+), 82 deletions(-)
diff --git a/src/core/or/dos.c b/src/core/or/dos.c index 11a0edcc6a..8e0fe9e641 100644 --- a/src/core/or/dos.c +++ b/src/core/or/dos.c @@ -21,6 +21,7 @@ #include "feature/relay/routermode.h" #include "feature/stats/geoip_stats.h" #include "lib/crypt_ops/crypto_rand.h" +#include "lib/time/compat_time.h"
#include "core/or/dos.h" #include "core/or/dos_sys.h" @@ -528,7 +529,8 @@ conn_update_on_connect(conn_client_stats_t *stats, const tor_addr_t *addr) stats->concurrent_count++;
/* Refill connect connection count. */ - token_bucket_ctr_refill(&stats->connect_count, (uint32_t) approx_time()); + token_bucket_ctr_refill(&stats->connect_count, + (uint32_t) monotime_coarse_absolute_sec());
/* Decrement counter for this new connection. */ if (token_bucket_ctr_get(&stats->connect_count) > 0) { @@ -808,7 +810,7 @@ dos_geoip_entry_init(clientmap_entry_t *geoip_ent) * can be enabled at runtime and these counters need to be valid. */ token_bucket_ctr_init(&geoip_ent->dos_stats.conn_stats.connect_count, dos_conn_connect_rate, dos_conn_connect_burst, - (uint32_t) approx_time()); + (uint32_t) monotime_coarse_absolute_sec()); }
/** Note that the given channel has sent outbound the maximum amount of cell diff --git a/src/feature/hs/hs_circuit.c b/src/feature/hs/hs_circuit.c index 4c27f417c5..4904f3ddf9 100644 --- a/src/feature/hs/hs_circuit.c +++ b/src/feature/hs/hs_circuit.c @@ -35,6 +35,7 @@ #include "lib/crypt_ops/crypto_dh.h" #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" +#include "lib/time/compat_time.h"
/* Trunnel. */ #include "trunnel/ed25519_cert.h" @@ -794,7 +795,7 @@ handle_rend_pqueue_cb(mainloop_event_t *ev, void *arg)
if (pow_state->using_pqueue_bucket) { token_bucket_ctr_refill(&pow_state->pqueue_bucket, - (uint32_t) approx_time()); + (uint32_t) monotime_coarse_absolute_sec());
if (token_bucket_ctr_get(&pow_state->pqueue_bucket) > 0) { token_bucket_ctr_dec(&pow_state->pqueue_bucket, 1); diff --git a/src/feature/hs/hs_dos.c b/src/feature/hs/hs_dos.c index 6323dbeeac..80ad3b1daa 100644 --- a/src/feature/hs/hs_dos.c +++ b/src/feature/hs/hs_dos.c @@ -28,6 +28,7 @@ #include "feature/relay/routermode.h"
#include "lib/evloop/token_bucket.h" +#include "lib/time/compat_time.h"
#include "feature/hs/hs_dos.h"
@@ -143,7 +144,7 @@ hs_dos_setup_default_intro2_defenses(or_circuit_t *circ) token_bucket_ctr_init(&circ->introduce2_bucket, consensus_param_introduce_rate_per_sec, consensus_param_introduce_burst_per_sec, - (uint32_t) approx_time()); + (uint32_t) monotime_coarse_absolute_sec()); }
/** Called when the consensus has changed. We might have new consensus @@ -188,7 +189,7 @@ hs_dos_can_send_intro2(or_circuit_t *s_intro_circ)
/* Refill INTRODUCE2 bucket. */ token_bucket_ctr_refill(&s_intro_circ->introduce2_bucket, - (uint32_t) approx_time()); + (uint32_t) monotime_coarse_absolute_sec());
/* Decrement the bucket for this valid INTRODUCE1 cell we just got. Don't * underflow else we end up with a too big of a bucket. */ diff --git a/src/feature/hs/hs_intropoint.c b/src/feature/hs/hs_intropoint.c index 0a656b78dd..52bd0cd499 100644 --- a/src/feature/hs/hs_intropoint.c +++ b/src/feature/hs/hs_intropoint.c @@ -17,6 +17,7 @@ #include "feature/rend/rendmid.h" #include "feature/stats/rephist.h" #include "lib/crypt_ops/crypto_format.h" +#include "lib/time/compat_time.h"
/* Trunnel */ #include "trunnel/ed25519_cert.h" @@ -316,7 +317,7 @@ handle_establish_intro_cell_dos_extension( token_bucket_ctr_init(&circ->introduce2_bucket, (uint32_t) intro2_rate_per_sec, (uint32_t) intro2_burst_per_sec, - (uint32_t) approx_time()); + (uint32_t) monotime_coarse_absolute_sec()); log_info(LD_REND, "Intro point DoS defenses enabled. Rate is %" PRIu64 " and Burst is %" PRIu64, intro2_rate_per_sec, intro2_burst_per_sec); diff --git a/src/feature/hs/hs_service.c b/src/feature/hs/hs_service.c index 3ef2a9120c..777cc85fea 100644 --- a/src/feature/hs/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -34,6 +34,7 @@ #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_util.h" #include "lib/time/tvdiff.h" +#include "lib/time/compat_time.h"
#include "feature/hs/hs_circuit.h" #include "feature/hs/hs_common.h" @@ -290,7 +291,7 @@ initialize_pow_defenses(hs_service_t *service) token_bucket_ctr_init(&pow_state->pqueue_bucket, service->config.pow_queue_rate, service->config.pow_queue_burst, - (uint32_t) approx_time()); + (uint32_t) monotime_coarse_absolute_sec());
pow_state->pqueue_low_level = MAX(8, service->config.pow_queue_rate / 4); pow_state->pqueue_high_level = 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/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/test/test_bwmgt.c b/src/test/test_bwmgt.c index a034c369d1..51ad8be59f 100644 --- a/src/test/test_bwmgt.c +++ b/src/test/test_bwmgt.c @@ -243,10 +243,30 @@ test_bwmgt_token_buf_refill(void *arg) tt_int_op(b.read_bucket.bucket, OP_GT, 8*KB-400); tt_int_op(b.read_bucket.bucket, OP_LT, 8*KB+400);
- // A ridiculous amount of time passes. - tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, INT32_MAX)); + /* A large amount of time passes, but less than the threshold at which + * we start detecting an assumed rollover event. This might be about 20 + * days on a system with stamp units equal to 1ms. */ + uint32_t ts_stamp = START_TS + UINT32_MAX / 5; + tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, ts_stamp)); tt_int_op(b.read_bucket.bucket, OP_EQ, b.cfg.burst);
+ /* Fully empty the bucket and make sure it's filling once again */ + token_bucket_rw_dec_read(&b, b.cfg.burst); + tt_int_op(b.read_bucket.bucket, OP_EQ, 0); + tt_int_op(1, OP_EQ, token_bucket_rw_refill(&b, ts_stamp += BW_SEC)); + tt_int_op(b.read_bucket.bucket, OP_GT, 16*KB - 300); + tt_int_op(b.read_bucket.bucket, OP_LT, 16*KB + 300); + + /* An even larger amount of time passes, which we take to be a 32-bit + * rollover event. The individual update is ignored, but the timestamp + * is still updated and the very next update should be accounted properly. */ + tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, ts_stamp += UINT32_MAX/2)); + tt_int_op(b.read_bucket.bucket, OP_GT, 16*KB - 600); + tt_int_op(b.read_bucket.bucket, OP_LT, 16*KB + 600); + tt_int_op(0, OP_EQ, token_bucket_rw_refill(&b, ts_stamp += BW_SEC)); + tt_int_op(b.read_bucket.bucket, OP_GT, 32*KB - 600); + tt_int_op(b.read_bucket.bucket, OP_LT, 32*KB + 600); + done: ; } diff --git a/src/test/test_dos.c b/src/test/test_dos.c index a34420024f..8c9ddfcbe5 100644 --- a/src/test/test_dos.c +++ b/src/test/test_dos.c @@ -9,6 +9,7 @@ #include "core/or/dos.h" #include "core/or/circuitlist.h" #include "lib/crypt_ops/crypto_rand.h" +#include "lib/time/compat_time.h" #include "feature/stats/geoip_stats.h" #include "core/or/channel.h" #include "feature/nodelist/microdesc.h" @@ -23,6 +24,8 @@ #include "test/test.h" #include "test/log_test_helpers.h"
+static const uint64_t BILLION = 1000000000; + static networkstatus_t *dummy_ns = NULL; static networkstatus_t * mock_networkstatus_get_latest_consensus(void) @@ -58,14 +61,18 @@ mock_enable_dos_protection(const networkstatus_t *ns) static void test_dos_conn_creation(void *arg) { + uint64_t monotime_now = 0xfffffffe; + (void) arg;
+ monotime_enable_test_mocking(); + monotime_coarse_set_mock_time_nsec(monotime_now); MOCK(get_param_cc_enabled, mock_enable_dos_protection); MOCK(get_param_conn_enabled, mock_enable_dos_protection);
/* Initialize test data */ or_connection_t or_conn; - time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */ + time_t wallclock_now = 1281533250; /* 2010-08-11 13:27:30 UTC */ tt_int_op(AF_INET,OP_EQ, tor_addr_parse(&TO_CONN(&or_conn)->addr, "18.0.0.1")); tor_addr_t *addr = &TO_CONN(&or_conn)->addr; @@ -75,13 +82,14 @@ test_dos_conn_creation(void *arg) uint32_t max_concurrent_conns = get_param_conn_max_concurrent_count(NULL);
/* Introduce new client */ - geoip_note_client_seen(GEOIP_CLIENT_CONNECT, addr, NULL, now); + geoip_note_client_seen(GEOIP_CLIENT_CONNECT, addr, NULL, wallclock_now); { /* Register many conns from this client but not enough to get it blocked */ unsigned int i; for (i = 0; i < max_concurrent_conns; i++) { /* Don't trigger the connect() rate limitation so advance the clock 1 * second for each connection. */ - update_approx_time(++now); + monotime_coarse_set_mock_time_nsec(monotime_now += BILLION); + update_approx_time(++wallclock_now); dos_new_client_conn(&or_conn, NULL); } } @@ -107,6 +115,7 @@ test_dos_conn_creation(void *arg)
done: dos_free_all(); + monotime_disable_test_mocking(); }
/** Helper mock: Place a fake IP addr for this channel in <b>addr_out</b> */ diff --git a/src/test/test_hs_dos.c b/src/test/test_hs_dos.c index 70f2ef412f..81410f7b9b 100644 --- a/src/test/test_hs_dos.c +++ b/src/test/test_hs_dos.c @@ -16,6 +16,7 @@ #include "test/log_test_helpers.h"
#include "app/config/config.h" +#include "lib/time/compat_time.h"
#include "core/or/circuitlist.h" #include "core/or/circuituse.h" @@ -45,7 +46,8 @@ free_mock_consensus(void) static void test_can_send_intro2(void *arg) { - uint32_t now = (uint32_t) approx_time(); + static const uint64_t BILLION = 1000000000; + uint64_t now = 12345; or_circuit_t *or_circ = NULL;
(void) arg; @@ -55,6 +57,8 @@ test_can_send_intro2(void *arg)
get_options_mutable()->ORPort_set = 1; setup_mock_consensus(); + monotime_enable_test_mocking(); + monotime_coarse_set_mock_time_nsec(now);
or_circ = or_circuit_new(1, NULL);
@@ -68,7 +72,7 @@ test_can_send_intro2(void *arg)
/* Simulate that 10 cells have arrived in 1 second. There should be no * refill since the bucket is already at maximum on the first cell. */ - update_approx_time(++now); + monotime_coarse_set_mock_time_nsec(now += BILLION); for (int i = 0; i < 10; i++) { tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ)); } @@ -76,7 +80,7 @@ test_can_send_intro2(void *arg) get_intro2_burst_consensus_param(NULL) - 10);
/* Fully refill the bucket minus 1 cell. */ - update_approx_time(++now); + monotime_coarse_set_mock_time_nsec(now += BILLION); tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ)); tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, get_intro2_burst_consensus_param(NULL) - 1); @@ -84,7 +88,7 @@ test_can_send_intro2(void *arg) /* Receive an INTRODUCE2 at each second. We should have the bucket full * since at every second it gets refilled. */ for (int i = 0; i < 10; i++) { - update_approx_time(++now); + monotime_coarse_set_mock_time_nsec(now += BILLION); tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ)); } /* Last check if we can send the cell decrements the bucket so minus 1. */ @@ -92,7 +96,8 @@ test_can_send_intro2(void *arg) get_intro2_burst_consensus_param(NULL) - 1);
/* Manually reset bucket for next test. */ - token_bucket_ctr_reset(&or_circ->introduce2_bucket, now); + token_bucket_ctr_reset(&or_circ->introduce2_bucket, + (uint32_t) monotime_coarse_absolute_sec()); tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, get_intro2_burst_consensus_param(NULL));
@@ -115,7 +120,7 @@ test_can_send_intro2(void *arg) }
/* One second has passed, we should have the rate minus 1 cell added. */ - update_approx_time(++now); + monotime_coarse_set_mock_time_nsec(now += BILLION); tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ)); tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, get_intro2_rate_consensus_param(NULL) - 1); @@ -125,6 +130,7 @@ test_can_send_intro2(void *arg)
hs_free_all(); free_mock_consensus(); + monotime_disable_test_mocking(); }
static void diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c index cbcdeade92..82b7ec029d 100644 --- a/src/test/test_hs_intropoint.c +++ b/src/test/test_hs_intropoint.c @@ -14,6 +14,7 @@ #include "test/test.h" #include "test/log_test_helpers.h" #include "lib/crypt_ops/crypto_rand.h" +#include "lib/time/compat_time.h"
#include "core/or/or.h" #include "core/or/channel.h" @@ -127,7 +128,7 @@ helper_create_intro_circuit(void) tt_assert(circ); circuit_change_purpose(TO_CIRCUIT(circ), CIRCUIT_PURPOSE_OR); token_bucket_ctr_init(&circ->introduce2_bucket, 100, 100, - (uint32_t) approx_time()); + (uint32_t) monotime_coarse_absolute_sec()); done: return circ; }
This is an automated email from the git hooks/post-receive script.
dgoulet pushed a commit to branch main in repository tor.
commit a2ec9a1199dbcad9e7ffada3e324c8cb81c8a192 Merge: 9976da9367 23f4a28f97 Author: David Goulet dgoulet@torproject.org AuthorDate: Wed May 24 11:45:40 2023 -0400
Merge branch 'tor-gitlab/mr/711'
src/core/or/dos.c | 6 ++- src/ext/equix/hashx/src/context.c | 1 + src/feature/hs/hs_circuit.c | 3 +- src/feature/hs/hs_dos.c | 5 +- src/feature/hs/hs_intropoint.c | 3 +- src/feature/hs/hs_service.c | 3 +- src/lib/evloop/token_bucket.c | 111 +++++++++++++++++++------------------- src/lib/evloop/token_bucket.h | 12 ++--- src/lib/time/compat_time.c | 17 ++++++ src/lib/time/compat_time.h | 16 +++++- src/test/test_bwmgt.c | 24 ++++++++- src/test/test_crypto.c | 9 ++-- src/test/test_dos.c | 15 ++++-- src/test/test_hs_dos.c | 18 ++++--- src/test/test_hs_intropoint.c | 3 +- 15 files changed, 160 insertions(+), 86 deletions(-)
tor-commits@lists.torproject.org