From: Zhiling Zou 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 Assisted-by: Codex:gpt-5.4 Signed-off-by: Zhiling Zou Signed-off-by: Ren Wei --- 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