fix: UAF in _on_member_sync_done (channel_cache freed by refresh)

cs_flush_sync passed &cs->channels[i] as member_sync cb_arg, but the 30s
cs_refresh_channels frees/reallocs cs->channels[], leaving the arg
dangling when _session_done later fires the callback. Re-find the channel
by the (stable) ns id instead of trusting arg.
This commit is contained in:
evgeny committed 2026-09-14 15:19:07 +03:00
1 parent 9ee61dce6c
commit a01a4ddba4
1 file changed
+7 -4
+7 -4
View File
@@ -357,7 +357,7 @@ static void cs_flush_sync(struct chat_sync* cs) {
if (pid == myid || !cs_is_peer_online(cs->inst, pid)) continue;
DEBUG_DEBUG(DEBUG_CATEGORY_MEMBER_SYNC, "%s: flush_sync start for peer=%016llx ch=%s",
CS_ID, (unsigned long long)pid, ch->channel_id);
member_sync_start(cs->inst, pid, ch->channel_id, _on_member_sync_done, ch);
member_sync_start(cs->inst, pid, ch->channel_id, _on_member_sync_done, NULL);
}
}
}
@@ -416,9 +416,12 @@ static void cs_resume_db_sync(const char* ch_id) {
}
static void _on_member_sync_done(uint64_t peer, const char* ns, int result, void* arg) {
struct channel_cache* ch = (struct channel_cache*)arg;
if (result == MT_OK && ch) ch->synced = CS_SYNC_DONE;
if (result == MT_OK) cs_resume_db_sync(ns);
(void)arg;
if (result == MT_OK) {
struct channel_cache* ch = g_cs ? cs_find(g_cs, ns) : NULL;
if (ch) ch->synced = CS_SYNC_DONE;
cs_resume_db_sync(ns);
}
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: member_sync %s ns=%s peer=%016llx",
CS_ID, result == MT_OK ? "OK" : "FAIL", ns, (unsigned long long)peer);
}