[PATCH 14/14] gso: fix overflow when writing to very small buffers

Maxime Coquelin maxime.coquelin at redhat.com
Wed Oct 14 17:00:49 CEST 2026


From: Bruce Richardson <bruce.richardson at intel.com>

The gso library never checks that the buffers used for the packet
headers are actually big enough to handle those headers, leading to a
memcpy overflow if the allocated mbuf size is too small. Add some
appropriate checks.

CVE-2026-100236
Bugzilla ID: 2047

Fixes: 119583797b6a ("gso: support TCP/IPv4 GSO")
Cc: stable at dpdk.org

Reported-by: Alexandru-Ionut Jipa <jipaionut at gmail.com>
Acked-by: Maxime Coquelin <maxime.coquelin at redhat.com>
Signed-off-by: Bruce Richardson <bruce.richardson at intel.com>
---
 .mailmap                  |  1 +
 lib/gso/gso_common.c      | 12 ++++++++++++
 lib/gso/gso_tcp4.c        |  5 ++---
 lib/gso/gso_tunnel_tcp4.c |  6 +++---
 lib/gso/gso_tunnel_udp4.c |  4 ++--
 lib/gso/gso_udp4.c        |  5 ++---
 6 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/.mailmap b/.mailmap
index 2e348c3bce..38d89d9e87 100644
--- a/.mailmap
+++ b/.mailmap
@@ -71,6 +71,7 @@ Alexander Skorichenko <askorichenko at netgate.com>
 Alexander Solganik <solganik at gmail.com>
 Alexander V Gutkin <alexander.v.gutkin at intel.com>
 Alexandre Ferrieux <alexandre.ferrieux at orange.com>
+Alexandru-Ionut Jipa <jipaionut at gmail.com>
 Alexey Kardashevskiy <aik at ozlabs.ru>
 Alexey Simakov <bigalex934 at gmail.com>
 Alfredo Cardigliano <cardigliano at ntop.org>
diff --git a/lib/gso/gso_common.c b/lib/gso/gso_common.c
index 378bf2c6aa..481c3b3beb 100644
--- a/lib/gso/gso_common.c
+++ b/lib/gso/gso_common.c
@@ -50,8 +50,20 @@ gso_do_segment(struct rte_mbuf *pkt,
 	struct rte_mbuf *hdr_segment, *pyld_segment, *prev_segment;
 	uint16_t pkt_in_data_pos, segment_bytes_remaining;
 	uint16_t pyld_len, nb_segs;
+	uint16_t direct_buf_size, direct_tailroom;
 	bool more_in_pkt, more_out_segs;
 
+	/*
+	 * The header must be fully contained in pkt's first segment and must fit
+	 * in a freshly allocated direct_pool mbuf.
+	 */
+	direct_buf_size = rte_pktmbuf_data_room_size(direct_pool);
+	if (unlikely(direct_buf_size <= (uint16_t)RTE_PKTMBUF_HEADROOM))
+		return -EINVAL;
+	direct_tailroom = direct_buf_size - RTE_PKTMBUF_HEADROOM;
+	if (unlikely(pkt_hdr_offset > pkt->data_len || pkt_hdr_offset > direct_tailroom))
+		return -EINVAL;
+
 	pkt_in = pkt;
 	nb_segs = 0;
 	more_in_pkt = 1;
diff --git a/lib/gso/gso_tcp4.c b/lib/gso/gso_tcp4.c
index e2ae4aaf6c..d086106355 100644
--- a/lib/gso/gso_tcp4.c
+++ b/lib/gso/gso_tcp4.c
@@ -53,11 +53,10 @@ gso_tcp4_segment(struct rte_mbuf *pkt,
 		return 0;
 	}
 
-	/* Don't process the packet without data */
+	/* Don't process the packet without data or hdr larger than seg size */
 	hdr_offset = pkt->l2_len + pkt->l3_len + pkt->l4_len;
-	if (unlikely(hdr_offset >= pkt->pkt_len)) {
+	if (unlikely(hdr_offset >= pkt->pkt_len || hdr_offset >= gso_size))
 		return 0;
-	}
 
 	pyld_unit_size = gso_size - hdr_offset;
 
diff --git a/lib/gso/gso_tunnel_tcp4.c b/lib/gso/gso_tunnel_tcp4.c
index 3a9159774b..f0d1a6efd6 100644
--- a/lib/gso/gso_tunnel_tcp4.c
+++ b/lib/gso/gso_tunnel_tcp4.c
@@ -77,10 +77,10 @@ gso_tunnel_tcp4_segment(struct rte_mbuf *pkt,
 	}
 
 	hdr_offset += pkt->l3_len + pkt->l4_len;
-	/* Don't process the packet without data */
-	if (hdr_offset >= pkt->pkt_len) {
+	/* Don't process the packet without data or hdr larger than seg size */
+	if (hdr_offset >= pkt->pkt_len || hdr_offset >= gso_size)
 		return 0;
-	}
+
 	pyld_unit_size = gso_size - hdr_offset;
 
 	/* Segment the payload */
diff --git a/lib/gso/gso_tunnel_udp4.c b/lib/gso/gso_tunnel_udp4.c
index 4fb275484c..43e4103bc7 100644
--- a/lib/gso/gso_tunnel_udp4.c
+++ b/lib/gso/gso_tunnel_udp4.c
@@ -78,8 +78,8 @@ gso_tunnel_udp4_segment(struct rte_mbuf *pkt,
 		return 0;
 
 	hdr_offset += pkt->l3_len;
-	/* Don't process the packet without data */
-	if ((hdr_offset + pkt->l4_len) >= pkt->pkt_len)
+	/* Don't process the packet without data or hdrs larger than seg size */
+	if ((hdr_offset + pkt->l4_len) >= pkt->pkt_len || hdr_offset >= gso_size)
 		return 0;
 
 	/* pyld_unit_size must be a multiple of 8 because frag_off
diff --git a/lib/gso/gso_udp4.c b/lib/gso/gso_udp4.c
index 5d0186aa24..e2ec84759d 100644
--- a/lib/gso/gso_udp4.c
+++ b/lib/gso/gso_udp4.c
@@ -62,10 +62,9 @@ gso_udp4_segment(struct rte_mbuf *pkt,
 	 */
 	hdr_offset = pkt->l2_len + pkt->l3_len;
 
-	/* Don't process the packet without data. */
-	if (unlikely(hdr_offset + pkt->l4_len >= pkt->pkt_len)) {
+	/* Don't process the packet without data or header larger than seg size. */
+	if (unlikely(hdr_offset + pkt->l4_len >= pkt->pkt_len || hdr_offset >= gso_size))
 		return 0;
-	}
 
 	/* pyld_unit_size must be a multiple of 8 because frag_off
 	 * uses 8 bytes as unit.
-- 
2.56.0



More information about the dev mailing list