patch 'ethdev: fix flow conversion with null buffer' has been queued to stable release 24.11.9

luca.boccassi at gmail.com luca.boccassi at gmail.com
Thu Nov 5 17:43:06 CET 2026


Hi,

FYI, your patch has been queued to stable release 24.11.9

Note it hasn't been pushed to http://dpdk.org/browse/dpdk-stable yet.
It will be pushed if I get no objections before 11/07/26. So please
shout if anyone has objections.

Also note that after the patch there's a diff of the upstream commit vs the
patch applied to the branch. This will indicate if there was any rebasing
needed to apply to the stable branch. If there were code changes for rebasing
(ie: not only metadata diffs), please double check that the rebase was
correctly done.

Queued patches are on a temporary branch at:
https://github.com/bluca/dpdk-stable

This queued commit can be viewed at:
https://github.com/bluca/dpdk-stable/commit/3eb4af016eb3784104575422fdef6edcc1ed7464

Thanks.

Luca Boccassi

---
>From 3eb4af016eb3784104575422fdef6edcc1ed7464 Mon Sep 17 00:00:00 2001
From: Anatoly Burakov <anatoly.burakov at intel.com>
Date: Tue, 27 Oct 2026 09:50:08 +0000
Subject: [PATCH] ethdev: fix flow conversion with null buffer

[ upstream commit 2ec9682273db70d75a46c253f4f8544adf682cf8 ]

rte_flow_conv_pattern() and rte_flow_conv_actions() document that the
destination buffer may be NULL when the size is zero, which is how
callers query the number of bytes required before allocating. Both
functions nonetheless walked the destination with ++dst in the first
pass and dst -= num before the second, regardless of size.

Pointer arithmetic on a NULL pointer is undefined behavior, and is
reported by UBSan as "applying non-zero offset to null pointer" for
every RTE_FLOW_CONV_OP_PATTERN and RTE_FLOW_CONV_OP_ACTIONS size query.

Keep the destination pointer fixed and index it only inside the
size-guarded writes, which are never reached when size is zero.

Fixes: 063911ee1df4 ("ethdev: add flow API object converter")

Signed-off-by: Anatoly Burakov <anatoly.burakov at intel.com>
---
 lib/ethdev/rte_flow.c | 42 +++++++++++++++++++++++-------------------
 1 file changed, 23 insertions(+), 19 deletions(-)

diff --git a/lib/ethdev/rte_flow.c b/lib/ethdev/rte_flow.c
index e334f26a5ff..ab141194714 100644
--- a/lib/ethdev/rte_flow.c
+++ b/lib/ethdev/rte_flow.c
@@ -843,7 +843,12 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
 	size_t ret;
 	unsigned int i;
 
-	for (i = 0, off = 0; !num || i != num; ++i, ++src, ++dst) {
+	/*
+	 * dst may be NULL when size is zero, so it is only ever indexed
+	 * inside the size-guarded writes below; pointer arithmetic on a
+	 * NULL pointer is undefined behavior.
+	 */
+	for (i = 0, off = 0; !num || i != num; ++i, ++src) {
 		/**
 		 * allow PMD private flow item
 		 */
@@ -854,7 +859,7 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
 				(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, src,
 				 "cannot convert unknown item type");
 		if (size >= off + sizeof(*dst))
-			*dst = (struct rte_flow_item){
+			dst[i] = (struct rte_flow_item){
 				.type = src->type,
 			};
 		off += sizeof(*dst);
@@ -863,8 +868,7 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
 	}
 	num = i;
 	src -= num;
-	dst -= num;
-	do {
+	for (i = 0; i != num; ++i, ++src) {
 		if (src->spec) {
 			off = RTE_ALIGN_CEIL(off, sizeof(double));
 			ret = rte_flow_conv_item_spec
@@ -872,7 +876,7 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
 				 size > off ? size - off : 0, src,
 				 RTE_FLOW_CONV_ITEM_SPEC);
 			if (size && size >= off + ret)
-				dst->spec = (void *)(data + off);
+				dst[i].spec = (void *)(data + off);
 			off += ret;
 
 		}
@@ -883,7 +887,7 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
 				 size > off ? size - off : 0, src,
 				 RTE_FLOW_CONV_ITEM_LAST);
 			if (size && size >= off + ret)
-				dst->last = (void *)(data + off);
+				dst[i].last = (void *)(data + off);
 			off += ret;
 		}
 		if (src->mask) {
@@ -893,12 +897,10 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
 				 size > off ? size - off : 0, src,
 				 RTE_FLOW_CONV_ITEM_MASK);
 			if (size && size >= off + ret)
-				dst->mask = (void *)(data + off);
+				dst[i].mask = (void *)(data + off);
 			off += ret;
 		}
-		++src;
-		++dst;
-	} while (--num);
+	}
 	return off;
 }
 
