diff --git a/CHANGELOG b/CHANGELOG index 8f7ce1bd..1681f0ca 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -145,6 +145,15 @@ HISTORY ++ Bugfixes: + 2014-01-10: Simon Goldschmidt + * ip_frag.c, ip6_frag.c: fixed bug #41041 Potential use-after-free in IPv6 reassembly + + 2014-01-10: Simon Goldschmidt + * memp.c: fixed bug #41188 Alignment error in memp_init() when MEMP_SEPARATE_POOLS==1 + + 2014-01-10: Simon Goldschmidt + * tcp.c: fixed bug #39898 tcp_fasttmr() possible lock due to infinte queue process loop + 2013-06-29: Simon Goldschmidt * inet.h, sockets.h: partially fixed bug #37585: IPv6 compatibility (in socket structs) diff --git a/src/core/ipv4/ip_frag.c b/src/core/ipv4/ip_frag.c index 8d184345..ab30623d 100644 --- a/src/core/ipv4/ip_frag.c +++ b/src/core/ipv4/ip_frag.c @@ -481,7 +481,6 @@ ip_reass(struct pbuf *p) struct ip_reass_helper *iprh; u16_t offset, len; u8_t clen; - struct ip_reassdata *ipr_prev = NULL; IPFRAG_STATS_INC(ip_frag.recv); snmp_inc_ipreasmreqds(); @@ -527,7 +526,6 @@ ip_reass(struct pbuf *p) IPFRAG_STATS_INC(ip_frag.cachehit); break; } - ipr_prev = ipr; } if (ipr == NULL) { @@ -565,6 +563,7 @@ ip_reass(struct pbuf *p) /* find the right place to insert this pbuf */ /* @todo: trim pbufs if fragments are overlapping */ if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) { + struct ip_reassdata *ipr_prev; /* the totally last fragment (flag more fragments = 0) was received at least * once AND all fragments are received */ ipr->datagram_len += IP_HLEN; @@ -592,6 +591,14 @@ ip_reass(struct pbuf *p) pbuf_cat(p, r); r = iprh->next_pbuf; } + + /* find the previous entry in the linked list */ + for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr = ipr->next) { + if (ipr_prev->next == ipr) { + break; + } + } + /* release the sources allocate for the fragment queue entry */ ip_reass_dequeue_datagram(ipr, ipr_prev); diff --git a/src/core/ipv6/ip6_frag.c b/src/core/ipv6/ip6_frag.c index 47882d4e..77fdde5a 100644 --- a/src/core/ipv6/ip6_frag.c +++ b/src/core/ipv6/ip6_frag.c @@ -290,7 +290,14 @@ ip6_reass(struct pbuf *p) /* Make room and try again. */ ip6_reass_remove_oldest_datagram(ipr, clen); ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA); - if (ipr == NULL) + if (ipr != NULL) { + /* re-search ipr_prev since it might have been removed */ + for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr = ipr->next) { + if (ipr_prev->next == ipr) { + break; + } + } + } else #endif /* IP_REASS_FREE_OLDEST */ { IP6_FRAG_STATS_INC(ip6_frag.memerr); @@ -322,7 +329,14 @@ ip6_reass(struct pbuf *p) if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { #if IP_REASS_FREE_OLDEST ip6_reass_remove_oldest_datagram(ipr, clen); - if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) + if ((ip6_reass_pbufcount + clen) <= IP_REASS_MAX_PBUFS) { + /* re-search ipr_prev since it might have been removed */ + for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr = ipr->next) { + if (ipr_prev->next == ipr) { + break; + } + } + } else #endif /* IP_REASS_FREE_OLDEST */ { /* @todo: send ICMPv6 time exceeded here? */ @@ -335,6 +349,8 @@ ip6_reass(struct pbuf *p) /* Overwrite Fragment Header with our own helper struct. */ iprh = (struct ip6_reass_helper *)p->payload; + LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN", + sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN); iprh->next_pbuf = NULL; iprh->start = (offset & IP6_FRAG_OFFSET_MASK); iprh->end = (offset & IP6_FRAG_OFFSET_MASK) + len; @@ -456,6 +472,7 @@ ip6_reass(struct pbuf *p) if (valid) { /* All fragments have been received */ + u8_t* iphdr_ptr; /* chain together the pbufs contained within the ip6_reassdata list. */ iprh = (struct ip6_reass_helper*) ipr->p->payload; @@ -504,13 +521,14 @@ ip6_reass(struct pbuf *p) LWIP_ASSERT("sanity check linked list", ipr_prev != NULL); ipr_prev->next = ipr->next; } + iphdr_ptr = (u8_t*)ipr->iphdr; memp_free(MEMP_IP6_REASSDATA, ipr); /* adjust the number of pbufs currently queued for reassembly. */ ip6_reass_pbufcount -= pbuf_clen(p); /* Move pbuf back to IPv6 header. */ - if (pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr)) { + if (pbuf_header(p, (u8_t*)p->payload - iphdr_ptr)) { LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0); pbuf_free(p); return NULL; diff --git a/src/core/memp.c b/src/core/memp.c index 8e4b9226..453ab623 100644 --- a/src/core/memp.c +++ b/src/core/memp.c @@ -371,7 +371,7 @@ memp_init(void) for (i = 0; i < MEMP_MAX; ++i) { memp_tab[i] = NULL; #if MEMP_SEPARATE_POOLS - memp = (struct memp*)memp_bases[i]; + memp = (struct memp*)LWIP_MEM_ALIGN(memp_bases[i]); #endif /* MEMP_SEPARATE_POOLS */ /* create a linked list of memp elements */ for (j = 0; j < memp_num[i]; ++j) { diff --git a/src/core/tcp.c b/src/core/tcp.c index 8690cd24..65fc3c19 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -1112,6 +1112,8 @@ tcp_fasttmr_start: } } pcb = next; + } else { + pcb = pcb->next; } } }