netfilter: nf_tables: avoid false-positive lockdep splats with flowtables
authorFlorian Westphal <fw@strlen.de>
Mon, 4 Nov 2024 09:41:15 +0000 (10:41 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 5 Nov 2024 21:06:18 +0000 (22:06 +0100)
The transaction mutex prevents concurrent add/delete, its ok to iterate
those lists outside of rcu read side critical sections.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/net/netfilter/nf_tables.h
net/netfilter/nf_tables_api.c
net/netfilter/nft_flow_offload.c

index 91ae20cb76485b9e81db1928fd5d6489cd400d6a..c1513bd145683409dd1714ad649e71fcc9f488f0 100644 (file)
@@ -1463,7 +1463,8 @@ struct nft_flowtable {
        struct nf_flowtable             data;
 };
 
-struct nft_flowtable *nft_flowtable_lookup(const struct nft_table *table,
+struct nft_flowtable *nft_flowtable_lookup(const struct net *net,
+                                          const struct nft_table *table,
                                           const struct nlattr *nla,
                                           u8 genmask);
 
index a51731d76401cb075c21d471e3338b88659ba68a..9e367e134691810f2ba96b6d3f524fe61356cd2a 100644 (file)
@@ -8378,12 +8378,14 @@ static const struct nla_policy nft_flowtable_policy[NFTA_FLOWTABLE_MAX + 1] = {
        [NFTA_FLOWTABLE_FLAGS]          = { .type = NLA_U32 },
 };
 
-struct nft_flowtable *nft_flowtable_lookup(const struct nft_table *table,
+struct nft_flowtable *nft_flowtable_lookup(const struct net *net,
+                                          const struct nft_table *table,
                                           const struct nlattr *nla, u8 genmask)
 {
        struct nft_flowtable *flowtable;
 
-       list_for_each_entry_rcu(flowtable, &table->flowtables, list) {
+       list_for_each_entry_rcu(flowtable, &table->flowtables, list,
+                               lockdep_commit_lock_is_held(net)) {
                if (!nla_strcmp(nla, flowtable->name) &&
                    nft_active_genmask(flowtable, genmask))
                        return flowtable;
@@ -8739,7 +8741,7 @@ static int nf_tables_newflowtable(struct sk_buff *skb,
                return PTR_ERR(table);
        }
 
-       flowtable = nft_flowtable_lookup(table, nla[NFTA_FLOWTABLE_NAME],
+       flowtable = nft_flowtable_lookup(net, table, nla[NFTA_FLOWTABLE_NAME],
                                         genmask);
        if (IS_ERR(flowtable)) {
                err = PTR_ERR(flowtable);
@@ -8933,7 +8935,7 @@ static int nf_tables_delflowtable(struct sk_buff *skb,
                flowtable = nft_flowtable_lookup_byhandle(table, attr, genmask);
        } else {
                attr = nla[NFTA_FLOWTABLE_NAME];
-               flowtable = nft_flowtable_lookup(table, attr, genmask);
+               flowtable = nft_flowtable_lookup(net, table, attr, genmask);
        }
 
        if (IS_ERR(flowtable)) {
@@ -9003,7 +9005,8 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
        if (!hook_list)
                hook_list = &flowtable->hook_list;
 
-       list_for_each_entry_rcu(hook, hook_list, list) {
+       list_for_each_entry_rcu(hook, hook_list, list,
+                               lockdep_commit_lock_is_held(net)) {
                if (nla_put_string(skb, NFTA_DEVICE_NAME, hook->ops.dev->name))
                        goto nla_put_failure;
        }
@@ -9145,7 +9148,7 @@ static int nf_tables_getflowtable(struct sk_buff *skb,
                return PTR_ERR(table);
        }
 
-       flowtable = nft_flowtable_lookup(table, nla[NFTA_FLOWTABLE_NAME],
+       flowtable = nft_flowtable_lookup(net, table, nla[NFTA_FLOWTABLE_NAME],
                                         genmask);
        if (IS_ERR(flowtable)) {
                NL_SET_BAD_ATTR(extack, nla[NFTA_FLOWTABLE_NAME]);
index 2f732fae5a831e1215dfba87586172806ca76a9b..65199c23c75c5e9ea4ebc1a169122719b3cf4438 100644 (file)
@@ -409,8 +409,8 @@ static int nft_flow_offload_init(const struct nft_ctx *ctx,
        if (!tb[NFTA_FLOW_TABLE_NAME])
                return -EINVAL;
 
-       flowtable = nft_flowtable_lookup(ctx->table, tb[NFTA_FLOW_TABLE_NAME],
-                                        genmask);
+       flowtable = nft_flowtable_lookup(ctx->net, ctx->table,
+                                        tb[NFTA_FLOW_TABLE_NAME], genmask);
        if (IS_ERR(flowtable))
                return PTR_ERR(flowtable);