[PATCH net 1/1] net: openvswitch: reject mismatched flow IDs
From: Ren Wei <hidden>
Date: 2026-07-27 16:52:32
Subsystem:
networking [general], openvswitch, the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Aaron Conole, Eelco Chaudron, Ilya Maximets, Linus Torvalds
From: Zhiling Zou <redacted>
ovs_flow_cmd_new() looks for a duplicate flow before deciding whether the
request should insert a new flow or update an existing one. When the new
request carries a UFID, the function first looks up the UFID, but falls
back to a key lookup if the UFID is not found.
That fallback can find a flow which is identified by a different UFID, or
by its key. The update path then replaces that flow's actions even
though the request identified a different flow. If the caller asked for
an echoed notification, the reply skb was already sized from the request
identifier, but ovs_flow_cmd_fill_info() serializes the matched flow's
identifier. A short request UFID can therefore make the fill fail with
-EMSGSIZE and hit the BUG_ON() in the update path.
Track whether the matched flow was found by the same identifier as the
request, and reject updates where the identifier does not match. This
keeps OVS_FLOW_CMD_NEW from retargeting a different flow and avoids
building a reply for an identifier that the skb was not sized for.
Fixes: 74ed7ab9264c ("openvswitch: Add support for unique flow IDs.")
Cc: stable@vger.kernel.org
Reported-by: Vega <redacted>
Assisted-by: Codex:gpt-5.4
Signed-off-by: Zhiling Zou <redacted>
Signed-off-by: Ren Wei <redacted>
---
net/openvswitch/datapath.c | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index eaf332b156d73..1637420f854d5 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c@@ -1010,6 +1010,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]); int error; bool log = !a[OVS_FLOW_ATTR_PROBE]; + bool id_match = false; /* Must have key and actions. */ error = -EINVAL;
@@ -1075,10 +1076,17 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) } /* Check if this is a duplicate flow */ - if (ovs_identifier_is_ufid(&new_flow->id)) + if (ovs_identifier_is_ufid(&new_flow->id)) { flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id); - if (!flow) + if (flow) + id_match = true; + } + if (!flow) { flow = ovs_flow_tbl_lookup(&dp->table, key); + if (flow) + id_match = ovs_identifier_is_key(&new_flow->id) && + ovs_identifier_is_key(&flow->id); + } if (likely(!flow)) { rcu_assign_pointer(new_flow->sf_acts, acts);
@@ -1113,9 +1121,12 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) error = -EEXIST; goto err_unlock_ovs; } - /* The flow identifier has to be the same for flow updates. - * Look for any overlapping flow. - */ + /* The flow identifier has to be the same for flow updates. */ + if (unlikely(!id_match)) { + error = -ENOENT; + goto err_unlock_ovs; + } + /* Look for any overlapping flow. */ if (unlikely(!ovs_flow_cmp(flow, &match))) { if (ovs_identifier_is_key(&flow->id)) flow = ovs_flow_tbl_lookup_exact(&dp->table,
--
2.43.0