From: Zhiling Zou <[email protected]>

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: [email protected]
Reported-by: Vega <[email protected]>
Assisted-by: Codex:gpt-5.4
Signed-off-by: Zhiling Zou <[email protected]>
Signed-off-by: Ren Wei <[email protected]>
---
 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
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to