fixed bug #41041 Potential use-after-free in IPv6 reassembly

This commit is contained in:
Simon Goldschmidt 2014-01-10 21:47:42 +01:00
parent 75f2c56558
commit 381a7b110a
3 changed files with 31 additions and 5 deletions

View File

@ -80,6 +80,9 @@ 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

View File

@ -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);

View File

@ -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? */
@ -456,6 +470,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 +519,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;