Keep caller transactions intact on invalid receive commit and guard SQLite blob reads
This commit is contained in:
1 parent
797e5d39c4
commit
ddf570c791
2 files changed
+11
-2
No files matched your search
@@ -1236,7 +1236,8 @@ static int member_read_saved(sqlite3* db, const char* ns, uint64_t node, int sta
|
||||
uint8_t* blobs[] = {out->x, out->ed, out->join, out->update, out->owner, out->tree};
|
||||
for (size_t i = 0; i < 6; i++) {
|
||||
int bytes = sqlite3_column_bytes(st, cols[i]);
|
||||
if (bytes == sizes[i]) memcpy(blobs[i], sqlite3_column_blob(st, cols[i]), (size_t)bytes);
|
||||
const void* blob = sqlite3_column_blob(st, cols[i]);
|
||||
if (bytes == sizes[i] && blob) memcpy(blobs[i], blob, (size_t)bytes);
|
||||
else if (bytes || i < 2) out->malformed = 1;
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
@@ -1250,6 +1251,7 @@ static int member_read_saved(sqlite3* db, const char* ns, uint64_t node, int sta
|
||||
.userinfo=out->info,.adm_tags=out->tags,.adm_tags_sig=out->owner,
|
||||
.signed_by=(uint64_t)sqlite3_column_int64(st,9),.signature=out->tree};
|
||||
out->source = sqlite3_column_int(st, 11);
|
||||
if (sqlite3_errcode(db) == SQLITE_NOMEM) rc = SQLITE_NOMEM;
|
||||
}
|
||||
int final = sqlite3_finalize(st);
|
||||
if ((rc != SQLITE_ROW && rc != SQLITE_DONE) || final != SQLITE_OK) {
|
||||
@@ -1403,7 +1405,11 @@ static int member_commit_pull(void* ctx, void* state) {
|
||||
struct UTUN_INSTANCE* inst = ctx; struct member_pull* pull = state; sqlite3* db = _db(inst);
|
||||
char sql[2048]; sqlite3_stmt* st = NULL; const char* stage = "begin";
|
||||
uint64_t* incoming = NULL; size_t count = 0; int result = MT_ERR_IO, rc;
|
||||
if (!sqlite3_get_autocommit(db) || sqlite3_exec(db, "BEGIN IMMEDIATE /* member receive */", NULL, NULL, NULL) != SQLITE_OK) goto fail;
|
||||
if (!sqlite3_get_autocommit(db)) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMBER_SYNC, "member receive commit requires own transaction ch=%s sync=%lld",
|
||||
pull->channel, (long long)pull->id); return MT_ERR_IO;
|
||||
}
|
||||
if (sqlite3_exec(db, "BEGIN IMMEDIATE /* member receive */", NULL, NULL, NULL) != SQLITE_OK) goto fail;
|
||||
stage = "policy";
|
||||
snprintf(sql, sizeof(sql), "SELECT sync_policy FROM peers_%s WHERE id=%lld AND record_state=1", pull->channel, (long long)pull->id);
|
||||
rc = sqlite3_prepare_v2(db, sql, -1, &st, NULL);
|
||||
|
||||
@@ -104,6 +104,9 @@ int main(void) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "PASS two peers: isolated staging, no early profile/hash change, stale completion preserves newer commit");
|
||||
|
||||
profile(&source, 2, 4); a = receive(&source, &target, 2, identities[1].id); b = receive(&source, &target, 2, identities[3].id);
|
||||
assert(sqlite3_exec(target.topo_sqlite_db, "BEGIN", NULL, NULL, NULL) == SQLITE_OK);
|
||||
assert(member_commit_pull(&target, a) == MT_ERR_IO && !sqlite3_get_autocommit(target.topo_sqlite_db));
|
||||
assert(sqlite3_exec(target.topo_sqlite_db, "ROLLBACK", NULL, NULL, NULL) == SQLITE_OK);
|
||||
member_abort_pull(&target, a);
|
||||
assert(scalar(&target, "SELECT COUNT(*) FROM peers_1001 WHERE record_state=1") == 2);
|
||||
finish_receive(&target, b); assert(version(&target) == 4);
|
||||
|
||||
Reference in new issue
Block a user