ip4_frag/ip6_frag: fix potential NULL-pointer access on memory errors

This commit is contained in:
Simon Goldschmidt 2025-06-03 21:04:39 +02:00
parent 92522e4538
commit 56b29f8bcf
3 changed files with 50 additions and 41 deletions

View File

@ -6,6 +6,11 @@ HISTORY
* [Enter new changes just after this line - do not remove this line] * [Enter new changes just after this line - do not remove this line]
++ Bugfixes:
2025-06-03: Simon Goldschmidt
* ip4_frag/ip6_frag: fix potential NULL-pointer access on memory errors
(STABLE-2.2.1): (STABLE-2.2.1):
++ New features: ++ New features:

View File

@ -175,19 +175,21 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p
MIB2_STATS_INC(mib2.ipreasmfails); MIB2_STATS_INC(mib2.ipreasmfails);
#if LWIP_ICMP #if LWIP_ICMP
iprh = (struct ip_reass_helper *)ipr->p->payload; if (ipr->p != NULL) {
if (iprh->start == 0) { iprh = (struct ip_reass_helper *)ipr->p->payload;
/* The first fragment was received, send ICMP time exceeded. */ if (iprh->start == 0) {
/* First, de-queue the first pbuf from r->p. */ /* The first fragment was received, send ICMP time exceeded. */
p = ipr->p; /* First, de-queue the first pbuf from r->p. */
ipr->p = iprh->next_pbuf; p = ipr->p;
/* Then, copy the original header into it. */ ipr->p = iprh->next_pbuf;
SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN); /* Then, copy the original header into it. */
icmp_time_exceeded(p, ICMP_TE_FRAG); SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);
clen = pbuf_clen(p); icmp_time_exceeded(p, ICMP_TE_FRAG);
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); clen = pbuf_clen(p);
pbufs_freed = (u16_t)(pbufs_freed + clen); LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
pbuf_free(p); pbufs_freed = (u16_t)(pbufs_freed + clen);
pbuf_free(p);
}
} }
#endif /* LWIP_ICMP */ #endif /* LWIP_ICMP */

View File

@ -154,35 +154,37 @@ ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr)
struct ip6_reass_helper *iprh; struct ip6_reass_helper *iprh;
#if LWIP_ICMP6 #if LWIP_ICMP6
iprh = (struct ip6_reass_helper *)ipr->p->payload; if (ipr->p != NULL) {
if (iprh->start == 0) { iprh = (struct ip6_reass_helper *)ipr->p->payload;
/* The first fragment was received, send ICMP time exceeded. */ if (iprh->start == 0) {
/* First, de-queue the first pbuf from r->p. */ /* The first fragment was received, send ICMP time exceeded. */
p = ipr->p; /* First, de-queue the first pbuf from r->p. */
ipr->p = iprh->next_pbuf; p = ipr->p;
/* Restore the part that we've overwritten with our helper structure, or we ipr->p = iprh->next_pbuf;
* might send garbage (and disclose a pointer) in the ICMPv6 reply. */ /* Restore the part that we've overwritten with our helper structure, or we
MEMCPY(p->payload, ipr->orig_hdr, sizeof(*iprh)); * might send garbage (and disclose a pointer) in the ICMPv6 reply. */
/* Then, move back to the original ipv6 header (we are now pointing to Fragment header). MEMCPY(p->payload, ipr->orig_hdr, sizeof(*iprh));
This cannot fail since we already checked when receiving this fragment. */ /* Then, move back to the original ipv6 header (we are now pointing to Fragment header).
if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)ipr->iphdr))) { This cannot fail since we already checked when receiving this fragment. */
LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed", 0); if (pbuf_header_force(p, (s16_t)((u8_t*)p->payload - (u8_t*)ipr->iphdr))) {
LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed", 0);
}
else {
/* Reconstruct the zoned source and destination addresses, so that we do
* not end up sending the ICMP response over the wrong link. */
ip6_addr_t src_addr, dest_addr;
ip6_addr_copy_from_packed(src_addr, IPV6_FRAG_SRC(ipr));
ip6_addr_set_zone(&src_addr, ipr->src_zone);
ip6_addr_copy_from_packed(dest_addr, IPV6_FRAG_DEST(ipr));
ip6_addr_set_zone(&dest_addr, ipr->dest_zone);
/* Send the actual ICMP response. */
icmp6_time_exceeded_with_addrs(p, ICMP6_TE_FRAG, &src_addr, &dest_addr);
}
clen = pbuf_clen(p);
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
pbufs_freed = (u16_t)(pbufs_freed + clen);
pbuf_free(p);
} }
else {
/* Reconstruct the zoned source and destination addresses, so that we do
* not end up sending the ICMP response over the wrong link. */
ip6_addr_t src_addr, dest_addr;
ip6_addr_copy_from_packed(src_addr, IPV6_FRAG_SRC(ipr));
ip6_addr_set_zone(&src_addr, ipr->src_zone);
ip6_addr_copy_from_packed(dest_addr, IPV6_FRAG_DEST(ipr));
ip6_addr_set_zone(&dest_addr, ipr->dest_zone);
/* Send the actual ICMP response. */
icmp6_time_exceeded_with_addrs(p, ICMP6_TE_FRAG, &src_addr, &dest_addr);
}
clen = pbuf_clen(p);
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
pbufs_freed = (u16_t)(pbufs_freed + clen);
pbuf_free(p);
} }
#endif /* LWIP_ICMP6 */ #endif /* LWIP_ICMP6 */