Instrument channel creation SQL and hash committed schema, identities and roots

This commit is contained in:
evgeny committed 2026-10-27 04:40:36 +01:00
1 parent 60942e542b
commit 1d84765f08
2 files changed
+94 -1

No files matched your search

+3 -1
View File
@@ -314,7 +314,9 @@ test_chat_setting_LDADD = $(LIBUTUN) $(COMMON_LIBS)
test_chat_setting_LDFLAGS = -Wl,--wrap=chat_local_apply_settings
test_chat_channel_SOURCES = test_chat_channel.c
test_chat_channel_LDADD = $(LIBUTUN) $(COMMON_LIBS)
test_chat_channel_LDFLAGS = -Wl,--wrap=EVP_DigestSign -Wl,--wrap=sqlite3_bind_blob
test_chat_channel_LDFLAGS = -Wl,--wrap=EVP_DigestSign -Wl,--wrap=sqlite3_exec -Wl,--wrap=sqlite3_prepare_v2 \
-Wl,--wrap=sqlite3_bind_blob -Wl,--wrap=sqlite3_bind_text -Wl,--wrap=sqlite3_bind_int64 -Wl,--wrap=sqlite3_bind_null \
-Wl,--wrap=sqlite3_step -Wl,--wrap=sqlite3_changes -Wl,--wrap=sqlite3_finalize -Wl,--wrap=u_malloc_impl
else
test_socket_monitor_LDFLAGS += -Wl,--wrap=read
endif
+91
View File
@@ -9,6 +9,7 @@
#include "../src/chat/chat_event.h"
#include "../src/chat/member_sync.h"
#include "../src/routing_layer/topo_node_sqlite.h"
#include "../src/routing_layer/topo_group.h"
#include "../lib/platform_compat.h"
#include "../lib/debug_config.h"
#include "../lib/mem.h"
@@ -17,6 +18,33 @@ static unsigned fail_sign_number, channel_events;
static struct UTUN_INSTANCE* active;
static sqlite3* reader;
static int fail_profile_binding;
enum sql_fault { Q_NONE, Q_PREPARE, Q_BIND, Q_STEP, Q_CHANGES, Q_FINALIZE, Q_EXEC, Q_ALLOCATE };
static enum sql_fault sql_fault;
static const char *sql_prefix, *sql_suffix;
static int sql_bind, allocations_until_failure, failed_rollback, last_target;
static int sql_target(const char* sql) {
return sql_prefix && !strncmp(sql, sql_prefix, strlen(sql_prefix)) && (!sql_suffix || strstr(sql, sql_suffix));
}
static int take_sql(enum sql_fault point, const char* sql, int index) {
if (sql_fault != point || (sql && !sql_target(sql)) || (point == Q_BIND && index != sql_bind)) return 0;
sql_fault = Q_NONE;
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "channel test: SQL fault stage=%d bind=%d", point, index); return 1;
}
extern int __real_sqlite3_exec(sqlite3*, const char*, int (*)(void*, int, char**, char**), void*, char**);
int __wrap_sqlite3_exec(sqlite3* db, const char* sql, int (*cb)(void*, int, char**, char**), void* arg, char** error) {
if (failed_rollback && !strcmp(sql, "ROLLBACK")) {
failed_rollback = 0; DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "channel test: rollback failed"); return SQLITE_IOERR;
}
if (take_sql(Q_EXEC, sql, 0)) return SQLITE_IOERR;
return __real_sqlite3_exec(db, sql, cb, arg, error);
}
extern int __real_sqlite3_prepare_v2(sqlite3*, const char*, int, sqlite3_stmt**, const char**);
int __wrap_sqlite3_prepare_v2(sqlite3* db, const char* sql, int length, sqlite3_stmt** st, const char** tail) {
if (take_sql(Q_PREPARE, sql, 0)) { *st = NULL; return SQLITE_NOMEM; }
return __real_sqlite3_prepare_v2(db, sql, length, st, tail);
}
extern int __real_sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int, void (*)(void*));
int __wrap_sqlite3_bind_blob(sqlite3_stmt* st, int index, const void* value, int length, void (*destroy)(void*)) {
@@ -25,8 +53,71 @@ int __wrap_sqlite3_bind_blob(sqlite3_stmt* st, int index, const void* value, int
fail_profile_binding = 0; DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "channel test: injected root profile signature bind failure");
return SQLITE_NOMEM;
}
if (take_sql(Q_BIND, sqlite3_sql(st), index)) return SQLITE_NOMEM;
return __real_sqlite3_bind_blob(st, index, value, length, destroy);
}
extern int __real_sqlite3_bind_text(sqlite3_stmt*, int, const char*, int, void (*)(void*));
int __wrap_sqlite3_bind_text(sqlite3_stmt* st, int index, const char* value, int length, void (*destroy)(void*)) {
if (take_sql(Q_BIND, sqlite3_sql(st), index)) return SQLITE_NOMEM;
return __real_sqlite3_bind_text(st, index, value, length, destroy);
}
extern int __real_sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
int __wrap_sqlite3_bind_int64(sqlite3_stmt* st, int index, sqlite3_int64 value) {
if (take_sql(Q_BIND, sqlite3_sql(st), index)) return SQLITE_NOMEM;
return __real_sqlite3_bind_int64(st, index, value);
}
extern int __real_sqlite3_bind_null(sqlite3_stmt*, int);
int __wrap_sqlite3_bind_null(sqlite3_stmt* st, int index) {
if (take_sql(Q_BIND, sqlite3_sql(st), index)) return SQLITE_NOMEM;
return __real_sqlite3_bind_null(st, index);
}
extern int __real_sqlite3_step(sqlite3_stmt*);
int __wrap_sqlite3_step(sqlite3_stmt* st) {
const char* sql = sqlite3_sql(st); last_target = sql_target(sql);
if (take_sql(Q_STEP, sql, 0)) return SQLITE_IOERR;
return __real_sqlite3_step(st);
}
extern int __real_sqlite3_changes(sqlite3*);
int __wrap_sqlite3_changes(sqlite3* db) {
if (last_target && take_sql(Q_CHANGES, NULL, 0)) return 0;
return __real_sqlite3_changes(db);
}
extern int __real_sqlite3_finalize(sqlite3_stmt*);
int __wrap_sqlite3_finalize(sqlite3_stmt* st) {
int fail = st && take_sql(Q_FINALIZE, sqlite3_sql(st), 0);
int rc = __real_sqlite3_finalize(st); return fail ? SQLITE_IOERR : rc;
}
extern void* __real_u_malloc_impl(uint32_t, const char*);
void* __wrap_u_malloc_impl(uint32_t size, const char* location) {
if (sql_fault == Q_ALLOCATE && strstr(location, "topo_node_sqlite.c") && !--allocations_until_failure) {
sql_fault = Q_NONE; DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "channel test: schema allocation failed bytes=%u", size); return NULL;
}
return __real_u_malloc_impl(size, location);
}
/* Проверяем логические bytes описаний,всей схемы и Merkle через независимое соединение. */
static void snapshot(sqlite3* db, uint8_t out[32]) {
const char* queries[] = {
"SELECT channel_id,name,owner_node_id,x25519_pubkey,x25519_privkey,ed25519_pubkey,ed25519_privkey,signature FROM channels ORDER BY channel_id",
"SELECT namespace,level,prefix64,hash FROM merkle_tree_hash ORDER BY namespace,level,prefix64",
"SELECT type,name,tbl_name,sql FROM sqlite_master ORDER BY type,name"
};
EVP_MD_CTX* hash = EVP_MD_CTX_new(); assert(hash && EVP_DigestInit_ex(hash, EVP_sha256(), NULL) == 1);
for (unsigned query = 0; query < sizeof(queries) / sizeof(queries[0]); query++) {
assert(EVP_DigestUpdate(hash, &query, sizeof(query)) == 1); sqlite3_stmt* st = NULL;
assert(sqlite3_prepare_v2(db, queries[query], -1, &st, NULL) == SQLITE_OK); int rc;
while ((rc = sqlite3_step(st)) == SQLITE_ROW) {
for (int column = 0; column < sqlite3_column_count(st); column++) {
int type = sqlite3_column_type(st, column), bytes = sqlite3_column_bytes(st, column);
const void* value = sqlite3_column_blob(st, column); assert(!bytes || value);
assert(EVP_DigestUpdate(hash, &type, sizeof(type)) == 1 && EVP_DigestUpdate(hash, &bytes, sizeof(bytes)) == 1);
if (bytes) assert(EVP_DigestUpdate(hash, value, (size_t)bytes) == 1);
}
}
assert(rc == SQLITE_DONE && sqlite3_finalize(st) == SQLITE_OK);
}
unsigned length; assert(EVP_DigestFinal_ex(hash, out, &length) == 1 && length == 32); EVP_MD_CTX_free(hash);
}
extern int __real_EVP_DigestSign(EVP_MD_CTX*, unsigned char*, size_t*, const unsigned char*, size_t);
int __wrap_EVP_DigestSign(EVP_MD_CTX* ctx, unsigned char* signature, size_t* length, const unsigned char* data, size_t size) {