Merge branch 'tor-github/pr/1022'

This commit is contained in:
David Goulet 2019-05-23 09:50:28 -04:00
commit 29955f13e5
8 changed files with 93 additions and 26 deletions

View File

@ -42,7 +42,7 @@ matrix:
## include creates builds with gcc, linux ## include creates builds with gcc, linux
include: include:
## We include a single coverage build with the best options for coverage ## We include a single coverage build with the best options for coverage
- env: COVERAGE_OPTIONS="--enable-coverage" HARDENING_OPTIONS="" - env: COVERAGE_OPTIONS="--enable-coverage" HARDENING_OPTIONS="" TOR_TEST_RNG_SEED="636f766572616765"
## We only want to check these build option combinations once ## We only want to check these build option combinations once
## (they shouldn't vary by compiler or OS) ## (they shouldn't vary by compiler or OS)
## We run rust and coverage with hardening off, which seems like enough ## We run rust and coverage with hardening off, which seems like enough

11
changes/ticket28878 Normal file
View File

@ -0,0 +1,11 @@
o Minor features (testing):
- The circuitpadding tests now use a reproducible RNG implementation,
so that if a test fails, we can learn why. Part of ticket 28878.
- Tor's tests now support an environment variable, TOR_TEST_RNG_SEED,
to set the RNG seed for tests that use a reproducible RNG.
Part of ticket 28878.
o Minor features (continuous integration):
- When running coverage builds on Travis, we now set TOR_TEST_RNG_SEED,
to avoid RNG-based coverage differences.
Part of ticket 28878.

View File

