mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 06:13:31 +01:00
Merge remote-tracking branch 'public/bug7801_v2'
This commit is contained in:
commit
2b4d4ccb3d
13
changes/bug7801
Normal file
13
changes/bug7801
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
o Minor bugfixes:
|
||||||
|
- When choosing which stream on a formerly stalled circuit to wake
|
||||||
|
first, make better use of the platform's weak RNG. Previously, we
|
||||||
|
had been using the % ("modulo") operator to try to generate a 1/N
|
||||||
|
chance of picking each stream, but this behaves badly with many
|
||||||
|
platforms' choice of weak RNG. Fix for bug 7801; bugfix on
|
||||||
|
0.2.2.20-alpha.
|
||||||
|
- Use our own weak RNG when we need a weak RNG. Windows's rand()
|
||||||
|
and Irix's random() only return 15 bits; Solaris's random()
|
||||||
|
returns more bits but its RAND_MAX says it only returns 15, and
|
||||||
|
so on. Fixes another aspect of bug 7801; bugfix on
|
||||||
|
0.2.2.20-alpha.
|
||||||
|
|
@ -2059,30 +2059,6 @@ tor_lookup_hostname(const char *name, uint32_t *addr)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Initialize the insecure libc RNG. */
|
|
||||||
void
|
|
||||||
tor_init_weak_random(unsigned seed)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
srand(seed);
|
|
||||||
#else
|
|
||||||
srandom(seed);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return a randomly chosen value in the range 0..TOR_RAND_MAX. This
|
|
||||||
* entropy will not be cryptographically strong; do not rely on it
|
|
||||||
* for anything an adversary should not be able to predict. */
|
|
||||||
long
|
|
||||||
tor_weak_random(void)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
return rand();
|
|
||||||
#else
|
|
||||||
return random();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Hold the result of our call to <b>uname</b>. */
|
/** Hold the result of our call to <b>uname</b>. */
|
||||||
static char uname_result[256];
|
static char uname_result[256];
|
||||||
/** True iff uname_result is set. */
|
/** True iff uname_result is set. */
|
||||||
|
@ -581,11 +581,6 @@ typedef enum {
|
|||||||
SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08,
|
SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08,
|
||||||
} socks5_reply_status_t;
|
} socks5_reply_status_t;
|
||||||
|
|
||||||
/* ===== Insecure rng */
|
|
||||||
void tor_init_weak_random(unsigned seed);
|
|
||||||
long tor_weak_random(void);
|
|
||||||
#define TOR_RAND_MAX (RAND_MAX)
|
|
||||||
|
|
||||||
/* ===== OS compatibility */
|
/* ===== OS compatibility */
|
||||||
const char *get_uname(void);
|
const char *get_uname(void);
|
||||||
|
|
||||||
|
@ -2337,12 +2337,12 @@ crypto_dh_free(crypto_dh_t *dh)
|
|||||||
(OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c'))
|
(OPENSSL_VERSION_NUMBER >= OPENSSL_V(0,9,8,'c'))
|
||||||
|
|
||||||
/** Set the seed of the weak RNG to a random value. */
|
/** Set the seed of the weak RNG to a random value. */
|
||||||
static void
|
void
|
||||||
seed_weak_rng(void)
|
crypto_seed_weak_rng(tor_weak_rng_t *rng)
|
||||||
{
|
{
|
||||||
unsigned seed;
|
unsigned seed;
|
||||||
crypto_rand((void*)&seed, sizeof(seed));
|
crypto_rand((void*)&seed, sizeof(seed));
|
||||||
tor_init_weak_random(seed);
|
tor_init_weak_random(rng, seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
|
/** Try to get <b>out_len</b> bytes of the strongest entropy we can generate,
|
||||||
@ -2426,7 +2426,7 @@ crypto_seed_rng(int startup)
|
|||||||
}
|
}
|
||||||
|
|
||||||
memwipe(buf, 0, sizeof(buf));
|
memwipe(buf, 0, sizeof(buf));
|
||||||
seed_weak_rng();
|
|
||||||
if (rand_poll_ok || load_entropy_ok)
|
if (rand_poll_ok || load_entropy_ok)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
|
@ -256,6 +256,8 @@ int crypto_strongest_rand(uint8_t *out, size_t out_len);
|
|||||||
int crypto_rand_int(unsigned int max);
|
int crypto_rand_int(unsigned int max);
|
||||||
uint64_t crypto_rand_uint64(uint64_t max);
|
uint64_t crypto_rand_uint64(uint64_t max);
|
||||||
double crypto_rand_double(void);
|
double crypto_rand_double(void);
|
||||||
|
struct tor_weak_rng_t;
|
||||||
|
void crypto_seed_weak_rng(struct tor_weak_rng_t *rng);
|
||||||
|
|
||||||
char *crypto_random_hostname(int min_rand_len, int max_rand_len,
|
char *crypto_random_hostname(int min_rand_len, int max_rand_len,
|
||||||
const char *prefix, const char *suffix);
|
const char *prefix, const char *suffix);
|
||||||
|
@ -4996,3 +4996,45 @@ tor_check_port_forwarding(const char *filename,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Initialize the insecure RNG <b>rng</b> from a seed value <b>seed</b>. */
|
||||||
|
void
|
||||||
|
tor_init_weak_random(tor_weak_rng_t *rng, unsigned seed)
|
||||||
|
{
|
||||||
|
rng->state = (uint32_t)(seed & 0x7fffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return a randomly chosen value in the range 0..TOR_WEAK_RANDOM_MAX based
|
||||||
|
* on the RNG state of <b>rng</b>. This entropy will not be cryptographically
|
||||||
|
* strong; do not rely on it for anything an adversary should not be able to
|
||||||
|
* predict. */
|
||||||
|
int32_t
|
||||||
|
tor_weak_random(tor_weak_rng_t *rng)
|
||||||
|
{
|
||||||
|
/* Here's a linear congruential generator. OpenBSD and glibc use these
|
||||||
|
* parameters; they aren't too bad, and should have maximal period over the
|
||||||
|
* range 0..INT32_MAX. We don't want to use the platform rand() or random(),
|
||||||
|
* since some platforms have bad weak RNGs that only return values in the
|
||||||
|
* range 0..INT16_MAX, which just isn't enough. */
|
||||||
|
rng->state = (rng->state * 1103515245 + 12345) & 0x7fffffff;
|
||||||
|
return (int32_t) rng->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return a random number in the range [0 , <b>top</b>). {That is, the range
|
||||||
|
* of integers i such that 0 <= i < top.} Chooses uniformly. Requires that
|
||||||
|
* top is greater than 0. This randomness is not cryptographically strong; do
|
||||||
|
* not rely on it for anything an adversary should not be able to predict. */
|
||||||
|
int32_t
|
||||||
|
tor_weak_random_range(tor_weak_rng_t *rng, int32_t top)
|
||||||
|
{
|
||||||
|
/* We don't want to just do tor_weak_random() % top, since random() is often
|
||||||
|
* implemented with an LCG whose modulus is a power of 2, and those are
|
||||||
|
* cyclic in their low-order bits. */
|
||||||
|
int divisor, result;
|
||||||
|
tor_assert(top > 0);
|
||||||
|
divisor = TOR_WEAK_RANDOM_MAX / top;
|
||||||
|
do {
|
||||||
|
result = (int32_t)(tor_weak_random(rng) / divisor);
|
||||||
|
} while (result >= top);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -494,6 +494,20 @@ int tor_terminate_process(process_handle_t *process_handle);
|
|||||||
void tor_process_handle_destroy(process_handle_t *process_handle,
|
void tor_process_handle_destroy(process_handle_t *process_handle,
|
||||||
int also_terminate_process);
|
int also_terminate_process);
|
||||||
|
|
||||||
|
/* ===== Insecure rng */
|
||||||
|
typedef struct tor_weak_rng_t {
|
||||||
|
uint32_t state;
|
||||||
|
} tor_weak_rng_t;
|
||||||
|
|
||||||
|
#define TOR_WEAK_RNG_INIT {383745623}
|
||||||
|
#define TOR_WEAK_RANDOM_MAX (INT_MAX)
|
||||||
|
void tor_init_weak_random(tor_weak_rng_t *weak_rng, unsigned seed);
|
||||||
|
int32_t tor_weak_random(tor_weak_rng_t *weak_rng);
|
||||||
|
int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top);
|
||||||
|
/** Randomly return true according to <b>rng</b> with probability 1 in
|
||||||
|
* <b>n</b> */
|
||||||
|
#define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n)))
|
||||||
|
|
||||||
#ifdef UTIL_PRIVATE
|
#ifdef UTIL_PRIVATE
|
||||||
/* Prototypes for private functions only used by util.c (and unit tests) */
|
/* Prototypes for private functions only used by util.c (and unit tests) */
|
||||||
|
|
||||||
|
@ -196,8 +196,10 @@ static uint64_t onionskins_usec_roundtrip[MAX_ONION_HANDSHAKE_TYPE+1];
|
|||||||
* time. (microseconds) */
|
* time. (microseconds) */
|
||||||
#define MAX_BELIEVABLE_ONIONSKIN_DELAY (2*1000*1000)
|
#define MAX_BELIEVABLE_ONIONSKIN_DELAY (2*1000*1000)
|
||||||
|
|
||||||
|
static tor_weak_rng_t request_sample_rng = TOR_WEAK_RNG_INIT;
|
||||||
|
|
||||||
/** Return true iff we'd like to measure a handshake of type
|
/** Return true iff we'd like to measure a handshake of type
|
||||||
* <b>onionskin_type</b>. */
|
* <b>onionskin_type</b>. Call only from the main thread. */
|
||||||
static int
|
static int
|
||||||
should_time_request(uint16_t onionskin_type)
|
should_time_request(uint16_t onionskin_type)
|
||||||
{
|
{
|
||||||
@ -210,7 +212,7 @@ should_time_request(uint16_t onionskin_type)
|
|||||||
return 1;
|
return 1;
|
||||||
/** Otherwise, measure with P=1/128. We avoid doing this for every
|
/** Otherwise, measure with P=1/128. We avoid doing this for every
|
||||||
* handshake, since the measurement itself can take a little time. */
|
* handshake, since the measurement itself can take a little time. */
|
||||||
return tor_weak_random() < (TOR_RAND_MAX/128);
|
return tor_weak_random_one_in_n(&request_sample_rng, 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return an estimate of how many microseconds we will need for a single
|
/** Return an estimate of how many microseconds we will need for a single
|
||||||
@ -560,6 +562,7 @@ static void
|
|||||||
spawn_enough_cpuworkers(void)
|
spawn_enough_cpuworkers(void)
|
||||||
{
|
{
|
||||||
int num_cpuworkers_needed = get_num_cpus(get_options());
|
int num_cpuworkers_needed = get_num_cpus(get_options());
|
||||||
|
int reseed = 0;
|
||||||
|
|
||||||
if (num_cpuworkers_needed < MIN_CPUWORKERS)
|
if (num_cpuworkers_needed < MIN_CPUWORKERS)
|
||||||
num_cpuworkers_needed = MIN_CPUWORKERS;
|
num_cpuworkers_needed = MIN_CPUWORKERS;
|
||||||
@ -572,7 +575,11 @@ spawn_enough_cpuworkers(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
num_cpuworkers++;
|
num_cpuworkers++;
|
||||||
|
reseed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reseed)
|
||||||
|
crypto_seed_weak_rng(&request_sample_rng);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Take a pending task from the queue and assign it to 'cpuworker'. */
|
/** Take a pending task from the queue and assign it to 'cpuworker'. */
|
||||||
|
@ -2391,6 +2391,7 @@ tor_init(int argc, char *argv[])
|
|||||||
log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting.");
|
log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
stream_choice_seed_weak_rng();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,9 @@ uint64_t stats_n_relay_cells_relayed = 0;
|
|||||||
*/
|
*/
|
||||||
uint64_t stats_n_relay_cells_delivered = 0;
|
uint64_t stats_n_relay_cells_delivered = 0;
|
||||||
|
|
||||||
|
/** Used to tell which stream to read from first on a circuit. */
|
||||||
|
static tor_weak_rng_t stream_choice_rng = TOR_WEAK_RNG_INIT;
|
||||||
|
|
||||||
/** Update digest from the payload of cell. Assign integrity part to
|
/** Update digest from the payload of cell. Assign integrity part to
|
||||||
* cell.
|
* cell.
|
||||||
*/
|
*/
|
||||||
@ -1740,6 +1743,12 @@ circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint)
|
|||||||
circ, layer_hint);
|
circ, layer_hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
stream_choice_seed_weak_rng(void)
|
||||||
|
{
|
||||||
|
crypto_seed_weak_rng(&stream_choice_rng);
|
||||||
|
}
|
||||||
|
|
||||||
/** A helper function for circuit_resume_edge_reading() above.
|
/** A helper function for circuit_resume_edge_reading() above.
|
||||||
* The arguments are the same, except that <b>conn</b> is the head
|
* The arguments are the same, except that <b>conn</b> is the head
|
||||||
* of a linked list of edge streams that should each be considered.
|
* of a linked list of edge streams that should each be considered.
|
||||||
@ -1755,11 +1764,18 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
|
|||||||
int cells_on_queue;
|
int cells_on_queue;
|
||||||
int cells_per_conn;
|
int cells_per_conn;
|
||||||
edge_connection_t *chosen_stream = NULL;
|
edge_connection_t *chosen_stream = NULL;
|
||||||
|
int max_to_package;
|
||||||
|
|
||||||
|
if (first_conn == NULL) {
|
||||||
|
/* Don't bother to try to do the rest of this if there are no connections
|
||||||
|
* to resume. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* How many cells do we have space for? It will be the minimum of
|
/* How many cells do we have space for? It will be the minimum of
|
||||||
* the number needed to exhaust the package window, and the minimum
|
* the number needed to exhaust the package window, and the minimum
|
||||||
* needed to fill the cell queue. */
|
* needed to fill the cell queue. */
|
||||||
int max_to_package = circ->package_window;
|
max_to_package = circ->package_window;
|
||||||
if (CIRCUIT_IS_ORIGIN(circ)) {
|
if (CIRCUIT_IS_ORIGIN(circ)) {
|
||||||
cells_on_queue = circ->n_chan_cells.n;
|
cells_on_queue = circ->n_chan_cells.n;
|
||||||
} else {
|
} else {
|
||||||
@ -1784,10 +1800,19 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn,
|
|||||||
int num_streams = 0;
|
int num_streams = 0;
|
||||||
for (conn = first_conn; conn; conn = conn->next_stream) {
|
for (conn = first_conn; conn; conn = conn->next_stream) {
|
||||||
num_streams++;
|
num_streams++;
|
||||||
if ((tor_weak_random() % num_streams)==0)
|
if (tor_weak_random_one_in_n(&stream_choice_rng, num_streams)) {
|
||||||
chosen_stream = conn;
|
chosen_stream = conn;
|
||||||
|
}
|
||||||
/* Invariant: chosen_stream has been chosen uniformly at random from
|
/* Invariant: chosen_stream has been chosen uniformly at random from
|
||||||
* among the first num_streams streams on first_conn. */
|
* among the first num_streams streams on first_conn.
|
||||||
|
*
|
||||||
|
* (Note that we iterate over every stream on the circuit, so that after
|
||||||
|
* we've considered the first stream, we've chosen it with P=1; and
|
||||||
|
* after we consider the second stream, we've switched to it with P=1/2
|
||||||
|
* and stayed with the first stream with P=1/2; and after we've
|
||||||
|
* considered the third stream, we've switched to it with P=1/3 and
|
||||||
|
* remained with one of the first two streams with P=(2/3), giving each
|
||||||
|
* one P=(1/2)(2/3) )=(1/3).) */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +65,8 @@ const uint8_t *decode_address_from_payload(tor_addr_t *addr_out,
|
|||||||
int payload_len);
|
int payload_len);
|
||||||
void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan);
|
void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan);
|
||||||
|
|
||||||
|
void stream_choice_seed_weak_rng(void);
|
||||||
|
|
||||||
#ifdef RELAY_PRIVATE
|
#ifdef RELAY_PRIVATE
|
||||||
int relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction,
|
int relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction,
|
||||||
crypt_path_t **layer_hint, char *recognized);
|
crypt_path_t **layer_hint, char *recognized);
|
||||||
|
@ -3241,6 +3241,34 @@ test_util_set_env_var_in_sl(void *ptr)
|
|||||||
smartlist_free(expected_resulting_env_vars);
|
smartlist_free(expected_resulting_env_vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_util_weak_random(void *arg)
|
||||||
|
{
|
||||||
|
int i, j, n[16];
|
||||||
|
tor_weak_rng_t rng;
|
||||||
|
(void) arg;
|
||||||
|
|
||||||
|
tor_init_weak_random(&rng, (unsigned)time(NULL));
|
||||||
|
|
||||||
|
for (i = 1; i <= 256; ++i) {
|
||||||
|
for (j=0;j<100;++j) {
|
||||||
|
int r = tor_weak_random_range(&rng, i);
|
||||||
|
tt_int_op(0, <=, r);
|
||||||
|
tt_int_op(r, <, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(n,0,sizeof(n));
|
||||||
|
for (j=0;j<8192;++j) {
|
||||||
|
n[tor_weak_random_range(&rng, 16)]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0;i<16;++i)
|
||||||
|
tt_int_op(n[i], >, 0);
|
||||||
|
done:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_util_mathlog(void *arg)
|
test_util_mathlog(void *arg)
|
||||||
{
|
{
|
||||||
@ -3312,6 +3340,7 @@ struct testcase_t util_tests[] = {
|
|||||||
UTIL_TEST(read_file_eof_two_loops, 0),
|
UTIL_TEST(read_file_eof_two_loops, 0),
|
||||||
UTIL_TEST(read_file_eof_zero_bytes, 0),
|
UTIL_TEST(read_file_eof_zero_bytes, 0),
|
||||||
UTIL_TEST(mathlog, 0),
|
UTIL_TEST(mathlog, 0),
|
||||||
|
UTIL_TEST(weak_random, 0),
|
||||||
END_OF_TESTCASES
|
END_OF_TESTCASES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user