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
This commit is contained in:
Johanna Amann 2025-02-03 15:02:15 +01:00 committed by Arne Welzel
parent 280e7acc6e
commit a7cf057a63
5 changed files with 50 additions and 27 deletions

4
NEWS
View file

@ -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
---------------------

View file

@ -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<uint32_t, zeek::detail::KeyedHash::SEED_INIT_SIZE> buf = {};
size_t pos = 0; // accumulates entropy
bool seeds_done = false;
uint32_t seed = 0;
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
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;
}
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);
}
}
else
seeds_done = true;
}
zeek_srandom(seed, seeds_done);
zeek_srandom(seed);
if ( ! first_seed_saved ) {
first_seed = seed;

View file

@ -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

View file

@ -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

View file

@ -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