Browse Source

chat: fix use-after-free in invite_candidates trampoline + accept JOIN_INFO_RESP/READY/ERROR for unknown channels

proxy
evgeny 2 weeks ago
parent
commit
39a1da4c28
  1. 3
      src/chat/chat_sync.c
  2. 9
      src/chat/invite_build.c
  3. 15
      tools/chatgui/stress_restart.sh

3
src/chat/chat_sync.c

@ -210,7 +210,8 @@ static void chat_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) {
if (cs_group_id_to_ch_id(cs->inst, group_id, ch_id, sizeof(ch_id)) != 0) { if (cs_group_id_to_ch_id(cs->inst, group_id, ch_id, sizeof(ch_id)) != 0) {
/* CHANNEL_INVITE/JOIN_INFO_REQ приходят для ещё не созданного у нас канала: /* CHANNEL_INVITE/JOIN_INFO_REQ приходят для ещё не созданного у нас канала:
group_id == channel_id (numeric), поэтому выводим ch_id напрямую. */ group_id == channel_id (numeric), поэтому выводим ch_id напрямую. */
if (type == CS_MSG_CHANNEL_INVITE || type == CS_MSG_JOIN_INFO_REQ || type == CS_MSG_JOIN_REQUEST) { if (type == CS_MSG_CHANNEL_INVITE || type == CS_MSG_JOIN_INFO_REQ || type == CS_MSG_JOIN_INFO_RESP ||
type == CS_MSG_JOIN_REQUEST || type == CS_MSG_JOIN_READY || type == CS_MSG_ERROR) {
snprintf(ch_id, sizeof(ch_id), "%llu", (unsigned long long)group_id); snprintf(ch_id, sizeof(ch_id), "%llu", (unsigned long long)group_id);
} else { } else {
u_free(entry->dgram); queue_entry_free(entry); return; u_free(entry->dgram); queue_entry_free(entry); return;

9
src/chat/invite_build.c

@ -405,17 +405,18 @@ int chat_invite_candidate_nodes(struct UTUN_INSTANCE* inst, uint64_t channel_id,
void chat_invite_candidates_trampoline(void* arg) { void chat_invite_candidates_trampoline(void* arg) {
struct chat_invite_cand_req* req = (struct chat_invite_cand_req*)arg; struct chat_invite_cand_req* req = (struct chat_invite_cand_req*)arg;
if (!req) return; if (!req) return;
struct UTUN_INSTANCE* inst = req->inst;
char ch_id[64]; char ch_id[64];
strncpy(ch_id, req->ch_id, sizeof(ch_id) - 1); strncpy(ch_id, req->ch_id, sizeof(ch_id) - 1);
ch_id[sizeof(ch_id) - 1] = '\0'; ch_id[sizeof(ch_id) - 1] = '\0';
u_free(arg); u_free(arg);
if (!CC(req->inst) || !CC(req->inst)->initialized) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "invite_build: candidates — not initialized"); return; } if (!CC(inst) || !CC(inst)->initialized) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "invite_build: candidates — not initialized"); return; }
uint64_t channel_id = strtoull(ch_id, NULL, 10); uint64_t channel_id = strtoull(ch_id, NULL, 10);
uint64_t auto_id = 0; uint64_t auto_id = 0;
chat_invite_best_node(req->inst, channel_id, &auto_id); chat_invite_best_node(inst, channel_id, &auto_id);
uint64_t ids[INVITE_ADDR_MAX]; uint64_t ids[INVITE_ADDR_MAX];
int cnt = chat_invite_candidate_nodes(req->inst, channel_id, ids, INVITE_ADDR_MAX); int cnt = chat_invite_candidate_nodes(inst, channel_id, ids, INVITE_ADDR_MAX);
if (cnt < 0) cnt = 0; if (cnt < 0) cnt = 0;
size_t ch_len = strlen(ch_id); size_t ch_len = strlen(ch_id);
@ -428,7 +429,7 @@ void chat_invite_candidates_trampoline(void* arg) {
uint16_t u16 = (uint16_t)cnt; uint16_t u16 = (uint16_t)cnt;
memcpy(evt + 1 + ch_len + 8, &u16, 2); memcpy(evt + 1 + ch_len + 8, &u16, 2);
for (int i = 0; i < cnt; i++) memcpy(evt + 1 + ch_len + 8 + 2 + i * 8, &ids[i], 8); for (int i = 0; i < cnt; i++) memcpy(evt + 1 + ch_len + 8 + 2 + i * 8, &ids[i], 8);
chat_event_post(req->inst, CHAT_EVT_INVITE_CANDIDATES, evt, (int)evt_sz); chat_event_post(inst, CHAT_EVT_INVITE_CANDIDATES, evt, (int)evt_sz);
u_free(evt); u_free(evt);
} }

15
tools/chatgui/stress_restart.sh

@ -0,0 +1,15 @@
#!/bin/bash
set -u
cd "$(dirname "$0")/build" || exit 1
export DISPLAY="${DISPLAY:-:0}"
rnd() { local m=$((200 + RANDOM % 2801)) f; printf -v f '%03d' $((m%1000)); sleep "$((m/1000)).$f"; }
while :; do
env DISPLAY="$DISPLAY" QT_ACCESSIBILITY=1 ./vibechat >/dev/null 2>&1 &
p=$!
rnd
(( RANDOM % 2 )) && kill -9 "$p" || kill -HUP "$p"
wait "$p" 2>/dev/null
rnd
done
Loading…
Cancel
Save