netfilter: nf_tables_offload: release flow_rule on error from commit path
authorPablo Neira Ayuso <pablo@netfilter.org>
Thu, 14 Nov 2019 13:17:24 +0000 (14:17 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 15 Nov 2019 22:44:51 +0000 (23:44 +0100)
If hardware offload commit path fails, release all flow_rule objects.

Fixes: c9626a2cbdb2 ("netfilter: nf_tables: add hardware offload support")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nf_tables_offload.c

index 528886b..6d5f3cd 100644 (file)
@@ -422,14 +422,14 @@ int nft_flow_rule_offload_commit(struct net *net)
                                continue;
 
                        if (trans->ctx.flags & NLM_F_REPLACE ||
-                           !(trans->ctx.flags & NLM_F_APPEND))
-                               return -EOPNOTSUPP;
-
+                           !(trans->ctx.flags & NLM_F_APPEND)) {
+                               err = -EOPNOTSUPP;
+                               break;
+                       }
                        err = nft_flow_offload_rule(trans->ctx.chain,
                                                    nft_trans_rule(trans),
                                                    nft_trans_flow_rule(trans),
                                                    FLOW_CLS_REPLACE);
-                       nft_flow_rule_destroy(nft_trans_flow_rule(trans));
                        break;
                case NFT_MSG_DELRULE:
                        if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD))
@@ -442,7 +442,23 @@ int nft_flow_rule_offload_commit(struct net *net)
                }
 
                if (err)
-                       return err;
+                       break;
+       }
+
+       list_for_each_entry(trans, &net->nft.commit_list, list) {
+               if (trans->ctx.family != NFPROTO_NETDEV)
+                       continue;
+
+               switch (trans->msg_type) {
+               case NFT_MSG_NEWRULE:
+                       if (!(trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD))
+                               continue;
+
+                       nft_flow_rule_destroy(nft_trans_flow_rule(trans));
+                       break;
+               default:
+                       break;
+               }
        }
 
        return err;