From 371f9a46e6a2d531e0d83f6c927f373234e8e89b Mon Sep 17 00:00:00 2001 From: xueyunfei Date: Fri, 21 Aug 2020 15:46:29 +0800 Subject: [PATCH] ip4_reass: fix double-free of pbuf fix mr: http://git.savannah.nongnu.org/cgit/lwip.git/commit/?id=0795e289eb2fc3460293d8d9458acdbde6db7475 --- src/core/ipv4/ip4_frag.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/core/ipv4/ip4_frag.c b/src/core/ipv4/ip4_frag.c index fdb20886..807e3714 100644 --- a/src/core/ipv4/ip4_frag.c +++ b/src/core/ipv4/ip4_frag.c @@ -351,8 +351,8 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct /* Extract length and fragment offset from current fragment */ fraghdr = (struct ip_hdr*)new_p->payload; - len = lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; - offset = (lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; + len = (u16_t)(lwip_ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4); + offset = (u16_t)((lwip_ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8); /* overwrite the fragment's ip header from the pbuf with our helper struct, * and setup the embedded helper structure. */ @@ -362,7 +362,11 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct iprh = (struct ip_reass_helper*)new_p->payload; iprh->next_pbuf = NULL; iprh->start = offset; - iprh->end = offset + len; + iprh->end = (u16_t)(offset + len); + if (iprh->end < offset) { + /* u16_t overflow, cannot handle this */ + return IP_REASS_VALIDATE_PBUF_DROPPED; + } /* Iterate through until we either get to the end of the list (append), * or we find one with a larger offset (insert). */ @@ -376,7 +380,7 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct #if IP_REASS_CHECK_OVERLAP if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) { /* fragment overlaps with previous or following, throw away */ - goto freepbuf; + return IP_REASS_VALIDATE_PBUF_DROPPED; } #endif /* IP_REASS_CHECK_OVERLAP */ iprh_prev->next_pbuf = new_p; @@ -389,7 +393,7 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct #if IP_REASS_CHECK_OVERLAP if (iprh->end > iprh_tmp->start) { /* fragment overlaps with following, throw away */ - goto freepbuf; + return IP_REASS_VALIDATE_PBUF_DROPPED; } #endif /* IP_REASS_CHECK_OVERLAP */ /* fragment with the lowest offset */ @@ -398,11 +402,11 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct break; } else if (iprh->start == iprh_tmp->start) { /* received the same datagram twice: no need to keep the datagram */ - goto freepbuf; + return IP_REASS_VALIDATE_PBUF_DROPPED; #if IP_REASS_CHECK_OVERLAP } else if (iprh->start < iprh_tmp->end) { /* overlap: no need to keep the new datagram */ - goto freepbuf; + return IP_REASS_VALIDATE_PBUF_DROPPED; #endif /* IP_REASS_CHECK_OVERLAP */ } else { /* Check if the fragments received so far have no holes. */ @@ -480,12 +484,6 @@ ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct } /* If we come here, not all fragments were received, yet! */ return IP_REASS_VALIDATE_PBUF_QUEUED; /* not yet valid! */ -#if IP_REASS_CHECK_OVERLAP -freepbuf: - ip_reass_pbufcount -= pbuf_clen(new_p); - pbuf_free(new_p); - return IP_REASS_VALIDATE_PBUF_DROPPED; -#endif /* IP_REASS_CHECK_OVERLAP */ } /**