From d51bd4bc4675d4d7234da0d11e31dbede5efe17c Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Mon, 26 Apr 2021 22:45:14 -0700 Subject: [PATCH] Fix using clear_table() within an &expire_func This previously crashed since clear_table()/TableVal::RemoveAll() left behind a stale iterator to the old table causing a heap-use-after-free when resuming table expiry iteration in TableVal::DoExpire(). --- src/Val.cc | 8 +++++- .../Baseline/bifs.clear_table_expire_func/out | 2 ++ .../btest/bifs/clear_table_expire_func.zeek | 26 +++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 testing/btest/Baseline/bifs.clear_table_expire_func/out create mode 100644 testing/btest/bifs/clear_table_expire_func.zeek diff --git a/src/Val.cc b/src/Val.cc index bbb86bb3d5..ca2670185d 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -1459,6 +1459,8 @@ TableVal::~TableVal() void TableVal::RemoveAll() { + delete expire_iterator; + expire_iterator = nullptr; // Here we take the brute force approach. delete table_val; table_val = new PDict; @@ -2575,6 +2577,10 @@ void TableVal::DoExpire(double t) if ( ! v ) { // user-provided function deleted it + if ( ! expire_iterator ) + // Entire table got dropped (e.g. clear_table() / RemoveAll()) + break; + continue; } @@ -2613,7 +2619,7 @@ void TableVal::DoExpire(double t) if ( modified ) Modified(); - if ( (*expire_iterator) == table_val->end_robust() ) + if ( ! expire_iterator || (*expire_iterator) == table_val->end_robust() ) { delete expire_iterator; expire_iterator = nullptr; diff --git a/testing/btest/Baseline/bifs.clear_table_expire_func/out b/testing/btest/Baseline/bifs.clear_table_expire_func/out new file mode 100644 index 0000000000..d31d49d5e0 --- /dev/null +++ b/testing/btest/Baseline/bifs.clear_table_expire_func/out @@ -0,0 +1,2 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +expire diff --git a/testing/btest/bifs/clear_table_expire_func.zeek b/testing/btest/bifs/clear_table_expire_func.zeek new file mode 100644 index 0000000000..5f3eaee191 --- /dev/null +++ b/testing/btest/bifs/clear_table_expire_func.zeek @@ -0,0 +1,26 @@ +# @TEST-EXEC: zeek -b %INPUT > out +# @TEST-EXEC: btest-diff out +# @TEST-DOC: Checks use of clear_table() within an &expire_func works. + +redef exit_only_after_terminate=T; +redef table_expire_interval = 1msec; + +global myexpire: function(t: table[count] of count, i: count): interval; + +global mt: table[count] of count &create_expire=1msec &expire_func=myexpire; + +function myexpire(t: table[count] of count, i: count): interval + { + print "expire"; + clear_table(mt); + terminate(); + return 0secs; + } + +event zeek_init() + { + mt[0] = 0; + mt[1] = 1; + mt[2] = 2; + } +