Browse Source

lwip_tcp: детект и защита от self-loop (pcb->next==pcb) в tw_pcbs

tcp_slowtmr: после tcp_free проверка pcb==pcb2 → ctx->tw_pcbs=NULL, break
tcp_kill_timewait: проверка inactive->next==inactive → ctx->tw_pcbs=NULL, tcp_free
lwip_tcp_input: проверка pcb->next==pcb перед tcp_timewait_input → tcp_abort
все 3 лога выводят next_owner для диагностики источника self-ссылки
etcp-inflight-fix
Evgeny 4 months ago
parent
commit
a09c647dfd
  1. 19
      src/lwip_tcp/lwip_tcp.c
  2. 8
      src/lwip_tcp/lwip_tcp_in.c

19
src/lwip_tcp/lwip_tcp.c

@ -812,7 +812,15 @@ void tcp_slowtmr(struct lwip_tcp_ctx *ctx)
}
pcb2 = pcb;
pcb = pcb->next;
int self_loop = (pcb == pcb2);
uint8_t sl_owner = pcb2->next_owner;
tcp_free(pcb2);
if (self_loop) {
DEBUG_ERROR(DEBUG_CATEGORY_ALL, "TW_PCBS SELF-LOOP in tcp_slowtmr: freed pcb=%p state=TIME_WAIT port=%u next_owner=%d, clearing tw_pcbs",
(void*)pcb2, pcb2->local_port, sl_owner);
ctx->tw_pcbs = NULL;
break;
}
} else {
prev = pcb;
pcb = pcb->next;
@ -1036,7 +1044,16 @@ static void tcp_kill_timewait(struct lwip_tcp_ctx *ctx)
inactive = pcb;
}
}
if (inactive != NULL) tcp_abort(inactive);
if (inactive != NULL) {
if (inactive->next == inactive) {
DEBUG_ERROR(DEBUG_CATEGORY_ALL, "TW_PCBS SELF-LOOP in tcp_kill_timewait: aborting pcb=%p next_owner=%d, clearing tw_pcbs",
(void*)inactive, inactive->next_owner);
ctx->tw_pcbs = NULL;
tcp_free(inactive);
} else {
tcp_abort(inactive);
}
}
}
static void tcp_handle_closepend(struct lwip_tcp_ctx *ctx)

8
src/lwip_tcp/lwip_tcp_in.c

@ -221,7 +221,13 @@ void lwip_tcp_input(struct lwip_tcp_ctx *ctx, struct pbuf *p,
pcb->local_port == dport &&
pcb->remote_ip == src_ip &&
pcb->local_ip == dst_ip) {
tcp_timewait_input(pcb);
if (pcb->next == pcb) {
DEBUG_ERROR(DEBUG_CATEGORY_ALL, "TW_PCBS SELF-LOOP in lwip_tcp_input: pcb=%p sport=%u dport=%u next_owner=%d, aborting",
(void*)pcb, sport, dport, pcb->next_owner);
tcp_abort(pcb);
} else {
tcp_timewait_input(pcb);
}
pbuf_free(p);
return;
}

Loading…
Cancel
Save