@@ -936,7 +938,12 @@ rte_flow_conv_actions(struct rte_flow_action *dst,
 	size_t ret;
 	unsigned int i;
 
-	for (i = 0, off = 0; !num || i != num; ++i, ++src, ++dst) {
+	/*
+	 * dst may be NULL when size is zero, so it is only ever indexed
+	 * inside the size-guarded writes below; pointer arithmetic on a
+	 * NULL pointer is undefined behavior.
+	 */
+	for (i = 0, off = 0; !num || i != num; ++i, ++src) {
 		/**
 		 * allow PMD private flow action
 		 */
@@ -947,7 +954,7 @@ rte_flow_conv_actions(struct rte_flow_action *dst,
 				(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
 				 src, "cannot convert unknown action type");
 		if (size >= off + sizeof(*dst))
-			*dst = (struct rte_flow_action){
+			dst[i] = (struct rte_flow_action){
 				.type = src->type,
 			};
 		off += sizeof(*dst);
@@ -956,8 +963,7 @@ rte_flow_conv_actions(struct rte_flow_action *dst,
 	}
 	num = i;
 	src -= num;
-	dst -= num;
-	do {
+	for (i = 0; i != num; ++i, ++src) {
 		if (src->type == RTE_FLOW_ACTION_TYPE_INDIRECT) {
 			/*
 			 * Indirect action conf fills the indirect action
@@ -965,19 +971,17 @@ rte_flow_conv_actions(struct rte_flow_action *dst,
 			 * of duplicating the pointer memory.
 			 */
 			if (size)
-				dst->conf = src->conf;
+				dst[i].conf = src->conf;
 		} else if (src->conf) {
 			off = RTE_ALIGN_CEIL(off, sizeof(double));
 			ret = rte_flow_conv_action_conf
 				((void *)(data + off),
 				 size > off ? size - off : 0, src);
 			if (size && size >= off + ret)
-				dst->conf = (void *)(data + off);
+				dst[i].conf = (void *)(data + off);
 			off += ret;
 		}
-		++src;
-		++dst;
-	} while (--num);
+	}
 	return off;
 }
 
-- 
2.47.3

---
  Diff of the applied patch vs upstream commit (please double-check if non-empty:
---
--- -	2026-11-05 16:42:48.707767533 +0000
+++ 0099-ethdev-fix-flow-conversion-with-null-buffer.patch	2026-11-05 16:42:45.037064252 +0000
@@ -1 +1 @@
-From 2ec9682273db70d75a46c253f4f8544adf682cf8 Mon Sep 17 00:00:00 2001
+From 3eb4af016eb3784104575422fdef6edcc1ed7464 Mon Sep 17 00:00:00 2001
@@ -5,0 +6,2 @@
+[ upstream commit 2ec9682273db70d75a46c253f4f8544adf682cf8 ]
+
@@ -20 +21,0 @@
-Cc: stable at dpdk.org
@@ -28 +29 @@
-index 0ebf59165d..704ed663c5 100644
+index e334f26a5ff..ab141194714 100644
@@ -31 +32 @@
-@@ -921,7 +921,12 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
+@@ -843,7 +843,12 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
@@ -45 +46 @@
-@@ -932,7 +937,7 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
+@@ -854,7 +859,7 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
@@ -54 +55 @@
-@@ -941,8 +946,7 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
+@@ -863,8 +868,7 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
@@ -64 +65 @@
-@@ -950,7 +954,7 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
+@@ -872,7 +876,7 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
@@ -73 +74 @@
-@@ -961,7 +965,7 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
+@@ -883,7 +887,7 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
@@ -82 +83 @@
-@@ -971,12 +975,10 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
+@@ -893,12 +897,10 @@ rte_flow_conv_pattern(struct rte_flow_item *dst,
@@ -97 +98 @@
-@@ -1014,7 +1016,12 @@ rte_flow_conv_actions(struct rte_flow_action *dst,
+@@ -936,7 +938,12 @@ rte_flow_conv_actions(struct rte_flow_action *dst,
@@ -111 +112 @@
-@@ -1025,7 +1032,7 @@ rte_flow_conv_actions(struct rte_flow_action *dst,
+@@ -947,7 +954,7 @@ rte_flow_conv_actions(struct rte_flow_action *dst,
@@ -120 +121 @@
-@@ -1034,8 +1041,7 @@ rte_flow_conv_actions(struct rte_flow_action *dst,
+@@ -956,8 +963,7 @@ rte_flow_conv_actions(struct rte_flow_action *dst,
@@ -130 +131 @@
-@@ -1043,19 +1049,17 @@ rte_flow_conv_actions(struct rte_flow_action *dst,
+@@ -965,19 +971,17 @@ rte_flow_conv_actions(struct rte_flow_action *dst,


More information about the stable mailing list