Ensure SQLite allocation failures cannot authorize history deletion

This commit is contained in:
evgeny committed 2026-10-26 18:26:58 +01:00
1 parent 7853fb0fc6
commit aa97e053cd
2 files changed
+23 -3

No files matched your search

+2 -1
View File
@@ -847,7 +847,8 @@ if OS_LINUX
test_db_sync_integrity_SOURCES = test_db_sync_integrity.c
test_db_sync_integrity_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
test_db_sync_integrity_LDADD = $(LIBUTUN) $(CRYPTO_LIBS) $(COMMON_LIBS)
test_db_sync_integrity_LDFLAGS = -Wl,--wrap=EVP_DigestVerifyInit -Wl,--wrap=sqlite3_exec -Wl,--wrap=uasync_set_timeout
test_db_sync_integrity_LDFLAGS = -Wl,--wrap=EVP_DigestVerifyInit -Wl,--wrap=sqlite3_exec -Wl,--wrap=uasync_set_timeout \
-Wl,--wrap=sqlite3_column_blob -Wl,--wrap=sqlite3_errcode
endif
test_merkle_sync_SOURCES = test_merkle_sync.c $(test_clock_sources)
+21 -2
View File
@@ -3,7 +3,7 @@
#include "../src/chat/db_sync.c"
#include <assert.h>
static int fail_verify, fail_commit, fail_timer;
static int fail_verify, fail_commit, fail_timer, fail_blob, blob_nomem;
static unsigned fault_hits;
extern int __real_EVP_DigestVerifyInit(EVP_MD_CTX*, EVP_PKEY_CTX**, const EVP_MD*, ENGINE*, EVP_PKEY*);
int __wrap_EVP_DigestVerifyInit(EVP_MD_CTX* ctx, EVP_PKEY_CTX** pctx, const EVP_MD* md, ENGINE* engine, EVP_PKEY* key) {
@@ -17,6 +17,17 @@ int __wrap_sqlite3_exec(sqlite3* db, const char* sql, int (*cb)(void*, int, char
return __real_sqlite3_exec(db, sql, cb, arg, err);
}
extern const void* __real_sqlite3_column_blob(sqlite3_stmt*, int);
const void* __wrap_sqlite3_column_blob(sqlite3_stmt* stmt, int col) {
if (fail_blob) { fail_blob = 0; blob_nomem = 1; fault_hits++; return NULL; }
return __real_sqlite3_column_blob(stmt, col);
}
extern int __real_sqlite3_errcode(sqlite3*);
int __wrap_sqlite3_errcode(sqlite3* db) {
if (blob_nomem) { blob_nomem = 0; return SQLITE_NOMEM; }
return __real_sqlite3_errcode(db);
}
extern void* __real_uasync_set_timeout(struct UASYNC*, uint64_t, void*, void (*)(void*), const char*);
void* __wrap_uasync_set_timeout(struct UASYNC* ua, uint64_t delay, void* arg, void (*cb)(void*), const char* name) {
if (fail_timer && !strcmp(name, "db_recalc")) { fail_timer = 0; fault_hits++; return NULL; }
@@ -84,10 +95,16 @@ static void test_preservation(void) {
assert(insert(&f, 100, "original", sig) == 0 && insert(&f, 100, "original", sig) == 1);
fail_verify = 1; assert(insert(&f, 100, "original", sig) == -1); intact(&f, "original");
fail_verify = 2; assert(insert(&f, 100, "original", sig) == -1); intact(&f, "original");
fail_blob = 1; assert(insert(&f, 100, "original", sig) == -1); intact(&f, "original");
fail_blob = 1;
assert(si_send_data_batch(&f.si, 2, 0, 1, 0, DB_WANT_FROM_NONE) == -1); intact(&f, "original");
assert(insert(&f, 100, "modified", sig) == -2); intact(&f, "original");
sql(&f, "UPDATE history SET node_id=99");
assert(insert(&f, 100, "original", sig) == -1); intact(&f, "original");
assert(si_send_data_batch(&f.si, 2, 0, 1, 0, DB_WANT_FROM_NONE) == -1); intact(&f, "original");
f.inst.topo_sqlite_db = f.db.db; /* Отказ SQL lookup, в отличие от ещё неизвестного ключа. */
assert(insert(&f, 100, "original", sig) == -1); intact(&f, "original");
f.inst.topo_sqlite_db = NULL;
sql(&f, "UPDATE history SET node_id=1");
fail_verify = 1;
assert(si_send_data_batch(&f.si, 2, 0, 1, 0, DB_WANT_FROM_NONE) == -1); intact(&f, "original");
@@ -134,6 +151,8 @@ static void test_recalc(void) {
struct fixture f; init(&f); uint8_t sig[64];
for (uint64_t ts = 1; ts <= 55; ts++) { sign(&f, ts, "record", sig); assert(insert(&f, ts, "record", sig) == 0); }
uint64_t next = f.si.next_id, hash = 0;
fail_blob = 1;
assert(db_sync_last_chain_hash8(&f.si, &hash) == -1 && db_sync_count(&f.si) == 55 && f.si.recalc.pending);
fail_commit = 1;
assert(db_sync_last_chain_hash8(&f.si, &hash) == -1 && f.si.recalc.pending && f.si.recalc.pos == 0);
assert(sqlite3_get_autocommit(f.db.db));
@@ -172,7 +191,7 @@ int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); debug_set_category_level(DEBUG_CATEGORY_CHAT_SYNC, DEBUG_LEVEL_DEBUG);
size_t baseline = u_get_allocated_count();
test_preservation(); test_deletion(); test_recalc(); test_delivery();
assert(fault_hits == 10 && u_get_allocated_count() == baseline);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "PASS history integrity; injected failures=%u; tracked allocations restored", fault_hits);
assert(fault_hits == 7 && u_get_allocated_count() == baseline);
return 0;
}