diff --git a/src/transport_layer/etcp.c b/src/transport_layer/etcp.c index bcc79ebf..87b22ecd 100644 --- a/src/transport_layer/etcp.c +++ b/src/transport_layer/etcp.c @@ -1410,7 +1410,7 @@ void etcp_ack_recv(struct ETCP_CONN* etcp, uint32_t seq, uint16_t ts, uint16_t d } // === subtract inflight from the LAST link the packet was sent on === - if (acked_pkt->last_link) { + if (acked_pkt->last_link && acked_pkt->last_link->bbr) { struct ETCP_LINK* link = acked_pkt->last_link; link->inflight_bytes -= acked_pkt->ll.len; link->inflight_packets--; diff --git a/src/transport_layer/etcp_connections.c b/src/transport_layer/etcp_connections.c index 6fa82285..02a692a4 100644 --- a/src/transport_layer/etcp_connections.c +++ b/src/transport_layer/etcp_connections.c @@ -1074,6 +1074,18 @@ void etcp_link_update_inflight_lim(struct ETCP_LINK* link, uint32_t new_lim) { etcp_conn_on_inflight_lim_changed(link->etcp); } +// Обнуляет last_link для всех inflight-записей ссылающихся на dead_link. +// Вызывается перед u_free(link) чтобы etcp_ack_recv не упал на use-after-free. +static void etcp_inflight_nullify_link(struct ll_queue* q, struct ETCP_LINK* dead_link) { + if (!q) return; + struct ll_entry* entry = q->head; + while (entry) { + struct INFLIGHT_PACKET* inf = (struct INFLIGHT_PACKET*)entry->data; + if (inf->last_link == dead_link) inf->last_link = NULL; + entry = entry->next; + } +} + void etcp_link_close(struct ETCP_LINK* link) { DEBUG_TRACE(DEBUG_CATEGORY_CONNECTION, ""); if (!link) return; @@ -1096,6 +1108,7 @@ void etcp_link_close(struct ETCP_LINK* link) { if (link->shaper_timer) uasync_cancel_timeout(link->etcp->instance->ua, link->shaper_timer); if (link->keepalive_timer) uasync_cancel_timeout(link->etcp->instance->ua, link->keepalive_timer); etcp_conn_on_inflight_lim_changed(link->etcp); + u_free(link->bbr); u_free(link); return; } @@ -1136,6 +1149,8 @@ void etcp_link_close(struct ETCP_LINK* link) { link->etcp->log_name, link->local_link_id, sockaddr_storage_to_str(&link->remote_addr).str, link->total_decrypted, (unsigned long long)link->acked_bytes, link->inflight_bytes, link->inflight_packets); etcp_fire_link_status_cbk(link, link->link_state, link->link_status); + etcp_inflight_nullify_link(link->etcp->input_wait_ack, link); + etcp_inflight_nullify_link(link->etcp->input_send_q, link); u_free(link->bbr); u_free(link); }