@ -492,6 +492,12 @@ tinytest_set_test_skipped_(void)
cur_test_outcome = SKIP; cur_test_outcome = SKIP;
} }
int
tinytest_cur_test_has_failed(void)
{
return (cur_test_outcome == FAIL);
}
char * char *
tinytest_format_hex_(const void *val_, unsigned long len) tinytest_format_hex_(const void *val_, unsigned long len)
{ {

View File

@ -72,6 +72,9 @@ struct testlist_alias_t {
}; };
#define END_OF_ALIASES { NULL, NULL } #define END_OF_ALIASES { NULL, NULL }
/** Return true iff the current test has failed. */
int tinytest_cur_test_has_failed(void);
/** Implementation: called from a test to indicate failure, before logging. */ /** Implementation: called from a test to indicate failure, before logging. */
void tinytest_set_test_failed_(void); void tinytest_set_test_failed_(void);
/** Implementation: called from a test to indicate that we're skipping. */ /** Implementation: called from a test to indicate that we're skipping. */

View File

@ -17,6 +17,7 @@
#include "core/or/or.h" #include "core/or/or.h"
#include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_rand.h"
#include "ext/tinytest.h"
#include "test/rng_test_helpers.h" #include "test/rng_test_helpers.h"
@ -54,7 +55,8 @@ static uint8_t rng_seed[16];
static crypto_xof_t *rng_xof = NULL; static crypto_xof_t *rng_xof = NULL;
/** /**
* Print the seed for our PRNG to stdout. We use this when we're * Print the seed for our PRNG to stdout. We use this when we're failed
* test that had a reproducible RNG set.
**/ **/
void void
testing_dump_reproducible_rng_seed(void) testing_dump_reproducible_rng_seed(void)
@ -122,9 +124,22 @@ enable_deterministic_rng_impl(const uint8_t *seed, size_t seed_len)
void void
testing_enable_reproducible_rng(void) testing_enable_reproducible_rng(void)
{ {
uint8_t seed[16]; const char *provided_seed = getenv("TOR_TEST_RNG_SEED");
crypto_rand((char*)seed, sizeof(seed)); if (provided_seed) {
enable_deterministic_rng_impl(seed, sizeof(seed)); size_t hexlen = strlen(provided_seed);
size_t seedlen = hexlen / 2;
uint8_t *seed = tor_malloc(hexlen / 2);
if (base16_decode((char*)seed, seedlen, provided_seed, hexlen) < 0) {
puts("Cannot decode value in TOR_TEST_RNG_SEED");
exit(1);
}
enable_deterministic_rng_impl(seed, seedlen);
tor_free(seed);
} else {
uint8_t seed[16];
crypto_rand((char*)seed, sizeof(seed));
enable_deterministic_rng_impl(seed, sizeof(seed));
}
} }
/** /**
@ -228,3 +243,16 @@ testing_disable_rng_override(void)
rng_is_replaced = false; rng_is_replaced = false;
} }
/**
* As testing_disable_rng_override(), but dump the seed if the current
* test has failed.
*/
void
testing_disable_reproducible_rng(void)
{
if (tinytest_cur_test_has_failed()) {
testing_dump_reproducible_rng_seed();
}
testing_disable_rng_override();
}

View File

@ -14,8 +14,7 @@ void testing_prefilled_rng_reset(void);
void testing_disable_rng_override(void); void testing_disable_rng_override(void);
#define testing_disable_reproducible_rng() \ void testing_disable_reproducible_rng(void);
testing_disable_rng_override()
#define testing_disable_deterministic_rng() \ #define testing_disable_deterministic_rng() \
testing_disable_rng_override() testing_disable_rng_override()
#define testing_disable_prefilled_rng() \ #define testing_disable_prefilled_rng() \

View File

@ -36,6 +36,8 @@
#include "core/or/or_circuit_st.h" #include "core/or/or_circuit_st.h"
#include "core/or/origin_circuit_st.h" #include "core/or/origin_circuit_st.h"
#include "test/rng_test_helpers.h"
/* Start our monotime mocking at 1 second past whatever monotime_init() /* Start our monotime mocking at 1 second past whatever monotime_init()
* thought the actual wall clock time was, for platforms with bad resolution * thought the actual wall clock time was, for platforms with bad resolution
* and weird timevalues during monotime_init() before mocking. */ * and weird timevalues during monotime_init() before mocking. */
@ -313,6 +315,7 @@ test_circuitpadding_rtt(void *arg)
MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock); MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock); MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
testing_enable_reproducible_rng();
dummy_channel.cmux = circuitmux_alloc(); dummy_channel.cmux = circuitmux_alloc();
relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel)); relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
@ -416,6 +419,7 @@ test_circuitpadding_rtt(void *arg)
UNMOCK(circuit_package_relay_cell); UNMOCK(circuit_package_relay_cell);
UNMOCK(circuitmux_attach_circuit); UNMOCK(circuitmux_attach_circuit);
tor_free(circ_client_machine.states); tor_free(circ_client_machine.states);
testing_disable_reproducible_rng();
return; return;
} }
@ -540,6 +544,7 @@ test_circuitpadding_token_removal_higher(void *arg)
/* Mock it up */ /* Mock it up */
MOCK(monotime_absolute_usec, mock_monotime_absolute_usec); MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock); MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
testing_enable_reproducible_rng();
/* Setup test environment (time etc.) */ /* Setup test environment (time etc.) */
client_side = TO_CIRCUIT(origin_circuit_new()); client_side = TO_CIRCUIT(origin_circuit_new());
@ -633,6 +638,7 @@ test_circuitpadding_token_removal_higher(void *arg)
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
monotime_disable_test_mocking(); monotime_disable_test_mocking();
tor_free(circ_client_machine.states); tor_free(circ_client_machine.states);
testing_disable_reproducible_rng();
} }
/** Test lower token removal strategy by bin */ /** Test lower token removal strategy by bin */
@ -645,6 +651,7 @@ test_circuitpadding_token_removal_lower(void *arg)
/* Mock it up */ /* Mock it up */
MOCK(monotime_absolute_usec, mock_monotime_absolute_usec); MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock); MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
testing_enable_reproducible_rng();
/* Setup test environment (time etc.) */ /* Setup test environment (time etc.) */
client_side = TO_CIRCUIT(origin_circuit_new()); client_side = TO_CIRCUIT(origin_circuit_new());
@ -731,6 +738,7 @@ test_circuitpadding_token_removal_lower(void *arg)
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
monotime_disable_test_mocking(); monotime_disable_test_mocking();
tor_free(circ_client_machine.states); tor_free(circ_client_machine.states);
testing_disable_reproducible_rng();
} }
/** Test closest token removal strategy by bin */ /** Test closest token removal strategy by bin */
@ -743,6 +751,7 @@ test_circuitpadding_closest_token_removal(void *arg)
/* Mock it up */ /* Mock it up */
MOCK(monotime_absolute_usec, mock_monotime_absolute_usec); MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock); MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
testing_enable_reproducible_rng();
/* Setup test environment (time etc.) */ /* Setup test environment (time etc.) */
client_side = TO_CIRCUIT(origin_circuit_new()); client_side = TO_CIRCUIT(origin_circuit_new());
@ -837,6 +846,7 @@ test_circuitpadding_closest_token_removal(void *arg)
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
monotime_disable_test_mocking(); monotime_disable_test_mocking();
tor_free(circ_client_machine.states); tor_free(circ_client_machine.states);
testing_disable_reproducible_rng();
} }
/** Test closest token removal strategy with usec */ /** Test closest token removal strategy with usec */
@ -849,6 +859,7 @@ test_circuitpadding_closest_token_removal_usec(void *arg)
/* Mock it up */ /* Mock it up */
MOCK(monotime_absolute_usec, mock_monotime_absolute_usec); MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock); MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
testing_enable_reproducible_rng();
/* Setup test environment (time etc.) */ /* Setup test environment (time etc.) */
client_side = TO_CIRCUIT(origin_circuit_new()); client_side = TO_CIRCUIT(origin_circuit_new());
@ -948,6 +959,7 @@ test_circuitpadding_closest_token_removal_usec(void *arg)
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
monotime_disable_test_mocking(); monotime_disable_test_mocking();
tor_free(circ_client_machine.states); tor_free(circ_client_machine.states);
testing_disable_reproducible_rng();
} }
/** Test closest token removal strategy with usec */ /** Test closest token removal strategy with usec */
@ -960,6 +972,7 @@ test_circuitpadding_token_removal_exact(void *arg)
/* Mock it up */ /* Mock it up */
MOCK(monotime_absolute_usec, mock_monotime_absolute_usec); MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock); MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
testing_enable_reproducible_rng();
/* Setup test environment (time etc.) */ /* Setup test environment (time etc.) */
client_side = TO_CIRCUIT(origin_circuit_new()); client_side = TO_CIRCUIT(origin_circuit_new());
@ -1007,6 +1020,7 @@ test_circuitpadding_token_removal_exact(void *arg)
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
monotime_disable_test_mocking(); monotime_disable_test_mocking();
tor_free(circ_client_machine.states); tor_free(circ_client_machine.states);
testing_disable_reproducible_rng();
} }
#undef BIG_HISTOGRAM_LEN #undef BIG_HISTOGRAM_LEN
@ -1019,6 +1033,8 @@ test_circuitpadding_tokens(void *arg)
int64_t actual_mocked_monotime_start; int64_t actual_mocked_monotime_start;
(void)arg; (void)arg;
testing_enable_reproducible_rng();
/** Test plan: /** Test plan:
* *
* 1. Test symmetry between bin_to_usec and usec_to_bin * 1. Test symmetry between bin_to_usec and usec_to_bin
@ -1272,6 +1288,7 @@ test_circuitpadding_tokens(void *arg)
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
monotime_disable_test_mocking(); monotime_disable_test_mocking();
tor_free(circ_client_machine.states); tor_free(circ_client_machine.states);
testing_disable_reproducible_rng();
} }
void void
@ -1299,6 +1316,7 @@ test_circuitpadding_wronghop(void *arg)
/* Mock this function so that our cell counting tests don't get confused by /* Mock this function so that our cell counting tests don't get confused by
* padding that gets sent by scheduled timers. */ * padding that gets sent by scheduled timers. */
MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock); MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
testing_enable_reproducible_rng();
client_side = TO_CIRCUIT(origin_circuit_new()); client_side = TO_CIRCUIT(origin_circuit_new());
dummy_channel.cmux = circuitmux_alloc(); dummy_channel.cmux = circuitmux_alloc();
@ -1472,6 +1490,7 @@ test_circuitpadding_wronghop(void *arg)
UNMOCK(circuit_package_relay_cell); UNMOCK(circuit_package_relay_cell);
UNMOCK(circuitmux_attach_circuit); UNMOCK(circuitmux_attach_circuit);
nodes_free(); nodes_free();
testing_disable_reproducible_rng();
} }
void void
@ -1952,6 +1971,7 @@ test_circuitpadding_conditions(void *arg)
int64_t actual_mocked_monotime_start; int64_t actual_mocked_monotime_start;
(void)arg; (void)arg;
MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock); MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
testing_enable_reproducible_rng();
nodes_init(); nodes_init();
dummy_channel.cmux = circuitmux_alloc(); dummy_channel.cmux = circuitmux_alloc();
@ -2056,6 +2076,7 @@ test_circuitpadding_conditions(void *arg)
done: done:
/* XXX: Free everything */ /* XXX: Free everything */
testing_disable_reproducible_rng();
return; return;
} }
@ -2385,6 +2406,7 @@ test_circuitpadding_sample_distribution(void *arg)
/* mock this function so that we dont actually schedule any padding */ /* mock this function so that we dont actually schedule any padding */
MOCK(circpad_machine_schedule_padding, MOCK(circpad_machine_schedule_padding,
circpad_machine_schedule_padding_mock); circpad_machine_schedule_padding_mock);
testing_enable_reproducible_rng();
/* Initialize a machine with multiple probability distributions */ /* Initialize a machine with multiple probability distributions */
circpad_machines_init(); circpad_machines_init();
@ -2417,6 +2439,7 @@ test_circuitpadding_sample_distribution(void *arg)
done: done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
UNMOCK(circpad_machine_schedule_padding); UNMOCK(circpad_machine_schedule_padding);
testing_disable_reproducible_rng();
} }
static circpad_decision_t static circpad_decision_t
@ -2442,6 +2465,7 @@ test_circuitpadding_machine_rate_limiting(void *arg)
* really care about padding counts */ * really care about padding counts */
MOCK(circpad_machine_spec_transition, circpad_machine_spec_transition_mock); MOCK(circpad_machine_spec_transition, circpad_machine_spec_transition_mock);
MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock); MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
testing_enable_reproducible_rng();
/* Setup machine and circuits */ /* Setup machine and circuits */
client_side = TO_CIRCUIT(origin_circuit_new()); client_side = TO_CIRCUIT(origin_circuit_new());
@ -2495,6 +2519,7 @@ test_circuitpadding_machine_rate_limiting(void *arg)
done: done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side)); free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
testing_disable_reproducible_rng();
} }
/* Test global padding rate limits */ /* Test global padding rate limits */
@ -2514,6 +2539,7 @@ test_circuitpadding_global_rate_limiting(void *arg)
MOCK(circuit_package_relay_cell, MOCK(circuit_package_relay_cell,
circuit_package_relay_cell_mock); circuit_package_relay_cell_mock);
MOCK(monotime_absolute_usec, mock_monotime_absolute_usec); MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
testing_enable_reproducible_rng();
monotime_init(); monotime_init();
monotime_enable_test_mocking(); monotime_enable_test_mocking();
@ -2593,6 +2619,7 @@ test_circuitpadding_global_rate_limiting(void *arg)
circuitmux_free(dummy_channel.cmux); circuitmux_free(dummy_channel.cmux);
SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp)); SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp));
smartlist_free(vote1.net_params); smartlist_free(vote1.net_params);
testing_disable_reproducible_rng();
} }
/* Test reduced and disabled padding */ /* Test reduced and disabled padding */
@ -2603,6 +2630,7 @@ test_circuitpadding_reduce_disable(void *arg)
int64_t actual_mocked_monotime_start; int64_t actual_mocked_monotime_start;
MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock); MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
testing_enable_reproducible_rng();
nodes_init(); nodes_init();
dummy_channel.cmux = circuitmux_alloc(); dummy_channel.cmux = circuitmux_alloc();
@ -2742,6 +2770,7 @@ test_circuitpadding_reduce_disable(void *arg)
free_fake_orcirc(relay_side); free_fake_orcirc(relay_side);
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL); circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux); circuitmux_free(dummy_channel.cmux);
testing_disable_reproducible_rng();
} }
/** Just a basic machine whose whole purpose is to reach the END state */ /** Just a basic machine whose whole purpose is to reach the END state */

