From a7cf057a63eb40f35eba7058bf252dbb0721b880 Mon Sep 17 00:00:00 2001 From: Johanna Amann Date: Mon, 3 Feb 2025 15:02:15 +0100 Subject: [PATCH] util/init_random_seed: write_file implies deterministic This makes Zeek run in deterministic mode with --save-seeds usage and reworks all the extra indirections used in init_random_seed() to make it easier to follow the control flow. Fixes #4209 --- NEWS | 4 ++ src/util.cc | 51 +++++++++---------- .../core.save-load-seeds/load.conn.log.cut | 3 ++ .../core.save-load-seeds/save.conn.log.cut | 3 ++ testing/btest/core/save-load-seeds.zeek | 16 ++++++ 5 files changed, 50 insertions(+), 27 deletions(-) create mode 100644 testing/btest/Baseline/core.save-load-seeds/load.conn.log.cut create mode 100644 testing/btest/Baseline/core.save-load-seeds/save.conn.log.cut create mode 100644 testing/btest/core/save-load-seeds.zeek diff --git a/NEWS b/NEWS index 6a6c2a04be..3e0643030e 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,10 @@ Changed Functionality then prompt to use --help. The --help usage will now print to standard output rather than standard error. +- Saving seeds with ``--save-seeds`` will now put Zeek into deterministic mode. + A subsequent ``--load-seeds`` run with the same scripts and traces will produce + identical UID values as the original ``--save-seeds` run. + Removed Functionality --------------------- diff --git a/src/util.cc b/src/util.cc index edc424fb4a..34691a9f38 100644 --- a/src/util.cc +++ b/src/util.cc @@ -363,9 +363,8 @@ static long int zeek_rand_state = 0; static bool first_seed_saved = false; static unsigned int first_seed = 0; -static void zeek_srandom(unsigned int seed, bool deterministic) { +static void zeek_srandom(unsigned int seed) { zeek_rand_state = seed == 0 ? 1 : seed; - zeek_rand_deterministic = deterministic; srandom(seed); } @@ -380,26 +379,28 @@ void seed_random(unsigned int seed) { void init_random_seed(const char* read_file, const char* write_file, bool use_empty_seeds, const std::string& seed_string) { std::array buf = {}; - size_t pos = 0; // accumulates entropy - bool seeds_done = false; uint32_t seed = 0; - if ( read_file ) { - if ( ! read_random_seeds(read_file, &seed, buf) ) - reporter->FatalError("Could not load seeds from file '%s'.", read_file); - else - seeds_done = true; - } - else if ( ! seed_string.empty() ) { - if ( ! fill_random_seeds(seed_string, &seed, buf) ) - reporter->FatalError("Could not load seeds from string"); - else - seeds_done = true; - } - else if ( use_empty_seeds ) - seeds_done = true; + if ( write_file ) + // run in deterministic mode when we write a file + zeek_rand_deterministic = true; + + if ( read_file || use_empty_seeds || ! seed_string.empty() ) { + // if a seed is provided - run Zeek in deterministic mode + zeek_rand_deterministic = true; + + if ( read_file ) { + if ( ! read_random_seeds(read_file, &seed, buf) ) + reporter->FatalError("Could not load seeds from file '%s'.", read_file); + } + else if ( ! seed_string.empty() ) { + if ( ! fill_random_seeds(seed_string, &seed, buf) ) + reporter->FatalError("Could not load seeds from string"); + } + } + else { // no seed provided + size_t pos = 0; // accumulates entropy - if ( ! seeds_done ) { #ifdef HAVE_GETRANDOM // getrandom() guarantees reads up to 256 bytes are always successful, assert(sizeof(buf) < 256); @@ -437,17 +438,13 @@ void init_random_seed(const char* read_file, const char* write_file, bool use_em reporter->FatalError("Could not read enough random data. Wanted %d, got %zu", zeek::detail::KeyedHash::SEED_INIT_SIZE, pos); - if ( ! seed ) { - for ( size_t i = 0; i < pos; ++i ) { - seed ^= buf[i]; - seed = (seed << 1) | (seed >> 31); - } + for ( size_t i = 0; i < pos; ++i ) { + seed ^= buf[i]; + seed = (seed << 1) | (seed >> 31); } - else - seeds_done = true; } - zeek_srandom(seed, seeds_done); + zeek_srandom(seed); if ( ! first_seed_saved ) { first_seed = seed; diff --git a/testing/btest/Baseline/core.save-load-seeds/load.conn.log.cut b/testing/btest/Baseline/core.save-load-seeds/load.conn.log.cut new file mode 100644 index 0000000000..4d75476d4e --- /dev/null +++ b/testing/btest/Baseline/core.save-load-seeds/load.conn.log.cut @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +uid history service +CHhAvVGS1DHFjwGM9 ShADadFf http diff --git a/testing/btest/Baseline/core.save-load-seeds/save.conn.log.cut b/testing/btest/Baseline/core.save-load-seeds/save.conn.log.cut new file mode 100644 index 0000000000..4d75476d4e --- /dev/null +++ b/testing/btest/Baseline/core.save-load-seeds/save.conn.log.cut @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +uid history service +CHhAvVGS1DHFjwGM9 ShADadFf http diff --git a/testing/btest/core/save-load-seeds.zeek b/testing/btest/core/save-load-seeds.zeek new file mode 100644 index 0000000000..f51f16bb2e --- /dev/null +++ b/testing/btest/core/save-load-seeds.zeek @@ -0,0 +1,16 @@ +# @TEST-DOC: Save seeds and read and assure the UIDs are the same. Regression test for #4209 +# +# @TEST-EXEC: zeek --save-seeds myseeds -r $TRACES/http/get.trace %INPUT +# @TEST-EXEC: mkdir save && mv *log save +# @TEST-EXEC: zeek-cut -m uid history service < save/conn.log >save/conn.log.cut +# +# @TEST-EXEC: zeek --load-seeds myseeds -r $TRACES/http/get.trace %INPUT +# @TEST-EXEC: mkdir load && mv *log load +# @TEST-EXEC: zeek-cut -m uid history service < load/conn.log >load/conn.log.cut +# +# @TEST-EXEC: btest-diff load/conn.log.cut +# @TEST-EXEC: btest-diff save/conn.log.cut +# @TEST-EXEC: diff load/conn.log.cut save/conn.log.cut + +@load base/protocols/conn +@load base/protocols/http