Browse Source

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.
v2
evgeny 3 weeks ago
parent
commit
a01a4ddba4
  1. 11
      src/chat/chat_sync.c

11
src/chat/chat_sync.c

@ -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);
}

Loading…
Cancel
Save