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