mirror of
https://git.savannah.nongnu.org/git/lwip.git
synced 2026-08-10 17:43:39 +08:00
Fixed bug #27871: Calling tcp_abort() in recv callback can lead to accessing unallocated memory. As a consequence, ERR_ABRT means the application has called tcp_abort()!
This commit is contained in:
@@ -760,20 +760,21 @@ tcp_slowtmr(void)
|
||||
memp_free(MEMP_TCP_PCB, pcb);
|
||||
pcb = pcb2;
|
||||
} else {
|
||||
|
||||
/* We check if we should poll the connection. */
|
||||
++pcb->polltmr;
|
||||
if (pcb->polltmr >= pcb->pollinterval) {
|
||||
pcb->polltmr = 0;
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
|
||||
TCP_EVENT_POLL(pcb, err);
|
||||
if (err == ERR_OK) {
|
||||
tcp_output(pcb);
|
||||
}
|
||||
}
|
||||
|
||||
/* get the 'next' element now and work with 'prev' below (in case of abort) */
|
||||
prev = pcb;
|
||||
pcb = pcb->next;
|
||||
|
||||
/* We check if we should poll the connection. */
|
||||
++prev->polltmr;
|
||||
if (prev->polltmr >= prev->pollinterval) {
|
||||
prev->polltmr = 0;
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
|
||||
TCP_EVENT_POLL(prev, err);
|
||||
/* if err == ERR_ABRT, 'prev' is already deallocated */
|
||||
if (err == ERR_OK) {
|
||||
tcp_output(prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -823,9 +824,10 @@ tcp_slowtmr(void)
|
||||
void
|
||||
tcp_fasttmr(void)
|
||||
{
|
||||
struct tcp_pcb *pcb;
|
||||
struct tcp_pcb *pcb = tcp_active_pcbs;
|
||||
|
||||
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
|
||||
while(pcb != NULL) {
|
||||
struct tcp_pcb *next = pcb->next;
|
||||
/* If there is data which was previously "refused" by upper layer */
|
||||
if (pcb->refused_data != NULL) {
|
||||
/* Notify again application with data previously received. */
|
||||
@@ -834,16 +836,21 @@ tcp_fasttmr(void)
|
||||
TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
|
||||
if (err == ERR_OK) {
|
||||
pcb->refused_data = NULL;
|
||||
} else if (err == ERR_ABRT) {
|
||||
/* if err == ERR_ABRT, 'pcb' is already deallocated */
|
||||
pcb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* send delayed ACKs */
|
||||
if (pcb->flags & TF_ACK_DELAY) {
|
||||
if (pcb && (pcb->flags & TF_ACK_DELAY)) {
|
||||
LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));
|
||||
tcp_ack_now(pcb);
|
||||
tcp_output(pcb);
|
||||
pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
|
||||
}
|
||||
|
||||
pcb = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -280,6 +280,7 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
if (err == ERR_OK) {
|
||||
pcb->refused_data = NULL;
|
||||
} else {
|
||||
/* if err == ERR_ABRT, 'pcb' is already deallocated */
|
||||
/* drop incoming packets, because pcb is "full" */
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
|
||||
TCP_STATS_INC(tcp.drop);
|
||||
@@ -313,8 +314,11 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
now. */
|
||||
if (pcb->acked > 0) {
|
||||
TCP_EVENT_SENT(pcb, pcb->acked, err);
|
||||
if (err == ERR_ABRT) {
|
||||
goto aborted;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (recv_data != NULL) {
|
||||
if(flags & TCP_PSH) {
|
||||
recv_data->flags |= PBUF_FLAG_PUSH;
|
||||
@@ -322,6 +326,9 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
|
||||
/* Notify application that data has been received. */
|
||||
TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
|
||||
if (err == ERR_ABRT) {
|
||||
goto aborted;
|
||||
}
|
||||
|
||||
/* If the upper layer can't receive this data, store it */
|
||||
if (err != ERR_OK) {
|
||||
@@ -334,6 +341,9 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
function with a NULL buffer to indicate EOF. */
|
||||
if (recv_flags & TF_GOT_FIN) {
|
||||
TCP_EVENT_RECV(pcb, NULL, ERR_OK, err);
|
||||
if (err == ERR_ABRT) {
|
||||
goto aborted;
|
||||
}
|
||||
}
|
||||
|
||||
tcp_input_pcb = NULL;
|
||||
@@ -346,6 +356,9 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
#endif /* TCP_INPUT_DEBUG */
|
||||
}
|
||||
}
|
||||
/* Jump target if pcb has been aborted in a callback (by calling tcp_abort()).
|
||||
Below this line, 'pcb' may not be dereferenced! */
|
||||
aborted:
|
||||
tcp_input_pcb = NULL;
|
||||
|
||||
|
||||
@@ -616,6 +629,9 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
/* Call the user specified function to call when sucessfully
|
||||
* connected. */
|
||||
TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
|
||||
if (err == ERR_ABRT) {
|
||||
return ERR_ABRT;
|
||||
}
|
||||
tcp_ack_now(pcb);
|
||||
}
|
||||
/* received ACK? possibly a half-open connection */
|
||||
@@ -640,7 +656,10 @@ tcp_process(struct tcp_pcb *pcb)
|
||||
if (err != ERR_OK) {
|
||||
/* If the accept function returns with an error, we abort
|
||||
* the connection. */
|
||||
tcp_abort(pcb);
|
||||
/* Already aborted? */
|
||||
if (err != ERR_ABRT) {
|
||||
tcp_abort(pcb);
|
||||
}
|
||||
return ERR_ABRT;
|
||||
}
|
||||
old_cwnd = pcb->cwnd;
|
||||
|
||||
Reference in New Issue
Block a user