소스 검색

Merge remote-tracking branch 'tor-github/pr/819'

teor 5 년 전
부모
커밋
15900ab70f

+ 8 - 0
changes/bug28636

@@ -0,0 +1,8 @@
+  o Minor bugfixes (circuit padding):
+    - The circuit padding subsystem does not schedule padding if dormant mode
+      is enabled. Fixes bug 28636; bugfix on 0.4.0.1-alpha.
+
+  o Minor feature (circuit padding):
+    - We now use a fast RNG when scheduling circuit padding. Part of ticket
+      28636.
+

+ 4 - 4
src/core/or/circuit_st.h

@@ -13,7 +13,7 @@
 
 struct hs_token_t;
 struct circpad_machine_spec_t;
-struct circpad_machine_state_t;
+struct circpad_machine_runtime_t;
 
 /** Number of padding state machines on a circuit. */
 #define CIRCPAD_MAX_MACHINES (2)
@@ -187,8 +187,8 @@ struct circuit_t {
    *  and we can have up to CIRCPAD_MAX_MACHINES such machines. */
   const struct circpad_machine_spec_t *padding_machine[CIRCPAD_MAX_MACHINES];
 
-  /** Adaptive Padding machine info for above machines. This is the
-   *  per-circuit mutable information, such as the current state and
+  /** Adaptive Padding machine runtime info for above machines. This is
+   *  the per-circuit mutable information, such as the current state and
    *  histogram token counts. Some of it is optional (aka NULL).
    *  If a machine is being shut down, these indexes can be NULL
    *  without the corresponding padding_machine being NULL, while we
@@ -196,7 +196,7 @@ struct circuit_t {
    *
    *  Each element of this array corresponds to a different padding machine,
    *  and we can have up to CIRCPAD_MAX_MACHINES such machines. */
-  struct circpad_machine_state_t *padding_info[CIRCPAD_MAX_MACHINES];
+  struct circpad_machine_runtime_t *padding_info[CIRCPAD_MAX_MACHINES];
 };
 
 #endif

+ 45 - 37
src/core/or/circuitpadding.c

@@ -23,7 +23,7 @@
  * As specified by prop#254, clients can negotiate padding with relays by using
  * PADDING_NEGOTIATE cells. After successful padding negotiation, padding
  * machines are assigned to the circuit in their mutable form as a
- * circpad_machine_state_t.
+ * circpad_machine_runtime_t.
  *
  * Each state of a padding state machine can be either:
  * - A histogram that specifies inter-arrival padding delays.
@@ -48,6 +48,7 @@
 #include "core/or/circuitpadding.h"
 #include "core/or/circuitlist.h"
 #include "core/or/circuituse.h"
+#include "core/mainloop/netstatus.h"
 #include "core/or/relay.h"
 #include "feature/stats/rephist.h"
 #include "feature/nodelist/networkstatus.h"
@@ -187,11 +188,11 @@ circpad_circuit_free_all_machineinfos(circuit_t *circ)
 /**
  * Allocate a new mutable machineinfo structure.
  */
