DPDK-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Stephen Hemminger <stephen@networkplumber.org>
To: dev@dpdk.org
Cc: Stephen Hemminger <stephen@networkplumber.org>,
	stable@dpdk.org,
	Sriram Yagnaraman <sriram.yagnaraman@ericsson.com>,
	Jakub Grajciar <jgrajcia@cisco.com>,
	Ferruh Yigit <ferruh.yigit@amd.com>
Subject: [PATCH 5/7] net/memif: validate descriptor length in zero-copy mode
Date: Tue, 22 Sep 2026 12:40:56 -0700	[thread overview]
Message-ID: <20260922194138.508919-6-stephen@networkplumber.org> (raw)
In-Reply-To: <20260922194138.508919-1-stephen@networkplumber.org>

In zero-copy mode the receive buffers are the driver's own mbufs,
and the peer supplies the resulting length. That length needs to
be checked so that buggy/hostile peer doesn't crash server.

Validate the length against the buffer size advertised to the peer.
Read descriptor length once to avoid TOCTOU issues.

An invalid length means the peer is not honoring the contract on a
field whose buffer the driver owns, so nothing else in the ring can
be trusted. Drop the burst and disconnect, as is done for the other
invalid descriptor cases.

This also fixes the packet length of chained zero-copy segments.
memif_pktmbuf_chain() adds the tail data_len while it is still
zero, so a multi-segment packet previously carried only the length
of its first segment.

While here, fix a leak on the existing number-of-segments-overflow
path.

Bugzilla ID: 2018
Fixes: 43b815d88188 ("net/memif: support zero-copy slave")
Cc: stable@dpdk.org

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
Tested-by: Sriram Yagnaraman <sriram.yagnaraman@ericsson.com>
---
 drivers/net/memif/rte_eth_memif.c | 49 ++++++++++++++++++++++++++-----
 1 file changed, 42 insertions(+), 7 deletions(-)