View File

@ -1119,13 +1119,14 @@ test_psi_dist_sample(const struct dist *dist)
} }
static void static void
dump_seed(void) write_stochastic_warning(void)
{ {
printf("\n" if (tinytest_cur_test_has_failed()) {
printf("\n"
"NOTE: This is a stochastic test, and we expect it to fail from\n" "NOTE: This is a stochastic test, and we expect it to fail from\n"
"time to time, with some low probability. If you see it fail more\n" "time to time, with some low probability. If you see it fail more\n"
"than one trial in 100, though, please tell us.\n\n"); "than one trial in 100, though, please tell us.\n\n");
testing_dump_reproducible_rng_seed(); }
} }
static void static void
@ -1180,7 +1181,7 @@ test_stochastic_uniform(void *arg)
done: done:
if (tests_failed) { if (tests_failed) {
dump_seed(); write_stochastic_warning();
} }
testing_disable_reproducible_rng(); testing_disable_reproducible_rng();
} }
@ -1273,7 +1274,7 @@ test_stochastic_genpareto(void *arg)
done: done:
if (tests_failed) { if (tests_failed) {
dump_seed(); write_stochastic_warning();
} }
testing_disable_reproducible_rng(); testing_disable_reproducible_rng();
} }
@ -1301,7 +1302,7 @@ test_stochastic_geometric(void *arg)
done: done:
if (tests_failed) { if (tests_failed) {
dump_seed(); write_stochastic_warning();
} }
testing_disable_reproducible_rng(); testing_disable_reproducible_rng();
} }
@ -1328,7 +1329,7 @@ test_stochastic_logistic(void *arg)
done: done:
if (tests_failed) { if (tests_failed) {
dump_seed(); write_stochastic_warning();
} }
testing_disable_reproducible_rng(); testing_disable_reproducible_rng();
} }
@ -1337,7 +1338,6 @@ static void
test_stochastic_log_logistic(void *arg) test_stochastic_log_logistic(void *arg)
{ {
bool ok = 0; bool ok = 0;
bool tests_failed = true;
(void) arg; (void) arg;
testing_enable_reproducible_rng(); testing_enable_reproducible_rng();
@ -1351,12 +1351,8 @@ test_stochastic_log_logistic(void *arg)
ok = test_stochastic_log_logistic_impl(exp(-10), 1e-2); ok = test_stochastic_log_logistic_impl(exp(-10), 1e-2);
tt_assert(ok); tt_assert(ok);
tests_failed = false;
done: done:
if (tests_failed) { write_stochastic_warning();
dump_seed();
}
testing_disable_reproducible_rng(); testing_disable_reproducible_rng();
} }
@ -1364,7 +1360,6 @@ static void
test_stochastic_weibull(void *arg) test_stochastic_weibull(void *arg)
{ {
bool ok = 0; bool ok = 0;
bool tests_failed = true;
(void) arg; (void) arg;
testing_enable_reproducible_rng(); testing_enable_reproducible_rng();
@ -1380,12 +1375,8 @@ test_stochastic_weibull(void *arg)
ok = test_stochastic_weibull_impl(10, 1); ok = test_stochastic_weibull_impl(10, 1);
tt_assert(ok); tt_assert(ok);
tests_failed = false;
done: done:
if (tests_failed) { write_stochastic_warning();
dump_seed();
}
testing_disable_reproducible_rng(); testing_disable_reproducible_rng();
UNMOCK(crypto_rand); UNMOCK(crypto_rand);
} }