-STATIC circpad_machine_state_t *
+STATIC circpad_machine_runtime_t *
 circpad_circuit_machineinfo_new(circuit_t *on_circ, int machine_index)
 {
-  circpad_machine_state_t *mi =
-    tor_malloc_zero(sizeof(circpad_machine_state_t));
+  circpad_machine_runtime_t *mi =
+    tor_malloc_zero(sizeof(circpad_machine_runtime_t));
   mi->machine_index = machine_index;
   mi->on_circ = on_circ;
 
@@ -206,7 +207,7 @@ circpad_circuit_machineinfo_new(circuit_t *on_circ, int machine_index)
  * invalid state.
  */
 STATIC const circpad_state_t *
-circpad_machine_current_state(const circpad_machine_state_t *mi)
+circpad_machine_current_state(const circpad_machine_runtime_t *mi)
 {
   const circpad_machine_spec_t *machine = CIRCPAD_GET_MACHINE(mi);
 
@@ -233,7 +234,7 @@ circpad_machine_current_state(const circpad_machine_state_t *mi)
  * CIRCPAD_DELAY_INFINITE is returned.
  */
 STATIC circpad_delay_t
-circpad_histogram_bin_to_usec(const circpad_machine_state_t *mi,
+circpad_histogram_bin_to_usec(const circpad_machine_runtime_t *mi,
                               circpad_hist_index_t bin)
 {
   const circpad_state_t *state = circpad_machine_current_state(mi);
@@ -264,7 +265,7 @@ circpad_histogram_bin_to_usec(const circpad_machine_state_t *mi,
  * (The upper bound is included in the bin.)
  */
 STATIC circpad_delay_t
-histogram_get_bin_upper_bound(const circpad_machine_state_t *mi,
+histogram_get_bin_upper_bound(const circpad_machine_runtime_t *mi,
                               circpad_hist_index_t bin)
 {
   return circpad_histogram_bin_to_usec(mi, bin+1) - 1;
@@ -272,7 +273,7 @@ histogram_get_bin_upper_bound(const circpad_machine_state_t *mi,
 
 /** Return the midpoint of the histogram bin <b>bin_index</b>. */
 static circpad_delay_t
-circpad_get_histogram_bin_midpoint(const circpad_machine_state_t *mi,
+circpad_get_histogram_bin_midpoint(const circpad_machine_runtime_t *mi,
                            int bin_index)
 {
   circpad_delay_t left_bound = circpad_histogram_bin_to_usec(mi, bin_index);
@@ -290,7 +291,7 @@ circpad_get_histogram_bin_midpoint(const circpad_machine_state_t *mi,
  * the highest non-infinity bin, that bin index will be returned.
  */
 STATIC circpad_hist_index_t
-circpad_histogram_usec_to_bin(const circpad_machine_state_t *mi,
+circpad_histogram_usec_to_bin(const circpad_machine_runtime_t *mi,
                               circpad_delay_t usec)
 {
   const circpad_state_t *state = circpad_machine_current_state(mi);
@@ -330,7 +331,7 @@ circpad_histogram_usec_to_bin(const circpad_machine_state_t *mi,
  * Called after a state transition, or if the bins are empty.
  */
 STATIC void
-circpad_machine_setup_tokens(circpad_machine_state_t *mi)
+circpad_machine_setup_tokens(circpad_machine_runtime_t *mi)
 {
   const circpad_state_t *state = circpad_machine_current_state(mi);
 
@@ -362,7 +363,7 @@ circpad_machine_setup_tokens(circpad_machine_state_t *mi)
  * Choose a length for this state (in cells), if specified.
  */
 static void
-circpad_choose_state_length(circpad_machine_state_t *mi)
+circpad_choose_state_length(circpad_machine_runtime_t *mi)
 {
   const circpad_state_t *state = circpad_machine_current_state(mi);
   double length;
@@ -415,7 +416,7 @@ circpad_distribution_sample_iat_delay(const circpad_state_t *state,
  * that bin's [start,end) time range.
  */
 STATIC circpad_delay_t
-circpad_machine_sample_delay(circpad_machine_state_t *mi)
+circpad_machine_sample_delay(circpad_machine_runtime_t *mi)
 {
   const circpad_state_t *state = circpad_machine_current_state(mi);
   const circpad_hist_token_t *histogram = NULL;
@@ -451,7 +452,8 @@ circpad_machine_sample_delay(circpad_machine_state_t *mi)
     histogram_total_tokens = state->histogram_total_tokens;
   }
 
-  bin_choice = crypto_rand_uint64(histogram_total_tokens);
+  bin_choice = crypto_fast_rng_get_uint64(get_thread_fast_rng(),
+                                          histogram_total_tokens);
 
   /* Skip all the initial zero bins */
   while (!histogram[curr_bin]) {
@@ -500,12 +502,12 @@ circpad_machine_sample_delay(circpad_machine_state_t *mi)
   bin_end = circpad_histogram_bin_to_usec(mi, curr_bin+1);
 
   /* Bin edges are monotonically increasing so this is a bug. Handle it. */
-  if (BUG(bin_start > bin_end)) {
+  if (BUG(bin_start >= bin_end)) {
     return bin_start;
   }
 
-  /* Sample randomly from within the bin width */
-  return (circpad_delay_t)crypto_rand_uint64_range(bin_start, bin_end);
+  return (circpad_delay_t)crypto_fast_rng_uint64_range(get_thread_fast_rng(),
+                                                       bin_start, bin_end);
 }
 
 /**
@@ -602,7 +604,7 @@ circpad_distribution_sample(circpad_distribution_t dist)
  * greater than the target, and that has tokens remaining.
  */
 static circpad_hist_index_t
-circpad_machine_first_higher_index(const circpad_machine_state_t *mi,
+circpad_machine_first_higher_index(const circpad_machine_runtime_t *mi,
                                    circpad_delay_t target_bin_usec)
 {
   circpad_hist_index_t bin = circpad_histogram_usec_to_bin(mi,
@@ -624,7 +626,7 @@ circpad_machine_first_higher_index(const circpad_machine_state_t *mi,
  * <b>target_bin_usec</b>, and that still has tokens remaining.
  */
 static circpad_hist_index_t
-circpad_machine_first_lower_index(const circpad_machine_state_t *mi,
+circpad_machine_first_lower_index(const circpad_machine_runtime_t *mi,
                                   circpad_delay_t target_bin_usec)
 {
   circpad_hist_index_t bin = circpad_histogram_usec_to_bin(mi,
@@ -645,7 +647,7 @@ circpad_machine_first_lower_index(const circpad_machine_state_t *mi,
  * greater than the target.
  */
 STATIC void
-circpad_machine_remove_higher_token(circpad_machine_state_t *mi,
+circpad_machine_remove_higher_token(circpad_machine_runtime_t *mi,
                                     circpad_delay_t target_bin_usec)
 {
   /* We need to remove the token from the first bin
@@ -666,7 +668,7 @@ circpad_machine_remove_higher_token(circpad_machine_state_t *mi,
  * lower than the target.
  */
 STATIC void
-circpad_machine_remove_lower_token(circpad_machine_state_t *mi,
+circpad_machine_remove_lower_token(circpad_machine_runtime_t *mi,
                                    circpad_delay_t target_bin_usec)
 {
   circpad_hist_index_t bin = circpad_machine_first_lower_index(mi,
@@ -695,7 +697,7 @@ circpad_machine_remove_lower_token(circpad_machine_state_t *mi,
  * If it is false, use bin index distance only.
  */
 STATIC void
-circpad_machine_remove_closest_token(circpad_machine_state_t *mi,
+circpad_machine_remove_closest_token(circpad_machine_runtime_t *mi,
                                      circpad_delay_t target_bin_usec,
                                      bool use_usec)
 {
@@ -777,7 +779,7 @@ circpad_machine_remove_closest_token(circpad_machine_state_t *mi,
  * If it is empty, do nothing.
  */
 static void
-circpad_machine_remove_exact(circpad_machine_state_t *mi,
+circpad_machine_remove_exact(circpad_machine_runtime_t *mi,
                              circpad_delay_t target_bin_usec)
 {
   circpad_hist_index_t bin = circpad_histogram_usec_to_bin(mi,
@@ -794,7 +796,7 @@ circpad_machine_remove_exact(circpad_machine_state_t *mi,
  * otherwise returns 0.
  */
 static circpad_decision_t
-check_machine_token_supply(circpad_machine_state_t *mi)
+check_machine_token_supply(circpad_machine_runtime_t *mi)
 {
   uint32_t histogram_total_tokens = 0;
 
@@ -834,7 +836,7 @@ check_machine_token_supply(circpad_machine_state_t *mi)
  * Returns 1 if we transition states, 0 otherwise.
  */
 STATIC circpad_decision_t
-circpad_machine_remove_token(circpad_machine_state_t *mi)
+circpad_machine_remove_token(circpad_machine_runtime_t *mi)
 {
   const circpad_state_t *state = NULL;
   circpad_time_t current_time;
@@ -961,14 +963,14 @@ circpad_send_command_to_hop,(origin_circuit_t *circ, uint8_t hopnum,
  * CIRCPAD_STATE_CHANGED. Otherwise return CIRCPAD_STATE_UNCHANGED.
  */
 circpad_decision_t
-circpad_send_padding_cell_for_callback(circpad_machine_state_t *mi)
+circpad_send_padding_cell_for_callback(circpad_machine_runtime_t *mi)
 {
   circuit_t *circ = mi->on_circ;
   int machine_idx = mi->machine_index;
   mi->padding_scheduled_at_usec = 0;
   circpad_statenum_t state = mi->current_state;
 
-  // Make sure circuit didn't close on us
+  /* Make sure circuit didn't close on us */
   if (mi->on_circ->marked_for_close) {
     log_fn(LOG_INFO,LD_CIRC,
            "Padding callback on a circuit marked for close. Ignoring.");
@@ -1047,7 +1049,7 @@ circpad_send_padding_cell_for_callback(circpad_machine_state_t *mi)
 /**
  * Tor-timer compatible callback that tells us to send a padding cell.
  *
- * Timers are associated with circpad_machine_state_t's. When the machineinfo
+ * Timers are associated with circpad_machine_runtime_t's. When the machineinfo
  * is freed on a circuit, the timers are cancelled. Since the lifetime
  * of machineinfo is always longer than the timers, handles are not
  * needed.
@@ -1056,7 +1058,7 @@ static void
 circpad_send_padding_callback(tor_timer_t *timer, void *args,
                               const struct monotime_t *time)
 {
-  circpad_machine_state_t *mi = ((circpad_machine_state_t*)args);
+  circpad_machine_runtime_t *mi = ((circpad_machine_runtime_t*)args);
   (void)timer; (void)time;
 
   if (mi && mi->on_circ) {
@@ -1106,7 +1108,7 @@ circpad_new_consensus_params(const networkstatus_t *ns)
  * Returns 1 if limits are set and we've hit them. Otherwise returns 0.
  */
 STATIC bool
-circpad_machine_reached_padding_limit(circpad_machine_state_t *mi)
+circpad_machine_reached_padding_limit(circpad_machine_runtime_t *mi)
 {
   const circpad_machine_spec_t *machine = CIRCPAD_GET_MACHINE(mi);
 
@@ -1154,12 +1156,18 @@ circpad_machine_reached_padding_limit(circpad_machine_state_t *mi)
  * 0 otherwise.
  */
 MOCK_IMPL(circpad_decision_t,
-circpad_machine_schedule_padding,(circpad_machine_state_t *mi))
+circpad_machine_schedule_padding,(circpad_machine_runtime_t *mi))
 {
   circpad_delay_t in_usec = 0;
   struct timeval timeout;
   tor_assert(mi);
 
+  /* Don't schedule padding if we are currently in dormant mode. */
+  if (!is_participating_on_network()) {
+    log_info(LD_CIRC, "Not scheduling padding because we are dormant.");
+    return CIRCPAD_STATE_UNCHANGED;
+  }
+
   // Don't pad in end (but  also don't cancel any previously
   // scheduled padding either).
   if (mi->current_state == CIRCPAD_STATE_END) {
@@ -1244,7 +1252,7 @@ circpad_machine_schedule_padding,(circpad_machine_state_t *mi))
  * not access it.
  */
 static void
-circpad_machine_spec_transitioned_to_end(circpad_machine_state_t *mi)
+circpad_machine_spec_transitioned_to_end(circpad_machine_runtime_t *mi)
 {
   const circpad_machine_spec_t *machine = CIRCPAD_GET_MACHINE(mi);
 
@@ -1294,7 +1302,7 @@ circpad_machine_spec_transitioned_to_end(circpad_machine_state_t *mi)
  * Returns 1 if we transition states, 0 otherwise.
  */
 MOCK_IMPL(circpad_decision_t,
-circpad_machine_spec_transition,(circpad_machine_state_t *mi,
+circpad_machine_spec_transition,(circpad_machine_runtime_t *mi,
                             circpad_event_t event))
 {
   const circpad_state_t *state =
@@ -1375,7 +1383,7 @@ circpad_machine_spec_transition,(circpad_machine_state_t *mi,
  */
 static void
 circpad_estimate_circ_rtt_on_received(circuit_t *circ,
-                                      circpad_machine_state_t *mi)
+                                      circpad_machine_runtime_t *mi)
 {
   /* Origin circuits don't estimate RTT. They could do it easily enough,
    * but they have no reason to use it in any delay calculations. */
@@ -1422,7 +1430,7 @@ circpad_estimate_circ_rtt_on_received(circuit_t *circ,
  */
 static void
 circpad_estimate_circ_rtt_on_send(circuit_t *circ,
-                                  circpad_machine_state_t *mi)
+                                  circpad_machine_runtime_t *mi)
 {
   /* Origin circuits don't estimate RTT. They could do it easily enough,
    * but they have no reason to use it in any delay calculations. */
@@ -1567,7 +1575,7 @@ circpad_cell_event_padding_received(circuit_t *on_circ)
  * Return 1 if we decide to transition, 0 otherwise.
  */
 circpad_decision_t
-circpad_internal_event_infinity(circpad_machine_state_t *mi)
+circpad_internal_event_infinity(circpad_machine_runtime_t *mi)
 {
   return circpad_machine_spec_transition(mi, CIRCPAD_EVENT_INFINITY);
 }
@@ -1581,7 +1589,7 @@ circpad_internal_event_infinity(circpad_machine_state_t *mi)
  * Return 1 if we decide to transition, 0 otherwise.
  */
 circpad_decision_t
-circpad_internal_event_bins_empty(circpad_machine_state_t *mi)
+circpad_internal_event_bins_empty(circpad_machine_runtime_t *mi)
 {
   if (circpad_machine_spec_transition(mi, CIRCPAD_EVENT_BINS_EMPTY)
       == CIRCPAD_STATE_CHANGED) {
@@ -1600,7 +1608,7 @@ circpad_internal_event_bins_empty(circpad_machine_state_t *mi)
  * Return 1 if we decide to transition, 0 otherwise.
  */
 circpad_decision_t
-circpad_internal_event_state_length_up(circpad_machine_state_t *mi)
+circpad_internal_event_state_length_up(circpad_machine_runtime_t *mi)
 {
   return circpad_machine_spec_transition(mi, CIRCPAD_EVENT_LENGTH_COUNT);
 }

+ 22 - 22
src/core/or/circuitpadding.h

@@ -88,7 +88,7 @@ typedef uint32_t circpad_delay_t;
 /**
  * Macro to clarify when we're checking the infinity bin.
  *
- * Works with either circpad_state_t or circpad_machine_state_t
+ * Works with either circpad_state_t or circpad_machine_runtime_t
  */
 #define CIRCPAD_INFINITY_BIN(mi)  ((mi)->histogram_len-1)
 
@@ -254,7 +254,7 @@ typedef uint16_t circpad_statenum_t;
  * A state of a padding state machine. The information here are immutable and
  * represent the initial form of the state; it does not get updated as things
  * happen. The mutable information that gets updated in runtime are carried in
- * a circpad_machine_state_t.
+ * a circpad_machine_runtime_t.
  *
  * This struct describes the histograms and parameters of a single
  * state in the adaptive padding machine. Instances of this struct
@@ -476,7 +476,7 @@ typedef struct circpad_state_t {
  *
  * XXX: Play with layout to minimize space on x64 Linux (most common relay).
  */
-typedef struct circpad_machine_state_t {
+typedef struct circpad_machine_runtime_t {
   /** The callback pointer for the padding callbacks.
    *
    *  These timers stick around the machineinfo until the machineinfo's circuit
@@ -560,7 +560,7 @@ typedef struct circpad_machine_state_t {
    * CIRCPAD_MAX_MACHINES define). */
   unsigned machine_index : 1;
 
-} circpad_machine_state_t;
+} circpad_machine_runtime_t;
 
 /** Helper macro to get an actual state machine from a machineinfo */
 #define CIRCPAD_GET_MACHINE(machineinfo) \
@@ -638,11 +638,11 @@ void circpad_cell_event_padding_received(struct circuit_t *on_circ);
 
 /** Internal events are events the machines send to themselves */
 circpad_decision_t
-circpad_internal_event_infinity(circpad_machine_state_t *mi);
+circpad_internal_event_infinity(circpad_machine_runtime_t *mi);
 circpad_decision_t
-circpad_internal_event_bins_empty(circpad_machine_state_t *);
+circpad_internal_event_bins_empty(circpad_machine_runtime_t *);
 circpad_decision_t circpad_internal_event_state_length_up(
-                                  circpad_machine_state_t *);
+                                  circpad_machine_runtime_t *);
 
 /** Machine creation events are events that cause us to set up or
  *  tear down padding state machines. */
@@ -685,47 +685,47 @@ bool circpad_padding_negotiated(struct circuit_t *circ,
                            uint8_t response);
 
 MOCK_DECL(circpad_decision_t,
-circpad_machine_schedule_padding,(circpad_machine_state_t *));
+circpad_machine_schedule_padding,(circpad_machine_runtime_t *));
 
 MOCK_DECL(circpad_decision_t,
-circpad_machine_spec_transition, (circpad_machine_state_t *mi,
+circpad_machine_spec_transition, (circpad_machine_runtime_t *mi,
                              circpad_event_t event));
 
 circpad_decision_t circpad_send_padding_cell_for_callback(
-                                 circpad_machine_state_t *mi);
+                                 circpad_machine_runtime_t *mi);
 
 #ifdef CIRCUITPADDING_PRIVATE
 STATIC circpad_delay_t
-circpad_machine_sample_delay(circpad_machine_state_t *mi);
+circpad_machine_sample_delay(circpad_machine_runtime_t *mi);
 
 STATIC bool
-circpad_machine_reached_padding_limit(circpad_machine_state_t *mi);
+circpad_machine_reached_padding_limit(circpad_machine_runtime_t *mi);
 
 STATIC
-circpad_decision_t circpad_machine_remove_token(circpad_machine_state_t *mi);
+circpad_decision_t circpad_machine_remove_token(circpad_machine_runtime_t *mi);
 
 STATIC circpad_delay_t
-circpad_histogram_bin_to_usec(const circpad_machine_state_t *mi,
+circpad_histogram_bin_to_usec(const circpad_machine_runtime_t *mi,
                               circpad_hist_index_t bin);
 
 STATIC const circpad_state_t *
-circpad_machine_current_state(const circpad_machine_state_t *mi);
+circpad_machine_current_state(const circpad_machine_runtime_t *mi);
 
 STATIC circpad_hist_index_t circpad_histogram_usec_to_bin(
-                                       const circpad_machine_state_t *mi,
+                                       const circpad_machine_runtime_t *mi,
                                        circpad_delay_t us);
 
-STATIC circpad_machine_state_t *circpad_circuit_machineinfo_new(
+STATIC circpad_machine_runtime_t *circpad_circuit_machineinfo_new(
                                                struct circuit_t *on_circ,
                                                int machine_index);
-STATIC void circpad_machine_remove_higher_token(circpad_machine_state_t *mi,
+STATIC void circpad_machine_remove_higher_token(circpad_machine_runtime_t *mi,
                                          circpad_delay_t target_bin_us);
-STATIC void circpad_machine_remove_lower_token(circpad_machine_state_t *mi,
+STATIC void circpad_machine_remove_lower_token(circpad_machine_runtime_t *mi,
                                          circpad_delay_t target_bin_us);
-STATIC void circpad_machine_remove_closest_token(circpad_machine_state_t *mi,
+STATIC void circpad_machine_remove_closest_token(circpad_machine_runtime_t *mi,
                                          circpad_delay_t target_bin_us,
                                          bool use_usec);
-STATIC void circpad_machine_setup_tokens(circpad_machine_state_t *mi);
+STATIC void circpad_machine_setup_tokens(circpad_machine_runtime_t *mi);
 
 MOCK_DECL(STATIC signed_error_t,
 circpad_send_command_to_hop,(struct origin_circuit_t *circ, uint8_t hopnum,
@@ -733,7 +733,7 @@ circpad_send_command_to_hop,(struct origin_circuit_t *circ, uint8_t hopnum,
                              ssize_t payload_len));
 
 STATIC circpad_delay_t
-histogram_get_bin_upper_bound(const circpad_machine_state_t *mi,
+histogram_get_bin_upper_bound(const circpad_machine_runtime_t *mi,
                               circpad_hist_index_t bin);
 
 #ifdef TOR_UNIT_TESTS

+ 1 - 0
src/feature/hibernate/hibernate.h

@@ -32,6 +32,7 @@ int getinfo_helper_accounting(control_connection_t *conn,
                               const char **errmsg);
 uint64_t get_accounting_max_total(void);
 void accounting_free_all(void);
+bool accounting_tor_is_dormant(void);
 
 #ifdef HIBERNATE_PRIVATE
 /** Possible values of hibernate_state */

+ 3 - 0
src/lib/crypt_ops/crypto_rand.h

@@ -66,6 +66,9 @@ void crypto_fast_rng_free_(crypto_fast_rng_t *);
 
 unsigned crypto_fast_rng_get_uint(crypto_fast_rng_t *rng, unsigned limit);
 uint64_t crypto_fast_rng_get_uint64(crypto_fast_rng_t *rng, uint64_t limit);
+uint32_t crypto_fast_rng_get_u32(crypto_fast_rng_t *rng);
+uint64_t crypto_fast_rng_uint64_range(crypto_fast_rng_t *rng,
+                                      uint64_t min, uint64_t max);
 double crypto_fast_rng_get_double(crypto_fast_rng_t *rng);
 
 /**

+ 29 - 1
src/lib/crypt_ops/crypto_rand_numeric.c

@@ -155,7 +155,34 @@ crypto_fast_rng_get_uint64(crypto_fast_rng_t *rng, uint64_t limit)
 }
 
 /**
- * As crypto_rand_, but extract the result from a crypto_fast_rng_t.
+ * As crypto_rand_u32, but extract the result from a crypto_fast_rng_t.
+ */
+uint32_t
+crypto_fast_rng_get_u32(crypto_fast_rng_t *rng)
+{
+  uint32_t val;
+  crypto_fast_rng_getbytes(rng, (void*)&val, sizeof(val));
+  return val;
+}
+
+/**
+ * As crypto_rand_uint64_range(), but extract the result from a
+ * crypto_fast_rng_t.
+ */
+uint64_t
+crypto_fast_rng_uint64_range(crypto_fast_rng_t *rng,
+                             uint64_t min, uint64_t max)
+{
+  /* Handle corrupted input */
+  if (BUG(min >= max)) {
+    return min;
+  }
+
+  return min + crypto_fast_rng_get_uint64(rng, max - min);
+}
+
+/**
+ * As crypto_rand_get_double() but extract the result from a crypto_fast_rng_t.
  */
 double
 crypto_fast_rng_get_double(crypto_fast_rng_t *rng)
@@ -164,3 +191,4 @@ crypto_fast_rng_get_double(crypto_fast_rng_t *rng)
   crypto_fast_rng_getbytes(rng, (void*)&u, sizeof(u));
   return ((double)u) / UINT_MAX_AS_DOUBLE;
 }
+

+ 68 - 97
src/lib/math/prob_distr.c

@@ -46,26 +46,27 @@
 
 #include "lib/crypt_ops/crypto_rand.h"
 #include "lib/cc/ctassert.h"
+#include "lib/log/util_bug.h"
 
 #include <float.h>
 #include <math.h>
 #include <stddef.h>
 
-/** Validators for downcasting macros below */
-#define validate_container_of(PTR, TYPE, FIELD)                         \
-  (0 * sizeof((PTR) - &((TYPE *)(((char *)(PTR)) -                      \
-      offsetof(TYPE, FIELD)))->FIELD))
-#define validate_const_container_of(PTR, TYPE, FIELD)                   \
-  (0 * sizeof((PTR) - &((const TYPE *)(((const char *)(PTR)) -          \
-      offsetof(TYPE, FIELD)))->FIELD))
-/** Downcasting macro */
-#define container_of(PTR, TYPE, FIELD)                                  \
-  ((TYPE *)(((char *)(PTR)) - offsetof(TYPE, FIELD))                    \
-    + validate_container_of(PTR, TYPE, FIELD))
-/** Constified downcasting macro */
-#define const_container_of(PTR, TYPE, FIELD)                            \
-  ((const TYPE *)(((const char *)(PTR)) - offsetof(TYPE, FIELD))        \
-    + validate_const_container_of(PTR, TYPE, FIELD))
+/** Declare a function that downcasts from a generic dist struct to the actual
+ *  subtype probablity distribution it represents. */
+#define DECLARE_PROB_DISTR_DOWNCAST_FN(name) \
+  static inline                           \
+  const struct name *                             \
+  dist_to_const_##name(const struct dist *obj) {    \
+    tor_assert(obj->ops == &name##_ops);            \
+    return SUBTYPE_P(obj, struct name, base);   \
+  }
+DECLARE_PROB_DISTR_DOWNCAST_FN(uniform)
+DECLARE_PROB_DISTR_DOWNCAST_FN(geometric)
+DECLARE_PROB_DISTR_DOWNCAST_FN(logistic)
+DECLARE_PROB_DISTR_DOWNCAST_FN(log_logistic)
+DECLARE_PROB_DISTR_DOWNCAST_FN(genpareto)
+DECLARE_PROB_DISTR_DOWNCAST_FN(weibull)
 
 /**
  * Count number of one bits in 32-bit word.
@@ -458,7 +459,7 @@ random_uniform_01(void)
    * system is broken.
    */
   z = 0;
-  while ((x = crypto_rand_u32()) == 0) {
+  while ((x = crypto_fast_rng_get_u32(get_thread_fast_rng())) == 0) {
     if (z >= 1088)
       /* Your bit sampler is broken.  Go home.  */
       return 0;
@@ -472,8 +473,8 @@ random_uniform_01(void)
    * occur only with measure zero in the uniform distribution on
    * [0, 1].
    */
-  hi = crypto_rand_u32() | UINT32_C(0x80000000);
-  lo = crypto_rand_u32() | UINT32_C(0x00000001);
+  hi = crypto_fast_rng_get_u32(get_thread_fast_rng()) | UINT32_C(0x80000000);
+  lo = crypto_fast_rng_get_u32(get_thread_fast_rng()) | UINT32_C(0x00000001);
 
   /* Round to nearest scaled significand in [2^63, 2^64].  */
   s = hi*(double)4294967296 + lo;
@@ -1315,40 +1316,48 @@ sample_geometric(uint32_t s, double p0, double p)
 
 /** Public API for probability distributions:
  *
- *  For each probability distribution we define each public functions
- *  (sample/cdf/sf/icdf/isf) as part of its dist_ops structure.
+ *  These are wrapper functions on top of the various probability distribution
+ *  operations using the generic <b>dist</b> structure.
+
+ *  These are the functions that should be used by consumers of this API.
  */
 
+/** Returns the name of the distribution in <b>dist</b>. */
 const char *
 dist_name(const struct dist *dist)
 {
   return dist->ops->name;
 }
 
+/* Sample a value from <b>dist</b> and return it. */
 double
 dist_sample(const struct dist *dist)
 {
   return dist->ops->sample(dist);
 }
 
+/** Compute the CDF of <b>dist</b> at <b>x</b>. */
 double
 dist_cdf(const struct dist *dist, double x)
 {
   return dist->ops->cdf(dist, x);
 }
 
+/** Compute the SF (Survival function) of <b>dist</b> at <b>x</b>. */
 double
 dist_sf(const struct dist *dist, double x)
 {
   return dist->ops->sf(dist, x);
 }
 
+/** Compute the iCDF (Inverse CDF) of <b>dist</b> at <b>x</b>. */
 double
 dist_icdf(const struct dist *dist, double p)
 {
   return dist->ops->icdf(dist, p);
 }
 
+/** Compute the iSF (Inverse Survival function) of <b>dist</b> at <b>x</b>. */
 double
 dist_isf(const struct dist *dist, double p)
 {
@@ -1360,8 +1369,7 @@ dist_isf(const struct dist *dist, double p)
 static double
 uniform_sample(const struct dist *dist)
 {
-  const struct uniform *U = const_container_of(dist, struct uniform,
-    base);
+  const struct uniform *U = dist_to_const_uniform(dist);
   double p0 = random_uniform_01();
 
   return sample_uniform_interval(p0, U->a, U->b);
@@ -1370,9 +1378,7 @@ uniform_sample(const struct dist *dist)
 static double
 uniform_cdf(const struct dist *dist, double x)
 {
-  const struct uniform *U = const_container_of(dist, struct uniform,
-    base);
-
+  const struct uniform *U = dist_to_const_uniform(dist);
   if (x < U->a)
     return 0;
   else if (x < U->b)
@@ -1384,8 +1390,7 @@ uniform_cdf(const struct dist *dist, double x)
 static double
 uniform_sf(const struct dist *dist, double x)
 {
-  const struct uniform *U = const_container_of(dist, struct uniform,
-    base);
+  const struct uniform *U = dist_to_const_uniform(dist);
 
   if (x > U->b)
     return 0;
@@ -1398,8 +1403,7 @@ uniform_sf(const struct dist *dist, double x)
 static double
 uniform_icdf(const struct dist *dist, double p)
 {
-  const struct uniform *U = const_container_of(dist, struct uniform,
-    base);
+  const struct uniform *U = dist_to_const_uniform(dist);
   double w = U->b - U->a;
 
   return (p < 0.5 ? (U->a + w*p) : (U->b - w*(1 - p)));
@@ -1408,8 +1412,7 @@ uniform_icdf(const struct dist *dist, double p)
 static double
 uniform_isf(const struct dist *dist, double p)
 {
-  const struct uniform *U = const_container_of(dist, struct uniform,
-    base);
+  const struct uniform *U = dist_to_const_uniform(dist);
   double w = U->b - U->a;
 
   return (p < 0.5 ? (U->b - w*p) : (U->a + w*(1 - p)));
@@ -1424,14 +1427,17 @@ const struct dist_ops uniform_ops = {
   .isf = uniform_isf,
 };
 
+/*******************************************************************/
+
+/** Private functions for each probability distribution. */
+
 /** Functions for logistic distribution: */
 
 static double
 logistic_sample(const struct dist *dist)
 {
-  const struct logistic *L = const_container_of(dist, struct logistic,
-    base);
-  uint32_t s = crypto_rand_u32();
+  const struct logistic *L = dist_to_const_logistic(dist);
+  uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
   double t = random_uniform_01();
   double p0 = random_uniform_01();
 
@@ -1441,36 +1447,28 @@ logistic_sample(const struct dist *dist)
 static double
 logistic_cdf(const struct dist *dist, double x)
 {
-  const struct logistic *L = const_container_of(dist, struct logistic,
-    base);
-
+  const struct logistic *L = dist_to_const_logistic(dist);
   return cdf_logistic(x, L->mu, L->sigma);
 }
 
 static double
 logistic_sf(const struct dist *dist, double x)
 {
-  const struct logistic *L = const_container_of(dist, struct logistic,
-    base);
-
+  const struct logistic *L = dist_to_const_logistic(dist);
   return sf_logistic(x, L->mu, L->sigma);
 }
 
 static double
 logistic_icdf(const struct dist *dist, double p)
 {
-  const struct logistic *L = const_container_of(dist, struct logistic,
-    base);
-
+  const struct logistic *L = dist_to_const_logistic(dist);
   return icdf_logistic(p, L->mu, L->sigma);
 }
 
 static double
 logistic_isf(const struct dist *dist, double p)
 {
-  const struct logistic *L = const_container_of(dist, struct logistic,
-    base);
-
+  const struct logistic *L = dist_to_const_logistic(dist);
   return isf_logistic(p, L->mu, L->sigma);
 }
 
@@ -1488,9 +1486,8 @@ const struct dist_ops logistic_ops = {
 static double
 log_logistic_sample(const struct dist *dist)
 {
-  const struct log_logistic *LL = const_container_of(dist, struct
-    log_logistic, base);
-  uint32_t s = crypto_rand_u32();
+  const struct log_logistic *LL = dist_to_const_log_logistic(dist);
+  uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
   double p0 = random_uniform_01();
 
   return sample_log_logistic_scaleshape(s, p0, LL->alpha, LL->beta);
@@ -1499,36 +1496,28 @@ log_logistic_sample(const struct dist *dist)
 static double
 log_logistic_cdf(const struct dist *dist, double x)
 {
-  const struct log_logistic *LL = const_container_of(dist,
-    struct log_logistic, base);
-
+  const struct log_logistic *LL = dist_to_const_log_logistic(dist);
   return cdf_log_logistic(x, LL->alpha, LL->beta);
 }
 
 static double
 log_logistic_sf(const struct dist *dist, double x)
 {
-  const struct log_logistic *LL = const_container_of(dist,
-    struct log_logistic, base);
-
+  const struct log_logistic *LL = dist_to_const_log_logistic(dist);
   return sf_log_logistic(x, LL->alpha, LL->beta);
 }
 
 static double
 log_logistic_icdf(const struct dist *dist, double p)
 {
-  const struct log_logistic *LL = const_container_of(dist,
-    struct log_logistic, base);
-
+  const struct log_logistic *LL = dist_to_const_log_logistic(dist);
   return icdf_log_logistic(p, LL->alpha, LL->beta);
 }
 
 static double
 log_logistic_isf(const struct dist *dist, double p)
 {
-  const struct log_logistic *LL = const_container_of(dist,
-    struct log_logistic, base);
-
+  const struct log_logistic *LL = dist_to_const_log_logistic(dist);
   return isf_log_logistic(p, LL->alpha, LL->beta);
 }
 
@@ -1546,9 +1535,8 @@ const struct dist_ops log_logistic_ops = {
 static double
 weibull_sample(const struct dist *dist)
 {
-  const struct weibull *W = const_container_of(dist, struct weibull,
-    base);
-  uint32_t s = crypto_rand_u32();
+  const struct weibull *W = dist_to_const_weibull(dist);
+  uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
   double p0 = random_uniform_01();
 
   return sample_weibull(s, p0, W->lambda, W->k);
@@ -1557,36 +1545,28 @@ weibull_sample(const struct dist *dist)
 static double
 weibull_cdf(const struct dist *dist, double x)
 {
-  const struct weibull *W = const_container_of(dist, struct weibull,
-    base);
-
+  const struct weibull *W = dist_to_const_weibull(dist);
   return cdf_weibull(x, W->lambda, W->k);
 }
 
 static double
 weibull_sf(const struct dist *dist, double x)
 {
-  const struct weibull *W = const_container_of(dist, struct weibull,
-    base);
-
+  const struct weibull *W = dist_to_const_weibull(dist);
   return sf_weibull(x, W->lambda, W->k);
 }
 
 static double
 weibull_icdf(const struct dist *dist, double p)
 {
-  const struct weibull *W = const_container_of(dist, struct weibull,
-    base);
-
+  const struct weibull *W = dist_to_const_weibull(dist);
   return icdf_weibull(p, W->lambda, W->k);
 }
 
 static double
 weibull_isf(const struct dist *dist, double p)
 {
-  const struct weibull *W = const_container_of(dist, struct weibull,
-    base);
-
+  const struct weibull *W = dist_to_const_weibull(dist);
   return isf_weibull(p, W->lambda, W->k);
 }
 
@@ -1604,9 +1584,8 @@ const struct dist_ops weibull_ops = {
 static double
 genpareto_sample(const struct dist *dist)
 {
-  const struct genpareto *GP = const_container_of(dist, struct genpareto,
-    base);
-  uint32_t s = crypto_rand_u32();
+  const struct genpareto *GP = dist_to_const_genpareto(dist);
+  uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
   double p0 = random_uniform_01();
 
   return sample_genpareto_locscale(s, p0, GP->mu, GP->sigma, GP->xi);
@@ -1615,36 +1594,28 @@ genpareto_sample(const struct dist *dist)
 static double
 genpareto_cdf(const struct dist *dist, double x)
 {
-  const struct genpareto *GP = const_container_of(dist, struct genpareto,
-    base);
-
+  const struct genpareto *GP = dist_to_const_genpareto(dist);
   return cdf_genpareto(x, GP->mu, GP->sigma, GP->xi);
 }
 
 static double
 genpareto_sf(const struct dist *dist, double x)
 {
-  const struct genpareto *GP = const_container_of(dist, struct genpareto,
-    base);
-
+  const struct genpareto *GP = dist_to_const_genpareto(dist);
   return sf_genpareto(x, GP->mu, GP->sigma, GP->xi);
 }
 
 static double
 genpareto_icdf(const struct dist *dist, double p)
 {
-  const struct genpareto *GP = const_container_of(dist, struct genpareto,
-    base);
-
+  const struct genpareto *GP = dist_to_const_genpareto(dist);
   return icdf_genpareto(p, GP->mu, GP->sigma, GP->xi);
 }
 
 static double
 genpareto_isf(const struct dist *dist, double p)
 {
-  const struct genpareto *GP = const_container_of(dist, struct genpareto,
-    base);
-
+  const struct genpareto *GP = dist_to_const_genpareto(dist);
   return isf_genpareto(p, GP->mu, GP->sigma, GP->xi);
 }
 
@@ -1662,8 +1633,8 @@ const struct dist_ops genpareto_ops = {
 static double
 geometric_sample(const struct dist *dist)
 {
-  const struct geometric *G = const_container_of(dist, struct geometric, base);
-  uint32_t s = crypto_rand_u32();
+  const struct geometric *G = dist_to_const_geometric(dist);
+  uint32_t s = crypto_fast_rng_get_u32(get_thread_fast_rng());
   double p0 = random_uniform_01();
 
   return sample_geometric(s, p0, G->p);
@@ -1672,7 +1643,7 @@ geometric_sample(const struct dist *dist)
 static double
 geometric_cdf(const struct dist *dist, double x)
 {
-  const struct geometric *G = const_container_of(dist, struct geometric, base);
+  const struct geometric *G = dist_to_const_geometric(dist);
 
   if (x < 1)
     return 0;
@@ -1683,7 +1654,7 @@ geometric_cdf(const struct dist *dist, double x)
 static double
 geometric_sf(const struct dist *dist, double x)
 {
-  const struct geometric *G = const_container_of(dist, struct geometric, base);
+  const struct geometric *G = dist_to_const_geometric(dist);
 
   if (x < 1)
     return 0;
@@ -1694,7 +1665,7 @@ geometric_sf(const struct dist *dist, double x)
 static double
 geometric_icdf(const struct dist *dist, double p)
 {
-  const struct geometric *G = const_container_of(dist, struct geometric, base);
+  const struct geometric *G = dist_to_const_geometric(dist);
 
   return log1p(-p)/log1p(-G->p);
 }
@@ -1702,7 +1673,7 @@ geometric_icdf(const struct dist *dist, double p)
 static double
 geometric_isf(const struct dist *dist, double p)
 {
-  const struct geometric *G = const_container_of(dist, struct geometric, base);
+  const struct geometric *G = dist_to_const_geometric(dist);
 
   return log(p)/log1p(-G->p);
 }

+ 18 - 11
src/test/test_circuitpadding.c

@@ -17,6 +17,7 @@
 #include "core/or/circuitlist.h"
 #include "core/or/circuitbuild.h"
 #include "core/or/circuitpadding.h"
+#include "core/mainloop/netstatus.h"
 #include "core/crypto/relay_crypto.h"
 #include "core/or/protover.h"
 #include "feature/nodelist/nodelist.h"
@@ -491,7 +492,7 @@ helper_create_machine_with_big_histogram(circpad_removal_t removal_strategy)
 }
 
 static circpad_decision_t
-circpad_machine_schedule_padding_mock(circpad_machine_state_t *mi)
+circpad_machine_schedule_padding_mock(circpad_machine_runtime_t *mi)
 {
   (void)mi;
   return 0;
@@ -507,7 +508,7 @@ mock_monotime_absolute_usec(void)
 static void
 test_circuitpadding_token_removal_higher(void *arg)
 {
-  circpad_machine_state_t *mi;
+  circpad_machine_runtime_t *mi;
   (void)arg;
 
   /* Mock it up */
@@ -612,7 +613,7 @@ test_circuitpadding_token_removal_higher(void *arg)
 static void
 test_circuitpadding_token_removal_lower(void *arg)
 {
-  circpad_machine_state_t *mi;
+  circpad_machine_runtime_t *mi;
   (void)arg;
 
   /* Mock it up */
@@ -710,7 +711,7 @@ test_circuitpadding_token_removal_lower(void *arg)
 static void
 test_circuitpadding_closest_token_removal(void *arg)
 {
-  circpad_machine_state_t *mi;
+  circpad_machine_runtime_t *mi;
   (void)arg;
 
   /* Mock it up */
@@ -816,7 +817,7 @@ test_circuitpadding_closest_token_removal(void *arg)
 static void
 test_circuitpadding_closest_token_removal_usec(void *arg)
 {
-  circpad_machine_state_t *mi;
+  circpad_machine_runtime_t *mi;
   (void)arg;
 
   /* Mock it up */
@@ -927,7 +928,7 @@ test_circuitpadding_closest_token_removal_usec(void *arg)
 static void
 test_circuitpadding_token_removal_exact(void *arg)
 {
-  circpad_machine_state_t *mi;
+  circpad_machine_runtime_t *mi;
   (void)arg;
 
   /* Mock it up */
@@ -988,7 +989,7 @@ void
 test_circuitpadding_tokens(void *arg)
 {
   const circpad_state_t *state;
-  circpad_machine_state_t *mi;
+  circpad_machine_runtime_t *mi;
   (void)arg;
 
   /** Test plan:
@@ -1020,6 +1021,9 @@ test_circuitpadding_tokens(void *arg)
   monotime_coarse_set_mock_time_nsec(1*TOR_NSEC_PER_USEC);
   curr_mocked_time = 1*TOR_NSEC_PER_USEC;
 
+  /* This is needed so that we are not considered to be dormant */
+  note_user_activity(20);
+
   timers_initialize();
 
   helper_create_basic_machine();
@@ -1749,6 +1753,9 @@ test_circuitpadding_conditions(void *arg)
   monotime_coarse_set_mock_time_nsec(1*TOR_NSEC_PER_USEC);
   curr_mocked_time = 1*TOR_NSEC_PER_USEC;
 
+  /* This is needed so that we are not considered to be dormant */
+  note_user_activity(20);
+
   timers_initialize();
   helper_create_conditional_machines();
 
@@ -2152,7 +2159,7 @@ helper_circpad_circ_distribution_machine_setup(int min, int max)
 static void
 test_circuitpadding_sample_distribution(void *arg)
 {
-  circpad_machine_state_t *mi;
+  circpad_machine_runtime_t *mi;
   int n_samples;
   int n_states;
 
@@ -2196,7 +2203,7 @@ test_circuitpadding_sample_distribution(void *arg)
 }
 
 static circpad_decision_t
-circpad_machine_spec_transition_mock(circpad_machine_state_t *mi,
+circpad_machine_spec_transition_mock(circpad_machine_runtime_t *mi,
                                 circpad_event_t event)
 {
   (void) mi;
@@ -2211,7 +2218,7 @@ test_circuitpadding_machine_rate_limiting(void *arg)
 {
   (void) arg;
   bool retval;
-  circpad_machine_state_t *mi;
+  circpad_machine_runtime_t *mi;
   int i;
 
   /* Ignore machine transitions for the purposes of this function, we only
@@ -2279,7 +2286,7 @@ test_circuitpadding_global_rate_limiting(void *arg)
 {
   (void) arg;
   bool retval;
-  circpad_machine_state_t *mi;
+  circpad_machine_runtime_t *mi;
   int i;
 
   /* Ignore machine transitions for the purposes of this function, we only