]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
netfilter: nft_set_pipapo: walk over current view on netlink dump
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 17 Sep 2024 20:25:49 +0000 (22:25 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Oct 2024 13:07:36 +0000 (15:07 +0200)
commit 29b359cf6d95fd60730533f7f10464e95bd17c73 upstream.

The generation mask can be updated while netlink dump is in progress.
The pipapo set backend walk iterator cannot rely on it to infer what
view of the datastructure is to be used. Add notation to specify if user
wants to read/update the set.

Based on patch from Florian Westphal.

Fixes: 2b84e215f874 ("netfilter: nft_set_pipapo: .walk does not deal with generations")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
include/net/netfilter/nf_tables.h
net/netfilter/nf_tables_api.c
net/netfilter/nft_set_pipapo.c

index 3cc25a5faa2365d6b920d2591ad292359b94506f..484f9cdf2dd046253045caf8f60ca2b39ba51f60 100644 (file)
@@ -262,9 +262,22 @@ struct nft_set_elem {
        void                    *priv;
 };
 
+/**
+ * enum nft_iter_type - nftables set iterator type
+ *
+ * @NFT_ITER_READ: read-only iteration over set elements
+ * @NFT_ITER_UPDATE: iteration under mutex to update set element state
+ */
+enum nft_iter_type {
+       NFT_ITER_UNSPEC,
+       NFT_ITER_READ,
+       NFT_ITER_UPDATE,
+};
+
 struct nft_set;
 struct nft_set_iter {
        u8              genmask;
+       enum nft_iter_type type:8;
        unsigned int    count;
        unsigned int    skip;
        int             err;
index 249c30c47cbd69761c05857047cc1193d1db0fb1..87c572ba69acbbcb363e0dc4769fff73180f226b 100644 (file)
@@ -594,6 +594,7 @@ static void nft_map_deactivate(const struct nft_ctx *ctx, struct nft_set *set)
 {
        struct nft_set_iter iter = {
                .genmask        = nft_genmask_next(ctx->net),
+               .type           = NFT_ITER_UPDATE,
                .fn             = nft_mapelem_deactivate,
        };
 
@@ -4777,6 +4778,7 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
                }
 
                iter.genmask    = nft_genmask_next(ctx->net);
+               iter.type       = NFT_ITER_UPDATE;
                iter.skip       = 0;
                iter.count      = 0;
                iter.err        = 0;
@@ -4830,6 +4832,7 @@ static void nft_map_activate(const struct nft_ctx *ctx, struct nft_set *set)
 {
        struct nft_set_iter iter = {
                .genmask        = nft_genmask_next(ctx->net),
+               .type           = NFT_ITER_UPDATE,
                .fn             = nft_mapelem_activate,
        };
 
@@ -5142,6 +5145,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
        args.cb                 = cb;
        args.skb                = skb;
        args.iter.genmask       = nft_genmask_cur(net);
+       args.iter.type          = NFT_ITER_READ;
        args.iter.skip          = cb->args[0];
        args.iter.count         = 0;
        args.iter.err           = 0;
@@ -6065,6 +6069,7 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
        if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL) {
                struct nft_set_iter iter = {
                        .genmask        = genmask,
+                       .type           = NFT_ITER_UPDATE,
                        .fn             = nft_flush_set,
                };
                set->ops->walk(&ctx, set, &iter);
index 9e0269e8501799ca18b60456f3dce82f33781557..b30be099fc7f3a8fd7876550d6d497ce7e160537 100644 (file)
@@ -2026,13 +2026,14 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
                            struct nft_set_iter *iter)
 {
        struct nft_pipapo *priv = nft_set_priv(set);
-       struct net *net = read_pnet(&set->net);
        struct nft_pipapo_match *m;
        struct nft_pipapo_field *f;
        int i, r;
 
+       WARN_ON_ONCE(iter->type == NFT_ITER_UNSPEC);
+
        rcu_read_lock();
-       if (iter->genmask == nft_genmask_cur(net))
+       if (iter->type == NFT_ITER_READ)
                m = rcu_dereference(priv->match);
        else
                m = priv->clone;