]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: openvswitch: fix skb leak on flow key update failure during recirculation
authorIlya Maximets <i.maximets@ovn.org>
Mon, 27 Jul 2026 18:18:30 +0000 (20:18 +0200)
committerJakub Kicinski <kuba@kernel.org>
Thu, 30 Jul 2026 00:42:33 +0000 (17:42 -0700)
do_execute_actions() returns right away when execute_recirc() fails on
the last action as it assumes this function always takes ownership of
the skb when 'last' is true.  But when the flow key update fails, the
function doesn't free the skb and it ends up leaked.

This is a very unlikely scenario as it requires the packet to become
unparseable by applying a set of actions on a previously parseable skb,
but should be fixed nevertheless.

Reported by Sashiko.

Fixes: 971427f353f3 ("openvswitch: Add recirc and hash action.")
Cc: stable@vger.kernel.org
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
Reviewed-by: Aaron Conole <aconole@redhat.com>
Link: https://patch.msgid.link/20260727181851.306076-2-i.maximets@ovn.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/openvswitch/actions.c

index 513fca6a8e8a48020e72729ade945ffcd13266e3..0118fe3b35e4bd30ae07b9f1ad1924b8f18ce8db 100644 (file)
@@ -1108,6 +1108,10 @@ static int execute_masked_set_action(struct sk_buff *skb,
        return err;
 }
 
+/* When 'last' is true, recirc() should always consume the 'skb'.
+ * Otherwise, recirc() should keep 'skb' intact regardless what
+ * actions are executed on recirculation.
+ */
 static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
                          struct sw_flow_key *key,
                          const struct nlattr *a, bool last)
@@ -1118,8 +1122,12 @@ static int execute_recirc(struct datapath *dp, struct sk_buff *skb,
                int err;
 
                err = ovs_flow_key_update(skb, key);
-               if (err)
+               if (err) {
+                       if (last)
+                               ovs_kfree_skb_reason(skb,
+                                                    OVS_DROP_ACTION_ERROR);
                        return err;
+               }
        }
        BUG_ON(!is_flow_key_valid(key));