diff --git a/drivers/net/memif/rte_eth_memif.c b/drivers/net/memif/rte_eth_memif.c
index f7be4e4f4b..7dbc80d3b0 100644
--- a/drivers/net/memif/rte_eth_memif.c
+++ b/drivers/net/memif/rte_eth_memif.c
@@ -711,7 +711,11 @@ eth_memif_rx_zc(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	memif_ring_t *ring = memif_get_ring_from_queue(proc_private, mq);
 	uint16_t cur_slot, last_slot, n_slots, ring_size, mask, s0, head;
 	uint16_t n_rx_pkts = 0;
+	/* Buffer size advertised to the peer by the refill loop below. */
+	const uint16_t buf_size = rte_pktmbuf_data_room_size(mq->mempool) -
+		RTE_PKTMBUF_HEADROOM;
 	memif_desc_t *d0;
+	memif_desc_t desc;
 	struct rte_mbuf *mbuf, *mbuf_tail;
 	struct rte_mbuf *mbuf_head = NULL;
 	int ret;
@@ -763,14 +767,31 @@ eth_memif_rx_zc(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 			rte_prefetch0(&ring->desc[(cur_slot + 1) & mask]);
 
 		mbuf->port = mq->in_port;
-		rte_pktmbuf_data_len(mbuf) = d0->length;
-		rte_pktmbuf_pkt_len(mbuf) = rte_pktmbuf_data_len(mbuf);
+		desc = memif_desc_read(d0);
+
+		/* The peer only supplies the length here */
+		if (unlikely(desc.length > buf_size)) {
+			memif_desc_error(mq, &desc, MEMIF_DESC_STATUS_ERR_DATA_TOO_BIG);
+			/* Consume the slot before discarding */
+			cur_slot++;
+			n_slots--;
+			goto discard;
+		}
 
-		mq->n_bytes += rte_pktmbuf_data_len(mbuf);
+		rte_pktmbuf_data_len(mbuf) = desc.length;
+		rte_pktmbuf_pkt_len(mbuf) = desc.length;
+		if (mbuf != mbuf_head)
+			rte_pktmbuf_pkt_len(mbuf_head) += desc.length;
+
+		mq->n_bytes += desc.length;
 
 		cur_slot++;
 		n_slots--;
-		if (d0->flags & MEMIF_DESC_FLAG_NEXT) {
+		if (desc.flags & MEMIF_DESC_FLAG_NEXT) {
+			if (unlikely(n_slots == 0)) {
+				mq->n_err++;
+				goto discard;
+			}
 			s0 = cur_slot & mask;
 			d0 = &ring->desc[s0];
 			mbuf_tail = mbuf;
@@ -778,7 +799,8 @@ eth_memif_rx_zc(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 			ret = memif_pktmbuf_chain(mbuf_head, mbuf_tail, mbuf);
 			if (unlikely(ret < 0)) {
 				MIF_LOG(ERR, "number-of-segments-overflow");
-				goto refill;
+				mq->n_err++;
+				goto discard;
 			}
 			goto next_slot;
 		}
@@ -788,6 +810,17 @@ eth_memif_rx_zc(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	}
 
 	mq->last_tail = cur_slot;
+	goto refill;
+
+discard:
+	/*
+	 * The peer is buggy or hostile, remaining descriptors cannot be trusted.
+	 * Drop the partially built packet and the slots not yet consumed.
+	 */
+	rte_pktmbuf_free(mbuf_head);
+	while (n_slots--)
+		rte_pktmbuf_free_seg(mq->buffers[cur_slot++ & mask]);
+	mq->last_tail = cur_slot;
 
 /* Supply server with new buffers */
 refill:
@@ -820,8 +853,9 @@ eth_memif_rx_zc(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		d0->length = rte_pktmbuf_data_room_size(mq->mempool) -
 				RTE_PKTMBUF_HEADROOM;
 		d0->region = 1;
+		/* Use the constant, the peer can change d0->region at any time. */
 		d0->offset = rte_pktmbuf_mtod(mbuf, uint8_t *) -
-			(uint8_t *)proc_private->regions[d0->region]->addr;
+			(uint8_t *)proc_private->regions[1]->addr;
 	}
 no_free_mbufs:
 	/* The ring->head acts as a guard variable between Tx and Rx
@@ -1096,8 +1130,9 @@ memif_tx_one_zc(struct pmd_process_private *proc_private, struct memif_queue *mq
 	mq->n_bytes += rte_pktmbuf_data_len(mbuf);
 	/* FIXME: get region index */
 	d0->region = 1;
+	/* Use the constant, the peer can change d0->region at any time. */
 	d0->offset = rte_pktmbuf_mtod(mbuf, uint8_t *) -
-		(uint8_t *)proc_private->regions[d0->region]->addr;
+		(uint8_t *)proc_private->regions[1]->addr;
 	d0->flags = 0;
 
 	/* check if buffer is chained */
-- 
2.53.0


  parent reply	other threads:[~2026-09-22 19:42 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-22 19:40 [PATCH 0/7] net/memif: validate input from connecting peer Stephen Hemminger
2026-09-22 19:40 ` [PATCH 1/7] maintainers: update for memif driver Stephen Hemminger
2026-09-22 19:40 ` [PATCH 2/7] net/memif: fix issues in statistics Stephen Hemminger
2026-09-22 19:40 ` [PATCH 3/7] net/memif: validate peer descriptors Stephen Hemminger
2026-09-22 19:40 ` [PATCH 4/7] net/memif: validate control channel requests Stephen Hemminger
2026-09-22 19:40 ` Stephen Hemminger [this message]
2026-09-22 19:40 ` [PATCH 6/7] net/memif: add server/client connectivity test Stephen Hemminger
2026-09-22 19:40 ` [PATCH 7/7] doc: clarify memif secret is not access control Stephen Hemminger
2026-09-24 15:44   ` Stephen Hemminger
2026-09-28 17:56   ` Stephen Hemminger
2026-09-24 11:24 ` [PATCH 0/7] net/memif: validate input from connecting peer Sriram Yagnaraman
2026-09-29 15:42   ` Stephen Hemminger

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260922194138.508919-6-stephen@networkplumber.org \
    --to=stephen@networkplumber.org \
    --cc=dev@dpdk.org \
    --cc=ferruh.yigit@amd.com \
    --cc=jgrajcia@cisco.com \
    --cc=sriram.yagnaraman@ericsson.com \
    --cc=stable@dpdk.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox