From 0ec7e807d49a7d845f89f782c5f074883949f228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=AA=E6=98=80=E8=8F=B2?= <15986557+yunfeiwang1228@user.noreply.gitee.com> Date: Tue, 15 Jul 2025 19:50:21 +0800 Subject: [PATCH] ip6_frag and ip4_frag# Signed-off-by: wyf --- CHANGELOG | 5 ++++ src/core/ipv4/ip4_frag.c | 28 ++++++++++--------- src/core/ipv6/ip6_frag.c | 60 +++++++++++++++++++++------------------- 3 files changed, 51 insertions(+), 42 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 90a5834..9c9b34d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,11 @@ HISTORY * [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): ++ New features: diff --git a/src/core/ipv4/ip4_frag.c b/src/core/ipv4/ip4_frag.c index 56b7881..764dc01 100644 --- a/src/core/ipv4/ip4_frag.c +++ b/src/core/ipv4/ip4_frag.c @@ -175,19 +175,21 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p MIB2_STATS_INC(mib2.ipreasmfails); #if LWIP_ICMP - iprh = (struct ip_reass_helper *)ipr->p->payload; - if (iprh->start == 0) { - /* The first fragment was received, send ICMP time exceeded. */ - /* First, de-queue the first pbuf from r->p. */ - p = ipr->p; - ipr->p = iprh->next_pbuf; - /* Then, copy the original header into it. */ - SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN); - icmp_time_exceeded(p, ICMP_TE_FRAG); - clen = pbuf_clen(p); - LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); - pbufs_freed = (u16_t)(pbufs_freed + clen); - pbuf_free(p); + if (ipr->p != NULL) { + iprh = (struct ip_reass_helper *)ipr->p->payload; + if (iprh->start == 0) { + /* The first fragment was received, send ICMP time exceeded. */ + /* First, de-queue the first pbuf from r->p. */ + p = ipr->p; + ipr->p = iprh->next_pbuf; + /* Then, copy the original header into it. */ + SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN); + icmp_time_exceeded(p, ICMP_TE_FRAG); + 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_ICMP */ diff --git a/src/core/ipv6/ip6_frag.c b/src/core/ipv6/ip6_frag.c index b4d62f2..81c3a19 100644 --- a/src/core/ipv6/ip6_frag.c +++ b/src/core/ipv6/ip6_frag.c @@ -174,36 +174,38 @@ ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr) struct ip6_reass_helper *iprh; #if LWIP_ICMP6 - iprh = (struct ip6_reass_helper *)ipr->p->payload; - if (iprh->start == 0) { - /* The first fragment was received, send ICMP time exceeded. */ - /* First, de-queue the first pbuf from r->p. */ - p = ipr->p; - ipr->p = iprh->next_pbuf; - /* Restore the part that we've overwritten with our helper structure, or we - * might send garbage (and disclose a pointer) in the ICMPv6 reply. */ - MEMCPY(p->payload, ipr->orig_hdr, sizeof(*iprh)); - /* Then, move back to the original ipv6 header (we are now pointing to Fragment header). - This cannot fail since we already checked when receiving this fragment. */ - 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); +if (ipr->p != NULL) { + iprh = (struct ip6_reass_helper *)ipr->p->payload; + if (iprh->start == 0) { + /* The first fragment was received, send ICMP time exceeded. */ + /* First, de-queue the first pbuf from r->p. */ + p = ipr->p; + ipr->p = iprh->next_pbuf; + /* Restore the part that we've overwritten with our helper structure, or we + * might send garbage (and disclose a pointer) in the ICMPv6 reply. */ + MEMCPY(p->payload, ipr->orig_hdr, sizeof(*iprh)); + /* Then, move back to the original ipv6 header (we are now pointing to Fragment header). + This cannot fail since we already checked when receiving this fragment. */ + 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); } +} #endif /* LWIP_ICMP6 */ /* First, free all received pbufs. The individual pbufs need to be released -- Gitee