fixup! Prevent SQLite storage backend from serving expired entries

This commit is contained in:
Arne Welzel 2025-07-15 11:58:28 +02:00
parent 0e17f9cb11
commit c5397917e1

View file

@ -17,11 +17,6 @@
using namespace std::chrono_literals; using namespace std::chrono_literals;
namespace {
// Helper to check whether a database-stored `expire_time` is considered expired.
bool is_expired(double expire_time) { return expire_time != 0 && expire_time < zeek::run_state::network_time; }
} // namespace
namespace zeek::storage::backend::sqlite { namespace zeek::storage::backend::sqlite {
OperationResult SQLite::RunPragma(std::string_view name, std::optional<std::string_view> value) { OperationResult SQLite::RunPragma(std::string_view name, std::optional<std::string_view> value) {
@ -196,7 +191,10 @@ OperationResult SQLite::DoOpen(OpenResultCallback* cb, RecordValPtr options) {
static std::array<std::pair<std::string, sqlite3*>, 8> statements = static std::array<std::pair<std::string, sqlite3*>, 8> statements =
{std::make_pair(util::fmt(put_base_cmd.c_str(), table_name.c_str()), db), {std::make_pair(util::fmt(put_base_cmd.c_str(), table_name.c_str()), db),
std::make_pair(util::fmt(put_cmd.c_str(), table_name.c_str()), db), std::make_pair(util::fmt(put_cmd.c_str(), table_name.c_str()), db),
std::make_pair(util::fmt("select value_str, expire_time from %s where key_str=?", table_name.c_str()), db), std::make_pair(util::fmt("select value_str, expire_time from %s where key_str=? and ((expire_time > ?) OR "
"(expire_time IS NOT NULL AND expire_time == 0.0))",
table_name.c_str()),
db),
std::make_pair(util::fmt("delete from %s where key_str=?", table_name.c_str()), db), std::make_pair(util::fmt("delete from %s where key_str=?", table_name.c_str()), db),
std::make_pair( std::make_pair(
@ -297,10 +295,10 @@ OperationResult SQLite::DoPut(ResultCallback* cb, ValPtr key, ValPtr value, bool
return {ReturnCode::SERIALIZATION_FAILED, "Failed to serialize key"}; return {ReturnCode::SERIALIZATION_FAILED, "Failed to serialize key"};
unique_stmt_ptr stmt; unique_stmt_ptr stmt;
if ( ! overwrite ) if ( overwrite )
stmt = unique_stmt_ptr(put_stmt.get(), sqlite3_reset);
else
stmt = unique_stmt_ptr(put_update_stmt.get(), sqlite3_reset); stmt = unique_stmt_ptr(put_update_stmt.get(), sqlite3_reset);
else
stmt = unique_stmt_ptr(put_stmt.get(), sqlite3_reset);
if ( auto res = CheckError(sqlite3_bind_blob(stmt.get(), 1, key_data->data(), key_data->size(), SQLITE_STATIC)); if ( auto res = CheckError(sqlite3_bind_blob(stmt.get(), 1, key_data->data(), key_data->size(), SQLITE_STATIC));
res.code != ReturnCode::SUCCESS ) { res.code != ReturnCode::SUCCESS ) {
@ -331,7 +329,7 @@ OperationResult SQLite::DoPut(ResultCallback* cb, ValPtr key, ValPtr value, bool
} }
if ( ! overwrite ) if ( ! overwrite )
if ( auto res = CheckError(sqlite3_bind_double(stmt.get(), 6, util::current_time())); if ( auto res = CheckError(sqlite3_bind_double(stmt.get(), 6, zeek::run_state::network_time));
res.code != ReturnCode::SUCCESS ) { res.code != ReturnCode::SUCCESS ) {
return res; return res;
} }
@ -365,6 +363,11 @@ OperationResult SQLite::DoGet(ResultCallback* cb, ValPtr key) {
return res; return res;
} }
if ( auto res = CheckError(sqlite3_bind_double(stmt.get(), 2, zeek::run_state::network_time));
res.code != ReturnCode::SUCCESS ) {
return res;
}
return Step(stmt.get(), true); return Step(stmt.get(), true);
} }
@ -514,9 +517,6 @@ OperationResult SQLite::Step(sqlite3_stmt* stmt, bool parse_value) {
int step_status = sqlite3_step(stmt); int step_status = sqlite3_step(stmt);
if ( step_status == SQLITE_ROW ) { if ( step_status == SQLITE_ROW ) {
if ( parse_value ) { if ( parse_value ) {
if ( sqlite3_column_type(stmt, 1) != SQLITE_NULL && is_expired(sqlite3_column_double(stmt, 1)) )
ret = {ReturnCode::KEY_NOT_FOUND, ""};
else {
auto blob = static_cast<const std::byte*>(sqlite3_column_blob(stmt, 0)); auto blob = static_cast<const std::byte*>(sqlite3_column_blob(stmt, 0));
size_t blob_size = sqlite3_column_bytes(stmt, 0); size_t blob_size = sqlite3_column_bytes(stmt, 0);
@ -527,7 +527,6 @@ OperationResult SQLite::Step(sqlite3_stmt* stmt, bool parse_value) {
else else
ret = {ReturnCode::OPERATION_FAILED, val.error()}; ret = {ReturnCode::OPERATION_FAILED, val.error()};
} }
}
else { else {
ret = {ReturnCode::OPERATION_FAILED, "sqlite3_step should not have returned a value"}; ret = {ReturnCode::OPERATION_FAILED, "sqlite3_step should not have returned a value"};
} }