]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 16 Jul 2023 19:22:47 +0000 (21:22 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 16 Jul 2023 19:22:47 +0000 (21:22 +0200)
added patches:
netfilter-nf_tables-add-nft_trans_prepare_error-to-deal-with-bound-set-chain.patch
netfilter-nf_tables-add-rescheduling-points-during-loop-detection-walks.patch
netfilter-nf_tables-drop-map-element-references-from-preparation-phase.patch
netfilter-nf_tables-fix-chain-binding-transaction-logic.patch
netfilter-nf_tables-fix-scheduling-while-atomic-splat.patch
netfilter-nf_tables-incorrect-error-path-handling-with-nft_msg_newrule.patch
netfilter-nf_tables-reject-unbound-anonymous-set-before-commit-phase.patch
netfilter-nf_tables-reject-unbound-chain-set-before-commit-phase.patch
netfilter-nf_tables-unbind-non-anonymous-set-if-rule-construction-fails.patch
netfilter-nf_tables-use-net_generic-infra-for-transaction-data.patch
netfilter-nftables-rename-set-element-data-activation-deactivation-functions.patch

12 files changed:
queue-5.10/netfilter-nf_tables-add-nft_trans_prepare_error-to-deal-with-bound-set-chain.patch [new file with mode: 0644]
queue-5.10/netfilter-nf_tables-add-rescheduling-points-during-loop-detection-walks.patch [new file with mode: 0644]
queue-5.10/netfilter-nf_tables-drop-map-element-references-from-preparation-phase.patch [new file with mode: 0644]
queue-5.10/netfilter-nf_tables-fix-chain-binding-transaction-logic.patch [new file with mode: 0644]
queue-5.10/netfilter-nf_tables-fix-scheduling-while-atomic-splat.patch [new file with mode: 0644]
queue-5.10/netfilter-nf_tables-incorrect-error-path-handling-with-nft_msg_newrule.patch [new file with mode: 0644]
queue-5.10/netfilter-nf_tables-reject-unbound-anonymous-set-before-commit-phase.patch [new file with mode: 0644]
queue-5.10/netfilter-nf_tables-reject-unbound-chain-set-before-commit-phase.patch [new file with mode: 0644]
queue-5.10/netfilter-nf_tables-unbind-non-anonymous-set-if-rule-construction-fails.patch [new file with mode: 0644]
queue-5.10/netfilter-nf_tables-use-net_generic-infra-for-transaction-data.patch [new file with mode: 0644]
queue-5.10/netfilter-nftables-rename-set-element-data-activation-deactivation-functions.patch [new file with mode: 0644]
queue-5.10/series

diff --git a/queue-5.10/netfilter-nf_tables-add-nft_trans_prepare_error-to-deal-with-bound-set-chain.patch b/queue-5.10/netfilter-nf_tables-add-nft_trans_prepare_error-to-deal-with-bound-set-chain.patch
new file mode 100644 (file)
index 0000000..1fdba2a
--- /dev/null
@@ -0,0 +1,170 @@
+From stable-owner@vger.kernel.org Thu Jul 13 10:49:52 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Thu, 13 Jul 2023 10:48:53 +0200
+Subject: netfilter: nf_tables: add NFT_TRANS_PREPARE_ERROR to deal with bound set/chain
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, stable@vger.kernel.org, sashal@kernel.org
+Message-ID: <20230713084859.71541-6-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 26b5a5712eb85e253724e56a54c17f8519bd8e4e ]
+
+Add a new state to deal with rule expressions deactivation from the
+newrule error path, otherwise the anonymous set remains in the list in
+inactive state for the next generation. Mark the set/chain transaction
+as unbound so the abort path releases this object, set it as inactive in
+the next generation so it is not reachable anymore from this transaction
+and reference counter is dropped.
+
+Fixes: 1240eb93f061 ("netfilter: nf_tables: incorrect error path handling with NFT_MSG_NEWRULE")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/netfilter/nf_tables.h |    2 +
+ net/netfilter/nf_tables_api.c     |   45 ++++++++++++++++++++++++++++++++------
+ net/netfilter/nft_immediate.c     |    3 ++
+ 3 files changed, 43 insertions(+), 7 deletions(-)
+
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -777,6 +777,7 @@ struct nft_expr_type {
+ enum nft_trans_phase {
+       NFT_TRANS_PREPARE,
++      NFT_TRANS_PREPARE_ERROR,
+       NFT_TRANS_ABORT,
+       NFT_TRANS_COMMIT,
+       NFT_TRANS_RELEASE
+@@ -970,6 +971,7 @@ struct nft_chain {
+ int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain);
+ int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain);
++void nf_tables_unbind_chain(const struct nft_ctx *ctx, struct nft_chain *chain);
+ enum nft_chain_types {
+       NFT_CHAIN_T_DEFAULT = 0,
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -173,7 +173,8 @@ static void nft_trans_destroy(struct nft
+       kfree(trans);
+ }
+-static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
++static void __nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set,
++                               bool bind)
+ {
+       struct nftables_pernet *nft_net;
+       struct net *net = ctx->net;
+@@ -187,17 +188,28 @@ static void nft_set_trans_bind(const str
+               switch (trans->msg_type) {
+               case NFT_MSG_NEWSET:
+                       if (nft_trans_set(trans) == set)
+-                              nft_trans_set_bound(trans) = true;
++                              nft_trans_set_bound(trans) = bind;
+                       break;
+               case NFT_MSG_NEWSETELEM:
+                       if (nft_trans_elem_set(trans) == set)
+-                              nft_trans_elem_set_bound(trans) = true;
++                              nft_trans_elem_set_bound(trans) = bind;
+                       break;
+               }
+       }
+ }
+-static void nft_chain_trans_bind(const struct nft_ctx *ctx, struct nft_chain *chain)
++static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
++{
++      return __nft_set_trans_bind(ctx, set, true);
++}
++
++static void nft_set_trans_unbind(const struct nft_ctx *ctx, struct nft_set *set)
++{
++      return __nft_set_trans_bind(ctx, set, false);
++}
++
++static void __nft_chain_trans_bind(const struct nft_ctx *ctx,
++                                 struct nft_chain *chain, bool bind)
+ {
+       struct nftables_pernet *nft_net;
+       struct net *net = ctx->net;
+@@ -211,16 +223,22 @@ static void nft_chain_trans_bind(const s
+               switch (trans->msg_type) {
+               case NFT_MSG_NEWCHAIN:
+                       if (nft_trans_chain(trans) == chain)
+-                              nft_trans_chain_bound(trans) = true;
++                              nft_trans_chain_bound(trans) = bind;
+                       break;
+               case NFT_MSG_NEWRULE:
+                       if (trans->ctx.chain == chain)
+-                              nft_trans_rule_bound(trans) = true;
++                              nft_trans_rule_bound(trans) = bind;
+                       break;
+               }
+       }
+ }
++static void nft_chain_trans_bind(const struct nft_ctx *ctx,
++                               struct nft_chain *chain)
++{
++      __nft_chain_trans_bind(ctx, chain, true);
++}
++
+ int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain)
+ {
+       if (!nft_chain_binding(chain))
+@@ -239,6 +257,11 @@ int nf_tables_bind_chain(const struct nf
+       return 0;
+ }
++void nf_tables_unbind_chain(const struct nft_ctx *ctx, struct nft_chain *chain)
++{
++      __nft_chain_trans_bind(ctx, chain, false);
++}
++
+ static int nft_netdev_register_hooks(struct net *net,
+                                    struct list_head *hook_list)
+ {
+@@ -3449,7 +3472,7 @@ static int nf_tables_newrule(struct net
+       return 0;
+ err2:
+-      nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE);
++      nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE_ERROR);
+       nf_tables_rule_destroy(&ctx, rule);
+ err1:
+       for (i = 0; i < n; i++) {
+@@ -4585,6 +4608,13 @@ void nf_tables_deactivate_set(const stru
+                             enum nft_trans_phase phase)
+ {
+       switch (phase) {
++      case NFT_TRANS_PREPARE_ERROR:
++              nft_set_trans_unbind(ctx, set);
++              if (nft_set_is_anonymous(set))
++                      nft_deactivate_next(ctx->net, set);
++
++              set->use--;
++              break;
+       case NFT_TRANS_PREPARE:
+               if (nft_set_is_anonymous(set))
+                       nft_deactivate_next(ctx->net, set);
+@@ -6525,6 +6555,7 @@ void nf_tables_deactivate_flowtable(cons
+                                   enum nft_trans_phase phase)
+ {
+       switch (phase) {
++      case NFT_TRANS_PREPARE_ERROR:
+       case NFT_TRANS_PREPARE:
+       case NFT_TRANS_ABORT:
+       case NFT_TRANS_RELEASE:
+--- a/net/netfilter/nft_immediate.c
++++ b/net/netfilter/nft_immediate.c
+@@ -150,6 +150,9 @@ static void nft_immediate_deactivate(con
+                               nft_rule_expr_deactivate(&chain_ctx, rule, phase);
+                       switch (phase) {
++                      case NFT_TRANS_PREPARE_ERROR:
++                              nf_tables_unbind_chain(ctx, chain);
++                              fallthrough;
+                       case NFT_TRANS_PREPARE:
+                               nft_deactivate_next(ctx->net, chain);
+                               break;
diff --git a/queue-5.10/netfilter-nf_tables-add-rescheduling-points-during-loop-detection-walks.patch b/queue-5.10/netfilter-nf_tables-add-rescheduling-points-during-loop-detection-walks.patch
new file mode 100644 (file)
index 0000000..e003123
--- /dev/null
@@ -0,0 +1,50 @@
+From stable-owner@vger.kernel.org Thu Jul 13 10:49:47 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Thu, 13 Jul 2023 10:48:50 +0200
+Subject: netfilter: nf_tables: add rescheduling points during loop detection walks
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, stable@vger.kernel.org, sashal@kernel.org
+Message-ID: <20230713084859.71541-3-pablo@netfilter.org>
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit 81ea010667417ef3f218dfd99b69769fe66c2b67 ]
+
+Add explicit rescheduling points during ruleset walk.
+
+Switching to a faster algorithm is possible but this is a much
+smaller change, suitable for nf tree.
+
+Link: https://bugzilla.netfilter.org/show_bug.cgi?id=1460
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_tables_api.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -3164,6 +3164,8 @@ int nft_chain_validate(const struct nft_
+                       if (err < 0)
+                               return err;
+               }
++
++              cond_resched();
+       }
+       return 0;
+@@ -8506,9 +8508,13 @@ static int nf_tables_check_loops(const s
+                               break;
+                       }
+               }
++
++              cond_resched();
+       }
+       list_for_each_entry(set, &ctx->table->sets, list) {
++              cond_resched();
++
+               if (!nft_is_active_next(ctx->net, set))
+                       continue;
+               if (!(set->flags & NFT_SET_MAP) ||
diff --git a/queue-5.10/netfilter-nf_tables-drop-map-element-references-from-preparation-phase.patch b/queue-5.10/netfilter-nf_tables-drop-map-element-references-from-preparation-phase.patch
new file mode 100644 (file)
index 0000000..e4f4bfe
--- /dev/null
@@ -0,0 +1,376 @@
+From stable-owner@vger.kernel.org Thu Jul 13 10:49:53 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Thu, 13 Jul 2023 10:48:57 +0200
+Subject: netfilter: nf_tables: drop map element references from preparation phase
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, stable@vger.kernel.org, sashal@kernel.org
+Message-ID: <20230713084859.71541-10-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 628bd3e49cba1c066228e23d71a852c23e26da73 ]
+
+set .destroy callback releases the references to other objects in maps.
+This is very late and it results in spurious EBUSY errors. Drop refcount
+from the preparation phase instead, update set backend not to drop
+reference counter from set .destroy path.
+
+Exceptions: NFT_TRANS_PREPARE_ERROR does not require to drop the
+reference counter because the transaction abort path releases the map
+references for each element since the set is unbound. The abort path
+also deals with releasing reference counter for new elements added to
+unbound sets.
+
+Fixes: 591054469b3e ("netfilter: nf_tables: revisit chain/object refcounting from elements")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/netfilter/nf_tables.h |    5 +-
+ net/netfilter/nf_tables_api.c     |   89 ++++++++++++++++++++++++++++++++++----
+ net/netfilter/nft_set_bitmap.c    |    5 +-
+ net/netfilter/nft_set_hash.c      |   23 +++++++--
+ net/netfilter/nft_set_pipapo.c    |   14 +++--
+ net/netfilter/nft_set_rbtree.c    |    5 +-
+ 6 files changed, 117 insertions(+), 24 deletions(-)
+
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -382,7 +382,8 @@ struct nft_set_ops {
+       int                             (*init)(const struct nft_set *set,
+                                               const struct nft_set_desc *desc,
+                                               const struct nlattr * const nla[]);
+-      void                            (*destroy)(const struct nft_set *set);
++      void                            (*destroy)(const struct nft_ctx *ctx,
++                                                 const struct nft_set *set);
+       void                            (*gc_init)(const struct nft_set *set);
+       unsigned int                    elemsize;
+@@ -686,6 +687,8 @@ void *nft_set_elem_init(const struct nft
+                       u64 timeout, u64 expiration, gfp_t gfp);
+ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
+                         bool destroy_expr);
++void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
++                              const struct nft_set *set, void *elem);
+ /**
+  *    struct nft_set_gc_batch_head - nf_tables set garbage collection batch
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -557,6 +557,31 @@ static int nft_trans_set_add(const struc
+       return 0;
+ }
++static void nft_setelem_data_deactivate(const struct net *net,
++                                      const struct nft_set *set,
++                                      struct nft_set_elem *elem);
++
++static int nft_mapelem_deactivate(const struct nft_ctx *ctx,
++                                struct nft_set *set,
++                                const struct nft_set_iter *iter,
++                                struct nft_set_elem *elem)
++{
++      nft_setelem_data_deactivate(ctx->net, set, elem);
++
++      return 0;
++}
++
++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),
++              .fn             = nft_mapelem_deactivate,
++      };
++
++      set->ops->walk(ctx, set, &iter);
++      WARN_ON_ONCE(iter.err);
++}
++
+ static int nft_delset(const struct nft_ctx *ctx, struct nft_set *set)
+ {
+       int err;
+@@ -565,6 +590,9 @@ static int nft_delset(const struct nft_c
+       if (err < 0)
+               return err;
++      if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
++              nft_map_deactivate(ctx, set);
++
+       nft_deactivate_next(ctx->net, set);
+       ctx->table->use--;
+@@ -4474,7 +4502,7 @@ err_set_expr_alloc:
+       if (set->expr)
+               nft_expr_destroy(&ctx, set->expr);
+-      ops->destroy(set);
++      ops->destroy(&ctx, set);
+ err_set_init:
+       kfree(set->name);
+ err_set_name:
+@@ -4490,7 +4518,7 @@ static void nft_set_destroy(const struct
+       if (set->expr)
+               nft_expr_destroy(ctx, set->expr);
+-      set->ops->destroy(set);
++      set->ops->destroy(ctx, set);
+       kfree(set->name);
+       kvfree(set);
+ }
+@@ -4614,10 +4642,39 @@ static void nf_tables_unbind_set(const s
+       }
+ }
++static void nft_setelem_data_activate(const struct net *net,
++                                    const struct nft_set *set,
++                                    struct nft_set_elem *elem);
++
++static int nft_mapelem_activate(const struct nft_ctx *ctx,
++                              struct nft_set *set,
++                              const struct nft_set_iter *iter,
++                              struct nft_set_elem *elem)
++{
++      nft_setelem_data_activate(ctx->net, set, elem);
++
++      return 0;
++}
++
++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),
++              .fn             = nft_mapelem_activate,
++      };
++
++      set->ops->walk(ctx, set, &iter);
++      WARN_ON_ONCE(iter.err);
++}
++
+ void nf_tables_activate_set(const struct nft_ctx *ctx, struct nft_set *set)
+ {
+-      if (nft_set_is_anonymous(set))
++      if (nft_set_is_anonymous(set)) {
++              if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
++                      nft_map_activate(ctx, set);
++
+               nft_clear(ctx->net, set);
++      }
+       set->use++;
+ }
+@@ -4636,13 +4693,20 @@ void nf_tables_deactivate_set(const stru
+               set->use--;
+               break;
+       case NFT_TRANS_PREPARE:
+-              if (nft_set_is_anonymous(set))
+-                      nft_deactivate_next(ctx->net, set);
++              if (nft_set_is_anonymous(set)) {
++                      if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
++                              nft_map_deactivate(ctx, set);
++                      nft_deactivate_next(ctx->net, set);
++              }
+               set->use--;
+               return;
+       case NFT_TRANS_ABORT:
+       case NFT_TRANS_RELEASE:
++              if (nft_set_is_anonymous(set) &&
++                  set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
++                      nft_map_deactivate(ctx, set);
++
+               set->use--;
+               fallthrough;
+       default:
+@@ -5249,6 +5313,7 @@ static void nft_set_elem_expr_destroy(co
+       }
+ }
++/* Drop references and destroy. Called from gc, dynset and abort path. */
+ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
+                         bool destroy_expr)
+ {
+@@ -5270,11 +5335,11 @@ void nft_set_elem_destroy(const struct n
+ }
+ EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
+-/* Only called from commit path, nft_setelem_data_deactivate() already deals
+- * with the refcounting from the preparation phase.
++/* Destroy element. References have been already dropped in the preparation
++ * path via nft_setelem_data_deactivate().
+  */
+-static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
+-                                     const struct nft_set *set, void *elem)
++void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
++                              const struct nft_set *set, void *elem)
+ {
+       struct nft_set_ext *ext = nft_set_elem_ext(set, elem);
+@@ -8399,6 +8464,9 @@ static int __nf_tables_abort(struct net
+               case NFT_MSG_DELSET:
+                       trans->ctx.table->use++;
+                       nft_clear(trans->ctx.net, nft_trans_set(trans));
++                      if (nft_trans_set(trans)->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
++                              nft_map_activate(&trans->ctx, nft_trans_set(trans));
++
+                       nft_trans_destroy(trans);
+                       break;
+               case NFT_MSG_NEWSETELEM:
+@@ -9128,6 +9196,9 @@ static void __nft_release_table(struct n
+       list_for_each_entry_safe(set, ns, &table->sets, list) {
+               list_del(&set->list);
+               table->use--;
++              if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
++                      nft_map_deactivate(&ctx, set);
++
+               nft_set_destroy(&ctx, set);
+       }
+       list_for_each_entry_safe(obj, ne, &table->objects, list) {
+--- a/net/netfilter/nft_set_bitmap.c
++++ b/net/netfilter/nft_set_bitmap.c
+@@ -270,13 +270,14 @@ static int nft_bitmap_init(const struct
+       return 0;
+ }
+-static void nft_bitmap_destroy(const struct nft_set *set)
++static void nft_bitmap_destroy(const struct nft_ctx *ctx,
++                             const struct nft_set *set)
+ {
+       struct nft_bitmap *priv = nft_set_priv(set);
+       struct nft_bitmap_elem *be, *n;
+       list_for_each_entry_safe(be, n, &priv->list, head)
+-              nft_set_elem_destroy(set, be, true);
++              nf_tables_set_elem_destroy(ctx, set, be);
+ }
+ static bool nft_bitmap_estimate(const struct nft_set_desc *desc, u32 features,
+--- a/net/netfilter/nft_set_hash.c
++++ b/net/netfilter/nft_set_hash.c
+@@ -380,19 +380,31 @@ static int nft_rhash_init(const struct n
+       return 0;
+ }
++struct nft_rhash_ctx {
++      const struct nft_ctx    ctx;
++      const struct nft_set    *set;
++};
++
+ static void nft_rhash_elem_destroy(void *ptr, void *arg)
+ {
+-      nft_set_elem_destroy(arg, ptr, true);
++      struct nft_rhash_ctx *rhash_ctx = arg;
++
++      nf_tables_set_elem_destroy(&rhash_ctx->ctx, rhash_ctx->set, ptr);
+ }
+-static void nft_rhash_destroy(const struct nft_set *set)
++static void nft_rhash_destroy(const struct nft_ctx *ctx,
++                            const struct nft_set *set)
+ {
+       struct nft_rhash *priv = nft_set_priv(set);
++      struct nft_rhash_ctx rhash_ctx = {
++              .ctx    = *ctx,
++              .set    = set,
++      };
+       cancel_delayed_work_sync(&priv->gc_work);
+       rcu_barrier();
+       rhashtable_free_and_destroy(&priv->ht, nft_rhash_elem_destroy,
+-                                  (void *)set);
++                                  (void *)&rhash_ctx);
+ }
+ /* Number of buckets is stored in u32, so cap our result to 1U<<31 */
+@@ -621,7 +633,8 @@ static int nft_hash_init(const struct nf
+       return 0;
+ }
+-static void nft_hash_destroy(const struct nft_set *set)
++static void nft_hash_destroy(const struct nft_ctx *ctx,
++                           const struct nft_set *set)
+ {
+       struct nft_hash *priv = nft_set_priv(set);
+       struct nft_hash_elem *he;
+@@ -631,7 +644,7 @@ static void nft_hash_destroy(const struc
+       for (i = 0; i < priv->buckets; i++) {
+               hlist_for_each_entry_safe(he, next, &priv->table[i], node) {
+                       hlist_del_rcu(&he->node);
+-                      nft_set_elem_destroy(set, he, true);
++                      nf_tables_set_elem_destroy(ctx, set, he);
+               }
+       }
+ }
+--- a/net/netfilter/nft_set_pipapo.c
++++ b/net/netfilter/nft_set_pipapo.c
+@@ -2127,10 +2127,12 @@ out_scratch:
+ /**
+  * nft_set_pipapo_match_destroy() - Destroy elements from key mapping array
++ * @ctx:      context
+  * @set:      nftables API set representation
+  * @m:                matching data pointing to key mapping array
+  */
+-static void nft_set_pipapo_match_destroy(const struct nft_set *set,
++static void nft_set_pipapo_match_destroy(const struct nft_ctx *ctx,
++                                       const struct nft_set *set,
+                                        struct nft_pipapo_match *m)
+ {
+       struct nft_pipapo_field *f;
+@@ -2147,15 +2149,17 @@ static void nft_set_pipapo_match_destroy
+               e = f->mt[r].e;
+-              nft_set_elem_destroy(set, e, true);
++              nf_tables_set_elem_destroy(ctx, set, e);
+       }
+ }
+ /**
+  * nft_pipapo_destroy() - Free private data for set and all committed elements
++ * @ctx:      context
+  * @set:      nftables API set representation
+  */
+-static void nft_pipapo_destroy(const struct nft_set *set)
++static void nft_pipapo_destroy(const struct nft_ctx *ctx,
++                             const struct nft_set *set)
+ {
+       struct nft_pipapo *priv = nft_set_priv(set);
+       struct nft_pipapo_match *m;
+@@ -2165,7 +2169,7 @@ static void nft_pipapo_destroy(const str
+       if (m) {
+               rcu_barrier();
+-              nft_set_pipapo_match_destroy(set, m);
++              nft_set_pipapo_match_destroy(ctx, set, m);
+ #ifdef NFT_PIPAPO_ALIGN
+               free_percpu(m->scratch_aligned);
+@@ -2182,7 +2186,7 @@ static void nft_pipapo_destroy(const str
+               m = priv->clone;
+               if (priv->dirty)
+-                      nft_set_pipapo_match_destroy(set, m);
++                      nft_set_pipapo_match_destroy(ctx, set, m);
+ #ifdef NFT_PIPAPO_ALIGN
+               free_percpu(priv->clone->scratch_aligned);
+--- a/net/netfilter/nft_set_rbtree.c
++++ b/net/netfilter/nft_set_rbtree.c
+@@ -657,7 +657,8 @@ static int nft_rbtree_init(const struct
+       return 0;
+ }
+-static void nft_rbtree_destroy(const struct nft_set *set)
++static void nft_rbtree_destroy(const struct nft_ctx *ctx,
++                             const struct nft_set *set)
+ {
+       struct nft_rbtree *priv = nft_set_priv(set);
+       struct nft_rbtree_elem *rbe;
+@@ -668,7 +669,7 @@ static void nft_rbtree_destroy(const str
+       while ((node = priv->root.rb_node) != NULL) {
+               rb_erase(node, &priv->root);
+               rbe = rb_entry(node, struct nft_rbtree_elem, node);
+-              nft_set_elem_destroy(set, rbe, true);
++              nf_tables_set_elem_destroy(ctx, set, rbe);
+       }
+ }
diff --git a/queue-5.10/netfilter-nf_tables-fix-chain-binding-transaction-logic.patch b/queue-5.10/netfilter-nf_tables-fix-chain-binding-transaction-logic.patch
new file mode 100644 (file)
index 0000000..039be73
--- /dev/null
@@ -0,0 +1,432 @@
+From stable-owner@vger.kernel.org Thu Jul 13 10:49:52 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Thu, 13 Jul 2023 10:48:52 +0200
+Subject: netfilter: nf_tables: fix chain binding transaction logic
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, stable@vger.kernel.org, sashal@kernel.org
+Message-ID: <20230713084859.71541-5-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 4bedf9eee016286c835e3d8fa981ddece5338795 ]
+
+Add bound flag to rule and chain transactions as in 6a0a8d10a366
+("netfilter: nf_tables: use-after-free in failing rule with bound set")
+to skip them in case that the chain is already bound from the abort
+path.
+
+This patch fixes an imbalance in the chain use refcnt that triggers a
+WARN_ON on the table and chain destroy path.
+
+This patch also disallows nested chain bindings, which is not
+supported from userspace.
+
+The logic to deal with chain binding in nft_data_hold() and
+nft_data_release() is not correct. The NFT_TRANS_PREPARE state needs a
+special handling in case a chain is bound but next expressions in the
+same rule fail to initialize as described by 1240eb93f061 ("netfilter:
+nf_tables: incorrect error path handling with NFT_MSG_NEWRULE").
+
+The chain is left bound if rule construction fails, so the objects
+stored in this chain (and the chain itself) are released by the
+transaction records from the abort path, follow up patch ("netfilter:
+nf_tables: add NFT_TRANS_PREPARE_ERROR to deal with bound set/chain")
+completes this error handling.
+
+When deleting an existing rule, chain bound flag is set off so the
+rule expression .destroy path releases the objects.
+
+Fixes: d0e2c7de92c7 ("netfilter: nf_tables: add NFT_CHAIN_BINDING")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/netfilter/nf_tables.h |   21 ++++++++-
+ net/netfilter/nf_tables_api.c     |   86 ++++++++++++++++++++++++-------------
+ net/netfilter/nft_immediate.c     |   87 ++++++++++++++++++++++++++++++++++----
+ 3 files changed, 153 insertions(+), 41 deletions(-)
+
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -907,7 +907,10 @@ static inline struct nft_userdata *nft_u
+       return (void *)&rule->data[rule->dlen];
+ }
+-void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *rule);
++void nft_rule_expr_activate(const struct nft_ctx *ctx, struct nft_rule *rule);
++void nft_rule_expr_deactivate(const struct nft_ctx *ctx, struct nft_rule *rule,
++                            enum nft_trans_phase phase);
++void nf_tables_rule_destroy(const struct nft_ctx *ctx, struct nft_rule *rule);
+ static inline void nft_set_elem_update_expr(const struct nft_set_ext *ext,
+                                           struct nft_regs *regs,
+@@ -966,6 +969,7 @@ struct nft_chain {
+ };
+ int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain);
++int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain);
+ enum nft_chain_types {
+       NFT_CHAIN_T_DEFAULT = 0,
+@@ -1002,11 +1006,17 @@ int nft_chain_validate_dependency(const
+ int nft_chain_validate_hooks(const struct nft_chain *chain,
+                              unsigned int hook_flags);
++static inline bool nft_chain_binding(const struct nft_chain *chain)
++{
++      return chain->flags & NFT_CHAIN_BINDING;
++}
++
+ static inline bool nft_chain_is_bound(struct nft_chain *chain)
+ {
+       return (chain->flags & NFT_CHAIN_BINDING) && chain->bound;
+ }
++int nft_chain_add(struct nft_table *table, struct nft_chain *chain);
+ void nft_chain_del(struct nft_chain *chain);
+ void nf_tables_chain_destroy(struct nft_ctx *ctx);
+@@ -1431,6 +1441,7 @@ struct nft_trans_rule {
+       struct nft_rule                 *rule;
+       struct nft_flow_rule            *flow;
+       u32                             rule_id;
++      bool                            bound;
+ };
+ #define nft_trans_rule(trans) \
+@@ -1439,6 +1450,8 @@ struct nft_trans_rule {
+       (((struct nft_trans_rule *)trans->data)->flow)
+ #define nft_trans_rule_id(trans)      \
+       (((struct nft_trans_rule *)trans->data)->rule_id)
++#define nft_trans_rule_bound(trans)   \
++      (((struct nft_trans_rule *)trans->data)->bound)
+ struct nft_trans_set {
+       struct nft_set                  *set;
+@@ -1454,13 +1467,17 @@ struct nft_trans_set {
+       (((struct nft_trans_set *)trans->data)->bound)
+ struct nft_trans_chain {
++      struct nft_chain                *chain;
+       bool                            update;
+       char                            *name;
+       struct nft_stats __percpu       *stats;
+       u8                              policy;
++      bool                            bound;
+       u32                             chain_id;
+ };
++#define nft_trans_chain(trans)        \
++      (((struct nft_trans_chain *)trans->data)->chain)
+ #define nft_trans_chain_update(trans) \
+       (((struct nft_trans_chain *)trans->data)->update)
+ #define nft_trans_chain_name(trans)   \
+@@ -1469,6 +1486,8 @@ struct nft_trans_chain {
+       (((struct nft_trans_chain *)trans->data)->stats)
+ #define nft_trans_chain_policy(trans) \
+       (((struct nft_trans_chain *)trans->data)->policy)
++#define nft_trans_chain_bound(trans)  \
++      (((struct nft_trans_chain *)trans->data)->bound)
+ #define nft_trans_chain_id(trans)     \
+       (((struct nft_trans_chain *)trans->data)->chain_id)
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -197,6 +197,48 @@ static void nft_set_trans_bind(const str
+       }
+ }
++static void nft_chain_trans_bind(const struct nft_ctx *ctx, struct nft_chain *chain)
++{
++      struct nftables_pernet *nft_net;
++      struct net *net = ctx->net;
++      struct nft_trans *trans;
++
++      if (!nft_chain_binding(chain))
++              return;
++
++      nft_net = net_generic(net, nf_tables_net_id);
++      list_for_each_entry_reverse(trans, &nft_net->commit_list, list) {
++              switch (trans->msg_type) {
++              case NFT_MSG_NEWCHAIN:
++                      if (nft_trans_chain(trans) == chain)
++                              nft_trans_chain_bound(trans) = true;
++                      break;
++              case NFT_MSG_NEWRULE:
++                      if (trans->ctx.chain == chain)
++                              nft_trans_rule_bound(trans) = true;
++                      break;
++              }
++      }
++}
++
++int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain)
++{
++      if (!nft_chain_binding(chain))
++              return 0;
++
++      if (nft_chain_binding(ctx->chain))
++              return -EOPNOTSUPP;
++
++      if (chain->bound)
++              return -EBUSY;
++
++      chain->bound = true;
++      chain->use++;
++      nft_chain_trans_bind(ctx, chain);
++
++      return 0;
++}
++
+ static int nft_netdev_register_hooks(struct net *net,
+                                    struct list_head *hook_list)
+ {
+@@ -328,8 +370,9 @@ static struct nft_trans *nft_trans_chain
+                               ntohl(nla_get_be32(ctx->nla[NFTA_CHAIN_ID]));
+               }
+       }
+-
++      nft_trans_chain(trans) = ctx->chain;
+       nft_trans_commit_list_add_tail(ctx->net, trans);
++
+       return trans;
+ }
+@@ -347,8 +390,7 @@ static int nft_delchain(struct nft_ctx *
+       return 0;
+ }
+-static void nft_rule_expr_activate(const struct nft_ctx *ctx,
+-                                 struct nft_rule *rule)
++void nft_rule_expr_activate(const struct nft_ctx *ctx, struct nft_rule *rule)
+ {
+       struct nft_expr *expr;
+@@ -361,9 +403,8 @@ static void nft_rule_expr_activate(const
+       }
+ }
+-static void nft_rule_expr_deactivate(const struct nft_ctx *ctx,
+-                                   struct nft_rule *rule,
+-                                   enum nft_trans_phase phase)
++void nft_rule_expr_deactivate(const struct nft_ctx *ctx, struct nft_rule *rule,
++                            enum nft_trans_phase phase)
+ {
+       struct nft_expr *expr;
+@@ -2017,7 +2058,7 @@ static int nft_basechain_init(struct nft
+       return 0;
+ }
+-static int nft_chain_add(struct nft_table *table, struct nft_chain *chain)
++int nft_chain_add(struct nft_table *table, struct nft_chain *chain)
+ {
+       int err;
+@@ -3118,8 +3159,7 @@ err_fill_rule_info:
+       return err;
+ }
+-static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
+-                                 struct nft_rule *rule)
++void nf_tables_rule_destroy(const struct nft_ctx *ctx, struct nft_rule *rule)
+ {
+       struct nft_expr *expr, *next;
+@@ -3136,7 +3176,7 @@ static void nf_tables_rule_destroy(const
+       kfree(rule);
+ }
+-void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *rule)
++static void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *rule)
+ {
+       nft_rule_expr_deactivate(ctx, rule, NFT_TRANS_RELEASE);
+       nf_tables_rule_destroy(ctx, rule);
+@@ -5547,7 +5587,6 @@ static int nf_tables_newsetelem(struct n
+ void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
+ {
+       struct nft_chain *chain;
+-      struct nft_rule *rule;
+       if (type == NFT_DATA_VERDICT) {
+               switch (data->verdict.code) {
+@@ -5555,15 +5594,6 @@ void nft_data_hold(const struct nft_data
+               case NFT_GOTO:
+                       chain = data->verdict.chain;
+                       chain->use++;
+-
+-                      if (!nft_chain_is_bound(chain))
+-                              break;
+-
+-                      chain->table->use++;
+-                      list_for_each_entry(rule, &chain->rules, list)
+-                              chain->use++;
+-
+-                      nft_chain_add(chain->table, chain);
+                       break;
+               }
+       }
+@@ -8254,7 +8284,7 @@ static int __nf_tables_abort(struct net
+                               kfree(nft_trans_chain_name(trans));
+                               nft_trans_destroy(trans);
+                       } else {
+-                              if (nft_chain_is_bound(trans->ctx.chain)) {
++                              if (nft_trans_chain_bound(trans)) {
+                                       nft_trans_destroy(trans);
+                                       break;
+                               }
+@@ -8271,6 +8301,10 @@ static int __nf_tables_abort(struct net
+                       nft_trans_destroy(trans);
+                       break;
+               case NFT_MSG_NEWRULE:
++                      if (nft_trans_rule_bound(trans)) {
++                              nft_trans_destroy(trans);
++                              break;
++                      }
+                       trans->ctx.chain->use--;
+                       list_del_rcu(&nft_trans_rule(trans)->list);
+                       nft_rule_expr_deactivate(&trans->ctx,
+@@ -8796,22 +8830,12 @@ static int nft_verdict_init(const struct
+ static void nft_verdict_uninit(const struct nft_data *data)
+ {
+       struct nft_chain *chain;
+-      struct nft_rule *rule;
+       switch (data->verdict.code) {
+       case NFT_JUMP:
+       case NFT_GOTO:
+               chain = data->verdict.chain;
+               chain->use--;
+-
+-              if (!nft_chain_is_bound(chain))
+-                      break;
+-
+-              chain->table->use--;
+-              list_for_each_entry(rule, &chain->rules, list)
+-                      chain->use--;
+-
+-              nft_chain_del(chain);
+               break;
+       }
+ }
+--- a/net/netfilter/nft_immediate.c
++++ b/net/netfilter/nft_immediate.c
+@@ -76,11 +76,9 @@ static int nft_immediate_init(const stru
+               switch (priv->data.verdict.code) {
+               case NFT_JUMP:
+               case NFT_GOTO:
+-                      if (nft_chain_is_bound(chain)) {
+-                              err = -EBUSY;
+-                              goto err1;
+-                      }
+-                      chain->bound = true;
++                      err = nf_tables_bind_chain(ctx, chain);
++                      if (err < 0)
++                              return err;
+                       break;
+               default:
+                       break;
+@@ -98,6 +96,31 @@ static void nft_immediate_activate(const
+                                  const struct nft_expr *expr)
+ {
+       const struct nft_immediate_expr *priv = nft_expr_priv(expr);
++      const struct nft_data *data = &priv->data;
++      struct nft_ctx chain_ctx;
++      struct nft_chain *chain;
++      struct nft_rule *rule;
++
++      if (priv->dreg == NFT_REG_VERDICT) {
++              switch (data->verdict.code) {
++              case NFT_JUMP:
++              case NFT_GOTO:
++                      chain = data->verdict.chain;
++                      if (!nft_chain_binding(chain))
++                              break;
++
++                      chain_ctx = *ctx;
++                      chain_ctx.chain = chain;
++
++                      list_for_each_entry(rule, &chain->rules, list)
++                              nft_rule_expr_activate(&chain_ctx, rule);
++
++                      nft_clear(ctx->net, chain);
++                      break;
++              default:
++                      break;
++              }
++      }
+       return nft_data_hold(&priv->data, nft_dreg_to_type(priv->dreg));
+ }
+@@ -107,6 +130,40 @@ static void nft_immediate_deactivate(con
+                                    enum nft_trans_phase phase)
+ {
+       const struct nft_immediate_expr *priv = nft_expr_priv(expr);
++      const struct nft_data *data = &priv->data;
++      struct nft_ctx chain_ctx;
++      struct nft_chain *chain;
++      struct nft_rule *rule;
++
++      if (priv->dreg == NFT_REG_VERDICT) {
++              switch (data->verdict.code) {
++              case NFT_JUMP:
++              case NFT_GOTO:
++                      chain = data->verdict.chain;
++                      if (!nft_chain_binding(chain))
++                              break;
++
++                      chain_ctx = *ctx;
++                      chain_ctx.chain = chain;
++
++                      list_for_each_entry(rule, &chain->rules, list)
++                              nft_rule_expr_deactivate(&chain_ctx, rule, phase);
++
++                      switch (phase) {
++                      case NFT_TRANS_PREPARE:
++                              nft_deactivate_next(ctx->net, chain);
++                              break;
++                      default:
++                              nft_chain_del(chain);
++                              chain->bound = false;
++                              chain->table->use--;
++                              break;
++                      }
++                      break;
++              default:
++                      break;
++              }
++      }
+       if (phase == NFT_TRANS_COMMIT)
+               return;
+@@ -131,15 +188,27 @@ static void nft_immediate_destroy(const
+       case NFT_GOTO:
+               chain = data->verdict.chain;
+-              if (!nft_chain_is_bound(chain))
++              if (!nft_chain_binding(chain))
++                      break;
++
++              /* Rule construction failed, but chain is already bound:
++               * let the transaction records release this chain and its rules.
++               */
++              if (chain->bound) {
++                      chain->use--;
+                       break;
++              }
++              /* Rule has been deleted, release chain and its rules. */
+               chain_ctx = *ctx;
+               chain_ctx.chain = chain;
+-              list_for_each_entry_safe(rule, n, &chain->rules, list)
+-                      nf_tables_rule_release(&chain_ctx, rule);
+-
++              chain->use--;
++              list_for_each_entry_safe(rule, n, &chain->rules, list) {
++                      chain->use--;
++                      list_del(&rule->list);
++                      nf_tables_rule_destroy(&chain_ctx, rule);
++              }
+               nf_tables_chain_destroy(&chain_ctx);
+               break;
+       default:
diff --git a/queue-5.10/netfilter-nf_tables-fix-scheduling-while-atomic-splat.patch b/queue-5.10/netfilter-nf_tables-fix-scheduling-while-atomic-splat.patch
new file mode 100644 (file)
index 0000000..8193a3c
--- /dev/null
@@ -0,0 +1,39 @@
+From stable-owner@vger.kernel.org Thu Jul 13 10:49:58 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Thu, 13 Jul 2023 10:48:59 +0200
+Subject: netfilter: nf_tables: fix scheduling-while-atomic splat
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, stable@vger.kernel.org, sashal@kernel.org
+Message-ID: <20230713084859.71541-12-pablo@netfilter.org>
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit 2024439bd5ceb145eeeb428b2a59e9b905153ac3 ]
+
+nf_tables_check_loops() can be called from rhashtable list
+walk so cond_resched() cannot be used here.
+
+Fixes: 81ea01066741 ("netfilter: nf_tables: add rescheduling points during loop detection walks")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_tables_api.c |    4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -8684,13 +8684,9 @@ static int nf_tables_check_loops(const s
+                               break;
+                       }
+               }
+-
+-              cond_resched();
+       }
+       list_for_each_entry(set, &ctx->table->sets, list) {
+-              cond_resched();
+-
+               if (!nft_is_active_next(ctx->net, set))
+                       continue;
+               if (!(set->flags & NFT_SET_MAP) ||
diff --git a/queue-5.10/netfilter-nf_tables-incorrect-error-path-handling-with-nft_msg_newrule.patch b/queue-5.10/netfilter-nf_tables-incorrect-error-path-handling-with-nft_msg_newrule.patch
new file mode 100644 (file)
index 0000000..17c6b4a
--- /dev/null
@@ -0,0 +1,73 @@
+From stable-owner@vger.kernel.org Thu Jul 13 10:49:52 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Thu, 13 Jul 2023 10:48:51 +0200
+Subject: netfilter: nf_tables: incorrect error path handling with NFT_MSG_NEWRULE
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, stable@vger.kernel.org, sashal@kernel.org
+Message-ID: <20230713084859.71541-4-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 1240eb93f0616b21c675416516ff3d74798fdc97 ]
+
+In case of error when adding a new rule that refers to an anonymous set,
+deactivate expressions via NFT_TRANS_PREPARE state, not NFT_TRANS_RELEASE.
+Thus, the lookup expression marks anonymous sets as inactive in the next
+generation to ensure it is not reachable in this transaction anymore and
+decrement the set refcount as introduced by c1592a89942e ("netfilter:
+nf_tables: deactivate anonymous set from preparation phase"). The abort
+step takes care of undoing the anonymous set.
+
+This is also consistent with rule deletion, where NFT_TRANS_PREPARE is
+used. Note that this error path is exercised in the preparation step of
+the commit protocol. This patch replaces nf_tables_rule_release() by the
+deactivate and destroy calls, this time with NFT_TRANS_PREPARE.
+
+Due to this incorrect error handling, it is possible to access a
+dangling pointer to the anonymous set that remains in the transaction
+list.
+
+[1009.379054] BUG: KASAN: use-after-free in nft_set_lookup_global+0x147/0x1a0 [nf_tables]
+[1009.379106] Read of size 8 at addr ffff88816c4c8020 by task nft-rule-add/137110
+[1009.379116] CPU: 7 PID: 137110 Comm: nft-rule-add Not tainted 6.4.0-rc4+ #256
+[1009.379128] Call Trace:
+[1009.379132]  <TASK>
+[1009.379135]  dump_stack_lvl+0x33/0x50
+[1009.379146]  ? nft_set_lookup_global+0x147/0x1a0 [nf_tables]
+[1009.379191]  print_address_description.constprop.0+0x27/0x300
+[1009.379201]  kasan_report+0x107/0x120
+[1009.379210]  ? nft_set_lookup_global+0x147/0x1a0 [nf_tables]
+[1009.379255]  nft_set_lookup_global+0x147/0x1a0 [nf_tables]
+[1009.379302]  nft_lookup_init+0xa5/0x270 [nf_tables]
+[1009.379350]  nf_tables_newrule+0x698/0xe50 [nf_tables]
+[1009.379397]  ? nf_tables_rule_release+0xe0/0xe0 [nf_tables]
+[1009.379441]  ? kasan_unpoison+0x23/0x50
+[1009.379450]  nfnetlink_rcv_batch+0x97c/0xd90 [nfnetlink]
+[1009.379470]  ? nfnetlink_rcv_msg+0x480/0x480 [nfnetlink]
+[1009.379485]  ? __alloc_skb+0xb8/0x1e0
+[1009.379493]  ? __alloc_skb+0xb8/0x1e0
+[1009.379502]  ? entry_SYSCALL_64_after_hwframe+0x46/0xb0
+[1009.379509]  ? unwind_get_return_address+0x2a/0x40
+[1009.379517]  ? write_profile+0xc0/0xc0
+[1009.379524]  ? avc_lookup+0x8f/0xc0
+[1009.379532]  ? __rcu_read_unlock+0x43/0x60
+
+Fixes: 958bee14d071 ("netfilter: nf_tables: use new transaction infrastructure to handle sets")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_tables_api.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -3409,7 +3409,8 @@ static int nf_tables_newrule(struct net
+       return 0;
+ err2:
+-      nf_tables_rule_release(&ctx, rule);
++      nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE);
++      nf_tables_rule_destroy(&ctx, rule);
+ err1:
+       for (i = 0; i < n; i++) {
+               if (info[i].ops) {
diff --git a/queue-5.10/netfilter-nf_tables-reject-unbound-anonymous-set-before-commit-phase.patch b/queue-5.10/netfilter-nf_tables-reject-unbound-anonymous-set-before-commit-phase.patch
new file mode 100644 (file)
index 0000000..08a0f52
--- /dev/null
@@ -0,0 +1,139 @@
+From stable-owner@vger.kernel.org Thu Jul 13 10:49:53 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Thu, 13 Jul 2023 10:48:54 +0200
+Subject: netfilter: nf_tables: reject unbound anonymous set before commit phase
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, stable@vger.kernel.org, sashal@kernel.org
+Message-ID: <20230713084859.71541-7-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 938154b93be8cd611ddfd7bafc1849f3c4355201 ]
+
+Add a new list to track set transaction and to check for unbound
+anonymous sets before entering the commit phase.
+
+Bail out at the end of the transaction handling if an anonymous set
+remains unbound.
+
+Fixes: 96518518cc41 ("netfilter: add nftables")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/netfilter/nf_tables.h |    3 +++
+ net/netfilter/nf_tables_api.c     |   34 +++++++++++++++++++++++++++++++---
+ 2 files changed, 34 insertions(+), 3 deletions(-)
+
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -1426,6 +1426,7 @@ static inline void nft_set_elem_clear_bu
+  *    struct nft_trans - nf_tables object update in transaction
+  *
+  *    @list: used internally
++ *    @binding_list: list of objects with possible bindings
+  *    @msg_type: message type
+  *    @put_net: ctx->net needs to be put
+  *    @ctx: transaction context
+@@ -1433,6 +1434,7 @@ static inline void nft_set_elem_clear_bu
+  */
+ struct nft_trans {
+       struct list_head                list;
++      struct list_head                binding_list;
+       int                             msg_type;
+       bool                            put_net;
+       struct nft_ctx                  ctx;
+@@ -1559,6 +1561,7 @@ __be64 nf_jiffies64_to_msecs(u64 input);
+ struct nftables_pernet {
+       struct list_head        tables;
+       struct list_head        commit_list;
++      struct list_head        binding_list;
+       struct list_head        module_list;
+       struct list_head        notify_list;
+       struct mutex            commit_mutex;
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -155,6 +155,7 @@ static struct nft_trans *nft_trans_alloc
+               return NULL;
+       INIT_LIST_HEAD(&trans->list);
++      INIT_LIST_HEAD(&trans->binding_list);
+       trans->msg_type = msg_type;
+       trans->ctx      = *ctx;
+@@ -167,9 +168,15 @@ static struct nft_trans *nft_trans_alloc
+       return nft_trans_alloc_gfp(ctx, msg_type, size, GFP_KERNEL);
+ }
+-static void nft_trans_destroy(struct nft_trans *trans)
++static void nft_trans_list_del(struct nft_trans *trans)
+ {
+       list_del(&trans->list);
++      list_del(&trans->binding_list);
++}
++
++static void nft_trans_destroy(struct nft_trans *trans)
++{
++      nft_trans_list_del(trans);
+       kfree(trans);
+ }
+@@ -347,6 +354,14 @@ static void nft_trans_commit_list_add_ta
+       struct nftables_pernet *nft_net;
+       nft_net = net_generic(net, nf_tables_net_id);
++
++      switch (trans->msg_type) {
++      case NFT_MSG_NEWSET:
++              if (nft_set_is_anonymous(nft_trans_set(trans)))
++                      list_add_tail(&trans->binding_list, &nft_net->binding_list);
++              break;
++      }
++
+       list_add_tail(&trans->list, &nft_net->commit_list);
+ }
+@@ -7717,7 +7732,7 @@ static void nf_tables_trans_destroy_work
+       synchronize_rcu();
+       list_for_each_entry_safe(trans, next, &head, list) {
+-              list_del(&trans->list);
++              nft_trans_list_del(trans);
+               nft_commit_release(trans);
+       }
+ }
+@@ -8019,6 +8034,18 @@ static int nf_tables_commit(struct net *
+               return 0;
+       }
++      list_for_each_entry(trans, &nft_net->binding_list, binding_list) {
++              switch (trans->msg_type) {
++              case NFT_MSG_NEWSET:
++                      if (nft_set_is_anonymous(nft_trans_set(trans)) &&
++                          !nft_trans_set_bound(trans)) {
++                              pr_warn_once("nftables ruleset with unbound set\n");
++                              return -EINVAL;
++                      }
++                      break;
++              }
++      }
++
+       /* 0. Validate ruleset, otherwise roll back for error reporting. */
+       if (nf_tables_validate(net) < 0)
+               return -EAGAIN;
+@@ -8421,7 +8448,7 @@ static int __nf_tables_abort(struct net
+       list_for_each_entry_safe_reverse(trans, next,
+                                        &nft_net->commit_list, list) {
+-              list_del(&trans->list);
++              nft_trans_list_del(trans);
+               nf_tables_abort_release(trans);
+       }
+@@ -9120,6 +9147,7 @@ static int __net_init nf_tables_init_net
+       INIT_LIST_HEAD(&nft_net->tables);
+       INIT_LIST_HEAD(&nft_net->commit_list);
++      INIT_LIST_HEAD(&nft_net->binding_list);
+       INIT_LIST_HEAD(&nft_net->module_list);
+       INIT_LIST_HEAD(&nft_net->notify_list);
+       mutex_init(&nft_net->commit_mutex);
diff --git a/queue-5.10/netfilter-nf_tables-reject-unbound-chain-set-before-commit-phase.patch b/queue-5.10/netfilter-nf_tables-reject-unbound-chain-set-before-commit-phase.patch
new file mode 100644 (file)
index 0000000..22f706a
--- /dev/null
@@ -0,0 +1,54 @@
+From stable-owner@vger.kernel.org Thu Jul 13 10:49:52 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Thu, 13 Jul 2023 10:48:55 +0200
+Subject: netfilter: nf_tables: reject unbound chain set before commit phase
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, stable@vger.kernel.org, sashal@kernel.org
+Message-ID: <20230713084859.71541-8-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 62e1e94b246e685d89c3163aaef4b160e42ceb02 ]
+
+Use binding list to track set transaction and to check for unbound
+chains before entering the commit phase.
+
+Bail out if chain binding remain unused before entering the commit
+step.
+
+Fixes: d0e2c7de92c7 ("netfilter: nf_tables: add NFT_CHAIN_BINDING")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_tables_api.c |   13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -360,6 +360,11 @@ static void nft_trans_commit_list_add_ta
+               if (nft_set_is_anonymous(nft_trans_set(trans)))
+                       list_add_tail(&trans->binding_list, &nft_net->binding_list);
+               break;
++      case NFT_MSG_NEWCHAIN:
++              if (!nft_trans_chain_update(trans) &&
++                  nft_chain_binding(nft_trans_chain(trans)))
++                      list_add_tail(&trans->binding_list, &nft_net->binding_list);
++              break;
+       }
+       list_add_tail(&trans->list, &nft_net->commit_list);
+@@ -8043,6 +8048,14 @@ static int nf_tables_commit(struct net *
+                               return -EINVAL;
+                       }
+                       break;
++              case NFT_MSG_NEWCHAIN:
++                      if (!nft_trans_chain_update(trans) &&
++                          nft_chain_binding(nft_trans_chain(trans)) &&
++                          !nft_trans_chain_bound(trans)) {
++                              pr_warn_once("nftables ruleset with unbound chain\n");
++                              return -EINVAL;
++                      }
++                      break;
+               }
+       }
diff --git a/queue-5.10/netfilter-nf_tables-unbind-non-anonymous-set-if-rule-construction-fails.patch b/queue-5.10/netfilter-nf_tables-unbind-non-anonymous-set-if-rule-construction-fails.patch
new file mode 100644 (file)
index 0000000..aee6afb
--- /dev/null
@@ -0,0 +1,33 @@
+From stable-owner@vger.kernel.org Thu Jul 13 10:49:58 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Thu, 13 Jul 2023 10:48:58 +0200
+Subject: netfilter: nf_tables: unbind non-anonymous set if rule construction fails
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, stable@vger.kernel.org, sashal@kernel.org
+Message-ID: <20230713084859.71541-11-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit 3e70489721b6c870252c9082c496703677240f53 ]
+
+Otherwise a dangling reference to a rule object that is gone remains
+in the set binding list.
+
+Fixes: 26b5a5712eb8 ("netfilter: nf_tables: add NFT_TRANS_PREPARE_ERROR to deal with bound set/chain")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_tables_api.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -4689,6 +4689,8 @@ void nf_tables_deactivate_set(const stru
+               nft_set_trans_unbind(ctx, set);
+               if (nft_set_is_anonymous(set))
+                       nft_deactivate_next(ctx->net, set);
++              else
++                      list_del_rcu(&binding->list);
+               set->use--;
+               break;
diff --git a/queue-5.10/netfilter-nf_tables-use-net_generic-infra-for-transaction-data.patch b/queue-5.10/netfilter-nf_tables-use-net_generic-infra-for-transaction-data.patch
new file mode 100644 (file)
index 0000000..769fada
--- /dev/null
@@ -0,0 +1,1443 @@
+From stable-owner@vger.kernel.org Thu Jul 13 10:49:52 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Thu, 13 Jul 2023 10:48:49 +0200
+Subject: netfilter: nf_tables: use net_generic infra for transaction data
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, stable@vger.kernel.org, sashal@kernel.org
+Message-ID: <20230713084859.71541-2-pablo@netfilter.org>
+
+From: Florian Westphal <fw@strlen.de>
+
+[ Upstream commit 0854db2aaef3fcdd3498a9d299c60adea2aa3dc6 ]
+
+This moves all nf_tables pernet data from struct net to a net_generic
+extension, with the exception of the gencursor.
+
+The latter is used in the data path and also outside of the nf_tables
+core. All others are only used from the configuration plane.
+
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/netfilter/nf_tables.h |   10 
+ include/net/netns/nftables.h      |    7 
+ net/netfilter/nf_tables_api.c     |  382 +++++++++++++++++++++++---------------
+ net/netfilter/nf_tables_offload.c |   30 +-
+ net/netfilter/nft_chain_filter.c  |   11 -
+ net/netfilter/nft_dynset.c        |    6 
+ 6 files changed, 279 insertions(+), 167 deletions(-)
+
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -1535,4 +1535,14 @@ void nf_tables_trans_destroy_flush_work(
+ int nf_msecs_to_jiffies64(const struct nlattr *nla, u64 *result);
+ __be64 nf_jiffies64_to_msecs(u64 input);
++struct nftables_pernet {
++      struct list_head        tables;
++      struct list_head        commit_list;
++      struct list_head        module_list;
++      struct list_head        notify_list;
++      struct mutex            commit_mutex;
++      unsigned int            base_seq;
++      u8                      validate_state;
++};
++
+ #endif /* _NET_NF_TABLES_H */
+--- a/include/net/netns/nftables.h
++++ b/include/net/netns/nftables.h
+@@ -5,14 +5,7 @@
+ #include <linux/list.h>
+ struct netns_nftables {
+-      struct list_head        tables;
+-      struct list_head        commit_list;
+-      struct list_head        module_list;
+-      struct list_head        notify_list;
+-      struct mutex            commit_mutex;
+-      unsigned int            base_seq;
+       u8                      gencursor;
+-      u8                      validate_state;
+ };
+ #endif
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -21,10 +21,13 @@
+ #include <net/netfilter/nf_tables.h>
+ #include <net/netfilter/nf_tables_offload.h>
+ #include <net/net_namespace.h>
++#include <net/netns/generic.h>
+ #include <net/sock.h>
+ #define NFT_MODULE_AUTOLOAD_LIMIT (MODULE_NAME_LEN - sizeof("nft-expr-255-"))
++unsigned int nf_tables_net_id __read_mostly;
++
+ static LIST_HEAD(nf_tables_expressions);
+ static LIST_HEAD(nf_tables_objects);
+ static LIST_HEAD(nf_tables_flowtables);
+@@ -103,7 +106,9 @@ static const u8 nft2audit_op[NFT_MSG_MAX
+ static void nft_validate_state_update(struct net *net, u8 new_validate_state)
+ {
+-      switch (net->nft.validate_state) {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
++
++      switch (nft_net->validate_state) {
+       case NFT_VALIDATE_SKIP:
+               WARN_ON_ONCE(new_validate_state == NFT_VALIDATE_DO);
+               break;
+@@ -114,7 +119,7 @@ static void nft_validate_state_update(st
+                       return;
+       }
+-      net->nft.validate_state = new_validate_state;
++      nft_net->validate_state = new_validate_state;
+ }
+ static void nf_tables_trans_destroy_work(struct work_struct *w);
+ static DECLARE_WORK(trans_destroy_work, nf_tables_trans_destroy_work);
+@@ -170,13 +175,15 @@ static void nft_trans_destroy(struct nft
+ static void nft_set_trans_bind(const struct nft_ctx *ctx, struct nft_set *set)
+ {
++      struct nftables_pernet *nft_net;
+       struct net *net = ctx->net;
+       struct nft_trans *trans;
+       if (!nft_set_is_anonymous(set))
+               return;
+-      list_for_each_entry_reverse(trans, &net->nft.commit_list, list) {
++      nft_net = net_generic(net, nf_tables_net_id);
++      list_for_each_entry_reverse(trans, &nft_net->commit_list, list) {
+               switch (trans->msg_type) {
+               case NFT_MSG_NEWSET:
+                       if (nft_trans_set(trans) == set)
+@@ -270,6 +277,14 @@ static void nf_tables_unregister_hook(st
+               nf_unregister_net_hook(net, &basechain->ops);
+ }
++static void nft_trans_commit_list_add_tail(struct net *net, struct nft_trans *trans)
++{
++      struct nftables_pernet *nft_net;
++
++      nft_net = net_generic(net, nf_tables_net_id);
++      list_add_tail(&trans->list, &nft_net->commit_list);
++}
++
+ static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
+ {
+       struct nft_trans *trans;
+@@ -281,7 +296,7 @@ static int nft_trans_table_add(struct nf
+       if (msg_type == NFT_MSG_NEWTABLE)
+               nft_activate_next(ctx->net, ctx->table);
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return 0;
+ }
+@@ -314,7 +329,7 @@ static struct nft_trans *nft_trans_chain
+               }
+       }
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return trans;
+ }
+@@ -387,7 +402,7 @@ static struct nft_trans *nft_trans_rule_
+                       ntohl(nla_get_be32(ctx->nla[NFTA_RULE_ID]));
+       }
+       nft_trans_rule(trans) = rule;
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return trans;
+ }
+@@ -453,7 +468,7 @@ static int nft_trans_set_add(const struc
+               nft_activate_next(ctx->net, set);
+       }
+       nft_trans_set(trans) = set;
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return 0;
+ }
+@@ -485,7 +500,7 @@ static int nft_trans_obj_add(struct nft_
+               nft_activate_next(ctx->net, obj);
+       nft_trans_obj(trans) = obj;
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return 0;
+ }
+@@ -519,7 +534,7 @@ static int nft_trans_flowtable_add(struc
+       INIT_LIST_HEAD(&nft_trans_flowtable_hooks(trans));
+       nft_trans_flowtable(trans) = flowtable;
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return 0;
+ }
+@@ -547,13 +562,15 @@ static struct nft_table *nft_table_looku
+                                         const struct nlattr *nla,
+                                         u8 family, u8 genmask)
+ {
++      struct nftables_pernet *nft_net;
+       struct nft_table *table;
+       if (nla == NULL)
+               return ERR_PTR(-EINVAL);
+-      list_for_each_entry_rcu(table, &net->nft.tables, list,
+-                              lockdep_is_held(&net->nft.commit_mutex)) {
++      nft_net = net_generic(net, nf_tables_net_id);
++      list_for_each_entry_rcu(table, &nft_net->tables, list,
++                              lockdep_is_held(&nft_net->commit_mutex)) {
+               if (!nla_strcmp(nla, table->name) &&
+                   table->family == family &&
+                   nft_active_genmask(table, genmask))
+@@ -567,9 +584,11 @@ static struct nft_table *nft_table_looku
+                                                  const struct nlattr *nla,
+                                                  u8 genmask)
+ {
++      struct nftables_pernet *nft_net;
+       struct nft_table *table;
+-      list_for_each_entry(table, &net->nft.tables, list) {
++      nft_net = net_generic(net, nf_tables_net_id);
++      list_for_each_entry(table, &nft_net->tables, list) {
+               if (be64_to_cpu(nla_get_be64(nla)) == table->handle &&
+                   nft_active_genmask(table, genmask))
+                       return table;
+@@ -621,6 +640,7 @@ struct nft_module_request {
+ static int nft_request_module(struct net *net, const char *fmt, ...)
+ {
+       char module_name[MODULE_NAME_LEN];
++      struct nftables_pernet *nft_net;
+       struct nft_module_request *req;
+       va_list args;
+       int ret;
+@@ -631,7 +651,8 @@ static int nft_request_module(struct net
+       if (ret >= MODULE_NAME_LEN)
+               return 0;
+-      list_for_each_entry(req, &net->nft.module_list, list) {
++      nft_net = net_generic(net, nf_tables_net_id);
++      list_for_each_entry(req, &nft_net->module_list, list) {
+               if (!strcmp(req->module, module_name)) {
+                       if (req->done)
+                               return 0;
+@@ -647,7 +668,7 @@ static int nft_request_module(struct net
+       req->done = false;
+       strlcpy(req->module, module_name, MODULE_NAME_LEN);
+-      list_add_tail(&req->list, &net->nft.module_list);
++      list_add_tail(&req->list, &nft_net->module_list);
+       return -EAGAIN;
+ }
+@@ -685,7 +706,9 @@ nf_tables_chain_type_lookup(struct net *
+ static __be16 nft_base_seq(const struct net *net)
+ {
+-      return htons(net->nft.base_seq & 0xffff);
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
++
++      return htons(nft_net->base_seq & 0xffff);
+ }
+ static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
+@@ -743,6 +766,7 @@ static void nft_notify_enqueue(struct sk
+ static void nf_tables_table_notify(const struct nft_ctx *ctx, int event)
+ {
++      struct nftables_pernet *nft_net;
+       struct sk_buff *skb;
+       int err;
+@@ -761,7 +785,8 @@ static void nf_tables_table_notify(const
+               goto err;
+       }
+-      nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
++      nft_net = net_generic(ctx->net, nf_tables_net_id);
++      nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
+       return;
+ err:
+       nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
+@@ -771,15 +796,17 @@ static int nf_tables_dump_tables(struct
+                                struct netlink_callback *cb)
+ {
+       const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
++      struct nftables_pernet *nft_net;
+       const struct nft_table *table;
+       unsigned int idx = 0, s_idx = cb->args[0];
+       struct net *net = sock_net(skb->sk);
+       int family = nfmsg->nfgen_family;
+       rcu_read_lock();
+-      cb->seq = net->nft.base_seq;
++      nft_net = net_generic(net, nf_tables_net_id);
++      cb->seq = nft_net->base_seq;
+-      list_for_each_entry_rcu(table, &net->nft.tables, list) {
++      list_for_each_entry_rcu(table, &nft_net->tables, list) {
+               if (family != NFPROTO_UNSPEC && family != table->family)
+                       continue;
+@@ -954,7 +981,7 @@ static int nf_tables_updtable(struct nft
+               goto err;
+       nft_trans_table_update(trans) = true;
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return 0;
+ err:
+       nft_trans_destroy(trans);
+@@ -1017,6 +1044,7 @@ static int nf_tables_newtable(struct net
+                             const struct nlattr * const nla[],
+                             struct netlink_ext_ack *extack)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+       u8 genmask = nft_genmask_next(net);
+       int family = nfmsg->nfgen_family;
+@@ -1026,7 +1054,7 @@ static int nf_tables_newtable(struct net
+       u32 flags = 0;
+       int err;
+-      lockdep_assert_held(&net->nft.commit_mutex);
++      lockdep_assert_held(&nft_net->commit_mutex);
+       attr = nla[NFTA_TABLE_NAME];
+       table = nft_table_lookup(net, attr, family, genmask);
+       if (IS_ERR(table)) {
+@@ -1084,7 +1112,7 @@ static int nf_tables_newtable(struct net
+       if (err < 0)
+               goto err_trans;
+-      list_add_tail_rcu(&table->list, &net->nft.tables);
++      list_add_tail_rcu(&table->list, &nft_net->tables);
+       return 0;
+ err_trans:
+       rhltable_destroy(&table->chains_ht);
+@@ -1172,11 +1200,12 @@ out:
+ static int nft_flush(struct nft_ctx *ctx, int family)
+ {
++      struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
+       struct nft_table *table, *nt;
+       const struct nlattr * const *nla = ctx->nla;
+       int err = 0;
+-      list_for_each_entry_safe(table, nt, &ctx->net->nft.tables, list) {
++      list_for_each_entry_safe(table, nt, &nft_net->tables, list) {
+               if (family != AF_UNSPEC && table->family != family)
+                       continue;
+@@ -1291,7 +1320,9 @@ nft_chain_lookup_byhandle(const struct n
+ static bool lockdep_commit_lock_is_held(const struct net *net)
+ {
+ #ifdef CONFIG_PROVE_LOCKING
+-      return lockdep_is_held(&net->nft.commit_mutex);
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
++
++      return lockdep_is_held(&nft_net->commit_mutex);
+ #else
+       return true;
+ #endif
+@@ -1494,6 +1525,7 @@ nla_put_failure:
+ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event)
+ {
++      struct nftables_pernet *nft_net;
+       struct sk_buff *skb;
+       int err;
+@@ -1513,7 +1545,8 @@ static void nf_tables_chain_notify(const
+               goto err;
+       }
+-      nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
++      nft_net = net_generic(ctx->net, nf_tables_net_id);
++      nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
+       return;
+ err:
+       nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
+@@ -1528,11 +1561,13 @@ static int nf_tables_dump_chains(struct
+       unsigned int idx = 0, s_idx = cb->args[0];
+       struct net *net = sock_net(skb->sk);
+       int family = nfmsg->nfgen_family;
++      struct nftables_pernet *nft_net;
+       rcu_read_lock();
+-      cb->seq = net->nft.base_seq;
++      nft_net = net_generic(net, nf_tables_net_id);
++      cb->seq = nft_net->base_seq;
+-      list_for_each_entry_rcu(table, &net->nft.tables, list) {
++      list_for_each_entry_rcu(table, &nft_net->tables, list) {
+               if (family != NFPROTO_UNSPEC && family != table->family)
+                       continue;
+@@ -1847,11 +1882,12 @@ static int nft_chain_parse_hook(struct n
+                               struct nft_chain_hook *hook, u8 family,
+                               bool autoload)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct nlattr *ha[NFTA_HOOK_MAX + 1];
+       const struct nft_chain_type *type;
+       int err;
+-      lockdep_assert_held(&net->nft.commit_mutex);
++      lockdep_assert_held(&nft_net->commit_mutex);
+       lockdep_nfnl_nft_mutex_not_held();
+       err = nla_parse_nested_deprecated(ha, NFTA_HOOK_MAX,
+@@ -2244,6 +2280,7 @@ static int nf_tables_updchain(struct nft
+       if (nla[NFTA_CHAIN_HANDLE] &&
+           nla[NFTA_CHAIN_NAME]) {
++              struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
+               struct nft_trans *tmp;
+               char *name;
+@@ -2253,7 +2290,7 @@ static int nf_tables_updchain(struct nft
+                       goto err;
+               err = -EEXIST;
+-              list_for_each_entry(tmp, &ctx->net->nft.commit_list, list) {
++              list_for_each_entry(tmp, &nft_net->commit_list, list) {
+                       if (tmp->msg_type == NFT_MSG_NEWCHAIN &&
+                           tmp->ctx.table == table &&
+                           nft_trans_chain_update(tmp) &&
+@@ -2267,7 +2304,7 @@ static int nf_tables_updchain(struct nft
+               nft_trans_chain_name(trans) = name;
+       }
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return 0;
+ err:
+@@ -2280,10 +2317,11 @@ static struct nft_chain *nft_chain_looku
+                                              const struct nft_table *table,
+                                              const struct nlattr *nla)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       u32 id = ntohl(nla_get_be32(nla));
+       struct nft_trans *trans;
+-      list_for_each_entry(trans, &net->nft.commit_list, list) {
++      list_for_each_entry(trans, &nft_net->commit_list, list) {
+               struct nft_chain *chain = trans->ctx.chain;
+               if (trans->msg_type == NFT_MSG_NEWCHAIN &&
+@@ -2299,6 +2337,7 @@ static int nf_tables_newchain(struct net
+                             const struct nlattr * const nla[],
+                             struct netlink_ext_ack *extack)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+       u8 genmask = nft_genmask_next(net);
+       int family = nfmsg->nfgen_family;
+@@ -2310,7 +2349,7 @@ static int nf_tables_newchain(struct net
+       u64 handle = 0;
+       u32 flags = 0;
+-      lockdep_assert_held(&net->nft.commit_mutex);
++      lockdep_assert_held(&nft_net->commit_mutex);
+       table = nft_table_lookup(net, nla[NFTA_CHAIN_TABLE], family, genmask);
+       if (IS_ERR(table)) {
+@@ -2848,6 +2887,7 @@ nla_put_failure:
+ static void nf_tables_rule_notify(const struct nft_ctx *ctx,
+                                 const struct nft_rule *rule, int event)
+ {
++      struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
+       struct sk_buff *skb;
+       int err;
+@@ -2867,7 +2907,7 @@ static void nf_tables_rule_notify(const
+               goto err;
+       }
+-      nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
++      nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
+       return;
+ err:
+       nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
+@@ -2925,11 +2965,13 @@ static int nf_tables_dump_rules(struct s
+       unsigned int idx = 0;
+       struct net *net = sock_net(skb->sk);
+       int family = nfmsg->nfgen_family;
++      struct nftables_pernet *nft_net;
+       rcu_read_lock();
+-      cb->seq = net->nft.base_seq;
++      nft_net = net_generic(net, nf_tables_net_id);
++      cb->seq = nft_net->base_seq;
+-      list_for_each_entry_rcu(table, &net->nft.tables, list) {
++      list_for_each_entry_rcu(table, &nft_net->tables, list) {
+               if (family != NFPROTO_UNSPEC && family != table->family)
+                       continue;
+@@ -3161,6 +3203,7 @@ static int nf_tables_newrule(struct net
+                            const struct nlattr * const nla[],
+                            struct netlink_ext_ack *extack)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+       u8 genmask = nft_genmask_next(net);
+       struct nft_expr_info *info = NULL;
+@@ -3178,7 +3221,7 @@ static int nf_tables_newrule(struct net
+       int err, rem;
+       u64 handle, pos_handle;
+-      lockdep_assert_held(&net->nft.commit_mutex);
++      lockdep_assert_held(&nft_net->commit_mutex);
+       table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask);
+       if (IS_ERR(table)) {
+@@ -3351,7 +3394,7 @@ static int nf_tables_newrule(struct net
+       kvfree(info);
+       chain->use++;
+-      if (net->nft.validate_state == NFT_VALIDATE_DO)
++      if (nft_net->validate_state == NFT_VALIDATE_DO)
+               return nft_table_validate(net, table);
+       if (chain->flags & NFT_CHAIN_HW_OFFLOAD) {
+@@ -3381,10 +3424,11 @@ static struct nft_rule *nft_rule_lookup_
+                                            const struct nft_chain *chain,
+                                            const struct nlattr *nla)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       u32 id = ntohl(nla_get_be32(nla));
+       struct nft_trans *trans;
+-      list_for_each_entry(trans, &net->nft.commit_list, list) {
++      list_for_each_entry(trans, &nft_net->commit_list, list) {
+               struct nft_rule *rule = nft_trans_rule(trans);
+               if (trans->msg_type == NFT_MSG_NEWRULE &&
+@@ -3497,13 +3541,14 @@ nft_select_set_ops(const struct nft_ctx
+                  const struct nft_set_desc *desc,
+                  enum nft_set_policies policy)
+ {
++      struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
+       const struct nft_set_ops *ops, *bops;
+       struct nft_set_estimate est, best;
+       const struct nft_set_type *type;
+       u32 flags = 0;
+       int i;
+-      lockdep_assert_held(&ctx->net->nft.commit_mutex);
++      lockdep_assert_held(&nft_net->commit_mutex);
+       lockdep_nfnl_nft_mutex_not_held();
+       if (nla[NFTA_SET_FLAGS] != NULL)
+@@ -3641,10 +3686,11 @@ static struct nft_set *nft_set_lookup_by
+                                          const struct nft_table *table,
+                                          const struct nlattr *nla, u8 genmask)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct nft_trans *trans;
+       u32 id = ntohl(nla_get_be32(nla));
+-      list_for_each_entry(trans, &net->nft.commit_list, list) {
++      list_for_each_entry(trans, &nft_net->commit_list, list) {
+               if (trans->msg_type == NFT_MSG_NEWSET) {
+                       struct nft_set *set = nft_trans_set(trans);
+@@ -3867,6 +3913,7 @@ static void nf_tables_set_notify(const s
+                                const struct nft_set *set, int event,
+                                gfp_t gfp_flags)
+ {
++      struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
+       struct sk_buff *skb;
+       u32 portid = ctx->portid;
+       int err;
+@@ -3885,7 +3932,7 @@ static void nf_tables_set_notify(const s
+               goto err;
+       }
+-      nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
++      nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
+       return;
+ err:
+       nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
+@@ -3898,14 +3945,16 @@ static int nf_tables_dump_sets(struct sk
+       struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
+       struct net *net = sock_net(skb->sk);
+       struct nft_ctx *ctx = cb->data, ctx_set;
++      struct nftables_pernet *nft_net;
+       if (cb->args[1])
+               return skb->len;
+       rcu_read_lock();
+-      cb->seq = net->nft.base_seq;
++      nft_net = net_generic(net, nf_tables_net_id);
++      cb->seq = nft_net->base_seq;
+-      list_for_each_entry_rcu(table, &net->nft.tables, list) {
++      list_for_each_entry_rcu(table, &nft_net->tables, list) {
+               if (ctx->family != NFPROTO_UNSPEC &&
+                   ctx->family != table->family)
+                       continue;
+@@ -4706,6 +4755,7 @@ static int nf_tables_dump_set(struct sk_
+ {
+       struct nft_set_dump_ctx *dump_ctx = cb->data;
+       struct net *net = sock_net(skb->sk);
++      struct nftables_pernet *nft_net;
+       struct nft_table *table;
+       struct nft_set *set;
+       struct nft_set_dump_args args;
+@@ -4716,7 +4766,8 @@ static int nf_tables_dump_set(struct sk_
+       int event;
+       rcu_read_lock();
+-      list_for_each_entry_rcu(table, &net->nft.tables, list) {
++      nft_net = net_generic(net, nf_tables_net_id);
++      list_for_each_entry_rcu(table, &nft_net->tables, list) {
+               if (dump_ctx->ctx.family != NFPROTO_UNSPEC &&
+                   dump_ctx->ctx.family != table->family)
+                       continue;
+@@ -4995,6 +5046,7 @@ static void nf_tables_setelem_notify(con
+                                    const struct nft_set_elem *elem,
+                                    int event, u16 flags)
+ {
++      struct nftables_pernet *nft_net;
+       struct net *net = ctx->net;
+       u32 portid = ctx->portid;
+       struct sk_buff *skb;
+@@ -5014,7 +5066,8 @@ static void nf_tables_setelem_notify(con
+               goto err;
+       }
+-      nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
++      nft_net = net_generic(net, nf_tables_net_id);
++      nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
+       return;
+ err:
+       nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
+@@ -5410,7 +5463,7 @@ static int nft_add_set_elem(struct nft_c
+       }
+       nft_trans_elem(trans) = elem;
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return 0;
+ err_set_full:
+@@ -5441,6 +5494,7 @@ static int nf_tables_newsetelem(struct n
+                               const struct nlattr * const nla[],
+                               struct netlink_ext_ack *extack)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       u8 genmask = nft_genmask_next(net);
+       const struct nlattr *attr;
+       struct nft_set *set;
+@@ -5470,7 +5524,7 @@ static int nf_tables_newsetelem(struct n
+                       return err;
+       }
+-      if (net->nft.validate_state == NFT_VALIDATE_DO)
++      if (nft_net->validate_state == NFT_VALIDATE_DO)
+               return nft_table_validate(net, ctx.table);
+       return 0;
+@@ -5606,7 +5660,7 @@ static int nft_del_setelem(struct nft_ct
+       nft_set_elem_deactivate(ctx->net, set, &elem);
+       nft_trans_elem(trans) = elem;
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return 0;
+ fail_ops:
+@@ -5640,7 +5694,7 @@ static int nft_flush_set(const struct nf
+       nft_set_elem_deactivate(ctx->net, set, elem);
+       nft_trans_elem_set(trans) = set;
+       nft_trans_elem(trans) = *elem;
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return 0;
+ err1:
+@@ -5939,7 +5993,7 @@ static int nf_tables_updobj(const struct
+       nft_trans_obj(trans) = obj;
+       nft_trans_obj_update(trans) = true;
+       nft_trans_obj_newobj(trans) = newobj;
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return 0;
+@@ -6102,6 +6156,7 @@ static int nf_tables_dump_obj(struct sk_
+       struct nft_obj_filter *filter = cb->data;
+       struct net *net = sock_net(skb->sk);
+       int family = nfmsg->nfgen_family;
++      struct nftables_pernet *nft_net;
+       struct nft_object *obj;
+       bool reset = false;
+@@ -6109,9 +6164,10 @@ static int nf_tables_dump_obj(struct sk_
+               reset = true;
+       rcu_read_lock();
+-      cb->seq = net->nft.base_seq;
++      nft_net = net_generic(net, nf_tables_net_id);
++      cb->seq = nft_net->base_seq;
+-      list_for_each_entry_rcu(table, &net->nft.tables, list) {
++      list_for_each_entry_rcu(table, &nft_net->tables, list) {
+               if (family != NFPROTO_UNSPEC && family != table->family)
+                       continue;
+@@ -6134,7 +6190,7 @@ static int nf_tables_dump_obj(struct sk_
+                               char *buf = kasprintf(GFP_ATOMIC,
+                                                     "%s:%u",
+                                                     table->name,
+-                                                    net->nft.base_seq);
++                                                    nft_net->base_seq);
+                               audit_log_nfcfg(buf,
+                                               family,
+@@ -6255,8 +6311,11 @@ static int nf_tables_getobj(struct net *
+               reset = true;
+       if (reset) {
+-              char *buf = kasprintf(GFP_ATOMIC, "%s:%u",
+-                                    table->name, net->nft.base_seq);
++              const struct nftables_pernet *nft_net;
++              char *buf;
++
++              nft_net = net_generic(net, nf_tables_net_id);
++              buf = kasprintf(GFP_ATOMIC, "%s:%u", table->name, nft_net->base_seq);
+               audit_log_nfcfg(buf,
+                               family,
+@@ -6341,10 +6400,11 @@ void nft_obj_notify(struct net *net, con
+                   struct nft_object *obj, u32 portid, u32 seq, int event,
+                   int family, int report, gfp_t gfp)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct sk_buff *skb;
+       int err;
+       char *buf = kasprintf(gfp, "%s:%u",
+-                            table->name, net->nft.base_seq);
++                            table->name, nft_net->base_seq);
+       audit_log_nfcfg(buf,
+                       family,
+@@ -6370,7 +6430,7 @@ void nft_obj_notify(struct net *net, con
+               goto err;
+       }
+-      nft_notify_enqueue(skb, report, &net->nft.notify_list);
++      nft_notify_enqueue(skb, report, &nft_net->notify_list);
+       return;
+ err:
+       nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
+@@ -6706,7 +6766,7 @@ static int nft_flowtable_update(struct n
+       INIT_LIST_HEAD(&nft_trans_flowtable_hooks(trans));
+       list_splice(&flowtable_hook.list, &nft_trans_flowtable_hooks(trans));
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return 0;
+@@ -6896,7 +6956,7 @@ static int nft_delflowtable_hook(struct
+       list_splice(&flowtable_del_list, &nft_trans_flowtable_hooks(trans));
+       nft_flowtable_hook_release(&flowtable_hook);
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return 0;
+@@ -7022,12 +7082,14 @@ static int nf_tables_dump_flowtable(stru
+       struct net *net = sock_net(skb->sk);
+       int family = nfmsg->nfgen_family;
+       struct nft_flowtable *flowtable;
++      struct nftables_pernet *nft_net;
+       const struct nft_table *table;
+       rcu_read_lock();
+-      cb->seq = net->nft.base_seq;
++      nft_net = net_generic(net, nf_tables_net_id);
++      cb->seq = nft_net->base_seq;
+-      list_for_each_entry_rcu(table, &net->nft.tables, list) {
++      list_for_each_entry_rcu(table, &nft_net->tables, list) {
+               if (family != NFPROTO_UNSPEC && family != table->family)
+                       continue;
+@@ -7162,6 +7224,7 @@ static void nf_tables_flowtable_notify(s
+                                      struct list_head *hook_list,
+                                      int event)
+ {
++      struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
+       struct sk_buff *skb;
+       int err;
+@@ -7181,7 +7244,7 @@ static void nf_tables_flowtable_notify(s
+               goto err;
+       }
+-      nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
++      nft_notify_enqueue(skb, ctx->report, &nft_net->notify_list);
+       return;
+ err:
+       nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
+@@ -7206,6 +7269,7 @@ static void nf_tables_flowtable_destroy(
+ static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net,
+                                  u32 portid, u32 seq)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct nlmsghdr *nlh;
+       char buf[TASK_COMM_LEN];
+       int event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWGEN);
+@@ -7215,7 +7279,7 @@ static int nf_tables_fill_gen_info(struc
+       if (!nlh)
+               goto nla_put_failure;
+-      if (nla_put_be32(skb, NFTA_GEN_ID, htonl(net->nft.base_seq)) ||
++      if (nla_put_be32(skb, NFTA_GEN_ID, htonl(nft_net->base_seq)) ||
+           nla_put_be32(skb, NFTA_GEN_PROC_PID, htonl(task_pid_nr(current))) ||
+           nla_put_string(skb, NFTA_GEN_PROC_NAME, get_task_comm(buf, current)))
+               goto nla_put_failure;
+@@ -7250,6 +7314,7 @@ static int nf_tables_flowtable_event(str
+ {
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+       struct nft_flowtable *flowtable;
++      struct nftables_pernet *nft_net;
+       struct nft_table *table;
+       struct net *net;
+@@ -7257,13 +7322,14 @@ static int nf_tables_flowtable_event(str
+               return 0;
+       net = dev_net(dev);
+-      mutex_lock(&net->nft.commit_mutex);
+-      list_for_each_entry(table, &net->nft.tables, list) {
++      nft_net = net_generic(net, nf_tables_net_id);
++      mutex_lock(&nft_net->commit_mutex);
++      list_for_each_entry(table, &nft_net->tables, list) {
+               list_for_each_entry(flowtable, &table->flowtables, list) {
+                       nft_flowtable_event(event, dev, flowtable);
+               }
+       }
+-      mutex_unlock(&net->nft.commit_mutex);
++      mutex_unlock(&nft_net->commit_mutex);
+       return NOTIFY_DONE;
+ }
+@@ -7444,16 +7510,17 @@ static const struct nfnl_callback nf_tab
+ static int nf_tables_validate(struct net *net)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct nft_table *table;
+-      switch (net->nft.validate_state) {
++      switch (nft_net->validate_state) {
+       case NFT_VALIDATE_SKIP:
+               break;
+       case NFT_VALIDATE_NEED:
+               nft_validate_state_update(net, NFT_VALIDATE_DO);
+               fallthrough;
+       case NFT_VALIDATE_DO:
+-              list_for_each_entry(table, &net->nft.tables, list) {
++              list_for_each_entry(table, &nft_net->tables, list) {
+                       if (nft_table_validate(net, table) < 0)
+                               return -EAGAIN;
+               }
+@@ -7630,9 +7697,10 @@ static int nf_tables_commit_chain_prepar
+ static void nf_tables_commit_chain_prepare_cancel(struct net *net)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct nft_trans *trans, *next;
+-      list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
++      list_for_each_entry_safe(trans, next, &nft_net->commit_list, list) {
+               struct nft_chain *chain = trans->ctx.chain;
+               if (trans->msg_type == NFT_MSG_NEWRULE ||
+@@ -7730,10 +7798,11 @@ void nft_chain_del(struct nft_chain *cha
+ static void nf_tables_module_autoload_cleanup(struct net *net)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct nft_module_request *req, *next;
+-      WARN_ON_ONCE(!list_empty(&net->nft.commit_list));
+-      list_for_each_entry_safe(req, next, &net->nft.module_list, list) {
++      WARN_ON_ONCE(!list_empty(&nft_net->commit_list));
++      list_for_each_entry_safe(req, next, &nft_net->module_list, list) {
+               WARN_ON_ONCE(!req->done);
+               list_del(&req->list);
+               kfree(req);
+@@ -7742,6 +7811,7 @@ static void nf_tables_module_autoload_cl
+ static void nf_tables_commit_release(struct net *net)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct nft_trans *trans;
+       /* all side effects have to be made visible.
+@@ -7751,35 +7821,36 @@ static void nf_tables_commit_release(str
+        * Memory reclaim happens asynchronously from work queue
+        * to prevent expensive synchronize_rcu() in commit phase.
+        */
+-      if (list_empty(&net->nft.commit_list)) {
++      if (list_empty(&nft_net->commit_list)) {
+               nf_tables_module_autoload_cleanup(net);
+-              mutex_unlock(&net->nft.commit_mutex);
++              mutex_unlock(&nft_net->commit_mutex);
+               return;
+       }
+-      trans = list_last_entry(&net->nft.commit_list,
++      trans = list_last_entry(&nft_net->commit_list,
+                               struct nft_trans, list);
+       get_net(trans->ctx.net);
+       WARN_ON_ONCE(trans->put_net);
+       trans->put_net = true;
+       spin_lock(&nf_tables_destroy_list_lock);
+-      list_splice_tail_init(&net->nft.commit_list, &nf_tables_destroy_list);
++      list_splice_tail_init(&nft_net->commit_list, &nf_tables_destroy_list);
+       spin_unlock(&nf_tables_destroy_list_lock);
+       nf_tables_module_autoload_cleanup(net);
+       schedule_work(&trans_destroy_work);
+-      mutex_unlock(&net->nft.commit_mutex);
++      mutex_unlock(&nft_net->commit_mutex);
+ }
+ static void nft_commit_notify(struct net *net, u32 portid)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct sk_buff *batch_skb = NULL, *nskb, *skb;
+       unsigned char *data;
+       int len;
+-      list_for_each_entry_safe(skb, nskb, &net->nft.notify_list, list) {
++      list_for_each_entry_safe(skb, nskb, &nft_net->notify_list, list) {
+               if (!batch_skb) {
+ new_batch:
+                       batch_skb = skb;
+@@ -7805,7 +7876,7 @@ new_batch:
+                              NFT_CB(batch_skb).report, GFP_KERNEL);
+       }
+-      WARN_ON_ONCE(!list_empty(&net->nft.notify_list));
++      WARN_ON_ONCE(!list_empty(&nft_net->notify_list));
+ }
+ static int nf_tables_commit_audit_alloc(struct list_head *adl,
+@@ -7871,6 +7942,7 @@ static void nf_tables_commit_audit_log(s
+ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct nft_trans *trans, *next;
+       struct nft_trans_elem *te;
+       struct nft_chain *chain;
+@@ -7878,8 +7950,8 @@ static int nf_tables_commit(struct net *
+       LIST_HEAD(adl);
+       int err;
+-      if (list_empty(&net->nft.commit_list)) {
+-              mutex_unlock(&net->nft.commit_mutex);
++      if (list_empty(&nft_net->commit_list)) {
++              mutex_unlock(&nft_net->commit_mutex);
+               return 0;
+       }
+@@ -7892,7 +7964,7 @@ static int nf_tables_commit(struct net *
+               return err;
+       /* 1.  Allocate space for next generation rules_gen_X[] */
+-      list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
++      list_for_each_entry_safe(trans, next, &nft_net->commit_list, list) {
+               int ret;
+               ret = nf_tables_commit_audit_alloc(&adl, trans->ctx.table);
+@@ -7915,7 +7987,7 @@ static int nf_tables_commit(struct net *
+       }
+       /* step 2.  Make rules_gen_X visible to packet path */
+-      list_for_each_entry(table, &net->nft.tables, list) {
++      list_for_each_entry(table, &nft_net->tables, list) {
+               list_for_each_entry(chain, &table->chains, list)
+                       nf_tables_commit_chain(net, chain);
+       }
+@@ -7924,12 +7996,13 @@ static int nf_tables_commit(struct net *
+        * Bump generation counter, invalidate any dump in progress.
+        * Cannot fail after this point.
+        */
+-      while (++net->nft.base_seq == 0);
++      while (++nft_net->base_seq == 0)
++              ;
+       /* step 3. Start new generation, rules_gen_X now in use. */
+       net->nft.gencursor = nft_gencursor_next(net);
+-      list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
++      list_for_each_entry_safe(trans, next, &nft_net->commit_list, list) {
+               nf_tables_commit_audit_collect(&adl, trans->ctx.table,
+                                              trans->msg_type);
+               switch (trans->msg_type) {
+@@ -8089,7 +8162,7 @@ static int nf_tables_commit(struct net *
+       nft_commit_notify(net, NETLINK_CB(skb).portid);
+       nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
+-      nf_tables_commit_audit_log(&adl, net->nft.base_seq);
++      nf_tables_commit_audit_log(&adl, nft_net->base_seq);
+       nf_tables_commit_release(net);
+       return 0;
+@@ -8097,17 +8170,18 @@ static int nf_tables_commit(struct net *
+ static void nf_tables_module_autoload(struct net *net)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct nft_module_request *req, *next;
+       LIST_HEAD(module_list);
+-      list_splice_init(&net->nft.module_list, &module_list);
+-      mutex_unlock(&net->nft.commit_mutex);
++      list_splice_init(&nft_net->module_list, &module_list);
++      mutex_unlock(&nft_net->commit_mutex);
+       list_for_each_entry_safe(req, next, &module_list, list) {
+               request_module("%s", req->module);
+               req->done = true;
+       }
+-      mutex_lock(&net->nft.commit_mutex);
+-      list_splice(&module_list, &net->nft.module_list);
++      mutex_lock(&nft_net->commit_mutex);
++      list_splice(&module_list, &nft_net->module_list);
+ }
+ static void nf_tables_abort_release(struct nft_trans *trans)
+@@ -8144,6 +8218,7 @@ static void nf_tables_abort_release(stru
+ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct nft_trans *trans, *next;
+       struct nft_trans_elem *te;
+@@ -8151,7 +8226,7 @@ static int __nf_tables_abort(struct net
+           nf_tables_validate(net) < 0)
+               return -EAGAIN;
+-      list_for_each_entry_safe_reverse(trans, next, &net->nft.commit_list,
++      list_for_each_entry_safe_reverse(trans, next, &nft_net->commit_list,
+                                        list) {
+               switch (trans->msg_type) {
+               case NFT_MSG_NEWTABLE:
+@@ -8277,7 +8352,7 @@ static int __nf_tables_abort(struct net
+       synchronize_rcu();
+       list_for_each_entry_safe_reverse(trans, next,
+-                                       &net->nft.commit_list, list) {
++                                       &nft_net->commit_list, list) {
+               list_del(&trans->list);
+               nf_tables_abort_release(trans);
+       }
+@@ -8293,22 +8368,24 @@ static int __nf_tables_abort(struct net
+ static int nf_tables_abort(struct net *net, struct sk_buff *skb,
+                          enum nfnl_abort_action action)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       int ret = __nf_tables_abort(net, action);
+-      mutex_unlock(&net->nft.commit_mutex);
++      mutex_unlock(&nft_net->commit_mutex);
+       return ret;
+ }
+ static bool nf_tables_valid_genid(struct net *net, u32 genid)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       bool genid_ok;
+-      mutex_lock(&net->nft.commit_mutex);
++      mutex_lock(&nft_net->commit_mutex);
+-      genid_ok = genid == 0 || net->nft.base_seq == genid;
++      genid_ok = genid == 0 || nft_net->base_seq == genid;
+       if (!genid_ok)
+-              mutex_unlock(&net->nft.commit_mutex);
++              mutex_unlock(&nft_net->commit_mutex);
+       /* else, commit mutex has to be released by commit or abort function */
+       return genid_ok;
+@@ -8909,19 +8986,19 @@ EXPORT_SYMBOL_GPL(__nft_release_basechai
+ static void __nft_release_hooks(struct net *net)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct nft_table *table;
+       struct nft_chain *chain;
+-      list_for_each_entry(table, &net->nft.tables, list) {
++      list_for_each_entry(table, &nft_net->tables, list) {
+               list_for_each_entry(chain, &table->chains, list)
+                       nf_tables_unregister_hook(net, table, chain);
+       }
+ }
+-static void __nft_release_tables(struct net *net)
++static void __nft_release_table(struct net *net, struct nft_table *table)
+ {
+       struct nft_flowtable *flowtable, *nf;
+-      struct nft_table *table, *nt;
+       struct nft_chain *chain, *nc;
+       struct nft_object *obj, *ne;
+       struct nft_rule *rule, *nr;
+@@ -8931,79 +9008,94 @@ static void __nft_release_tables(struct
+               .family = NFPROTO_NETDEV,
+       };
+-      list_for_each_entry_safe(table, nt, &net->nft.tables, list) {
+-              ctx.family = table->family;
+-              ctx.table = table;
+-              list_for_each_entry(chain, &table->chains, list) {
+-                      ctx.chain = chain;
+-                      list_for_each_entry_safe(rule, nr, &chain->rules, list) {
+-                              list_del(&rule->list);
+-                              chain->use--;
+-                              nf_tables_rule_release(&ctx, rule);
+-                      }
+-              }
+-              list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) {
+-                      list_del(&flowtable->list);
+-                      table->use--;
+-                      nf_tables_flowtable_destroy(flowtable);
+-              }
+-              list_for_each_entry_safe(set, ns, &table->sets, list) {
+-                      list_del(&set->list);
+-                      table->use--;
+-                      nft_set_destroy(&ctx, set);
+-              }
+-              list_for_each_entry_safe(obj, ne, &table->objects, list) {
+-                      nft_obj_del(obj);
+-                      table->use--;
+-                      nft_obj_destroy(&ctx, obj);
+-              }
+-              list_for_each_entry_safe(chain, nc, &table->chains, list) {
+-                      ctx.chain = chain;
+-                      nft_chain_del(chain);
+-                      table->use--;
+-                      nf_tables_chain_destroy(&ctx);
++      ctx.family = table->family;
++      ctx.table = table;
++      list_for_each_entry(chain, &table->chains, list) {
++              ctx.chain = chain;
++              list_for_each_entry_safe(rule, nr, &chain->rules, list) {
++                      list_del(&rule->list);
++                      chain->use--;
++                      nf_tables_rule_release(&ctx, rule);
+               }
+-              list_del(&table->list);
+-              nf_tables_table_destroy(&ctx);
+       }
++      list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) {
++              list_del(&flowtable->list);
++              table->use--;
++              nf_tables_flowtable_destroy(flowtable);
++      }
++      list_for_each_entry_safe(set, ns, &table->sets, list) {
++              list_del(&set->list);
++              table->use--;
++              nft_set_destroy(&ctx, set);
++      }
++      list_for_each_entry_safe(obj, ne, &table->objects, list) {
++              nft_obj_del(obj);
++              table->use--;
++              nft_obj_destroy(&ctx, obj);
++      }
++      list_for_each_entry_safe(chain, nc, &table->chains, list) {
++              ctx.chain = chain;
++              nft_chain_del(chain);
++              table->use--;
++              nf_tables_chain_destroy(&ctx);
++      }
++      list_del(&table->list);
++      nf_tables_table_destroy(&ctx);
++}
++
++static void __nft_release_tables(struct net *net)
++{
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
++      struct nft_table *table, *nt;
++
++      list_for_each_entry_safe(table, nt, &nft_net->tables, list)
++              __nft_release_table(net, table);
+ }
+ static int __net_init nf_tables_init_net(struct net *net)
+ {
+-      INIT_LIST_HEAD(&net->nft.tables);
+-      INIT_LIST_HEAD(&net->nft.commit_list);
+-      INIT_LIST_HEAD(&net->nft.module_list);
+-      INIT_LIST_HEAD(&net->nft.notify_list);
+-      mutex_init(&net->nft.commit_mutex);
+-      net->nft.base_seq = 1;
+-      net->nft.validate_state = NFT_VALIDATE_SKIP;
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
++
++      INIT_LIST_HEAD(&nft_net->tables);
++      INIT_LIST_HEAD(&nft_net->commit_list);
++      INIT_LIST_HEAD(&nft_net->module_list);
++      INIT_LIST_HEAD(&nft_net->notify_list);
++      mutex_init(&nft_net->commit_mutex);
++      nft_net->base_seq = 1;
++      nft_net->validate_state = NFT_VALIDATE_SKIP;
+       return 0;
+ }
+ static void __net_exit nf_tables_pre_exit_net(struct net *net)
+ {
+-      mutex_lock(&net->nft.commit_mutex);
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
++
++      mutex_lock(&nft_net->commit_mutex);
+       __nft_release_hooks(net);
+-      mutex_unlock(&net->nft.commit_mutex);
++      mutex_unlock(&nft_net->commit_mutex);
+ }
+ static void __net_exit nf_tables_exit_net(struct net *net)
+ {
+-      mutex_lock(&net->nft.commit_mutex);
+-      if (!list_empty(&net->nft.commit_list))
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
++
++      mutex_lock(&nft_net->commit_mutex);
++      if (!list_empty(&nft_net->commit_list))
+               __nf_tables_abort(net, NFNL_ABORT_NONE);
+       __nft_release_tables(net);
+-      mutex_unlock(&net->nft.commit_mutex);
+-      WARN_ON_ONCE(!list_empty(&net->nft.tables));
+-      WARN_ON_ONCE(!list_empty(&net->nft.module_list));
+-      WARN_ON_ONCE(!list_empty(&net->nft.notify_list));
++      mutex_unlock(&nft_net->commit_mutex);
++      WARN_ON_ONCE(!list_empty(&nft_net->tables));
++      WARN_ON_ONCE(!list_empty(&nft_net->module_list));
++      WARN_ON_ONCE(!list_empty(&nft_net->notify_list));
+ }
+ static struct pernet_operations nf_tables_net_ops = {
+       .init           = nf_tables_init_net,
+       .pre_exit       = nf_tables_pre_exit_net,
+       .exit           = nf_tables_exit_net,
++      .id             = &nf_tables_net_id,
++      .size           = sizeof(struct nftables_pernet),
+ };
+ static int __init nf_tables_module_init(void)
+--- a/net/netfilter/nf_tables_offload.c
++++ b/net/netfilter/nf_tables_offload.c
+@@ -7,6 +7,8 @@
+ #include <net/netfilter/nf_tables_offload.h>
+ #include <net/pkt_cls.h>
++extern unsigned int nf_tables_net_id;
++
+ static struct nft_flow_rule *nft_flow_rule_alloc(int num_actions)
+ {
+       struct nft_flow_rule *flow;
+@@ -371,16 +373,18 @@ static void nft_indr_block_cleanup(struc
+       struct nft_base_chain *basechain = block_cb->indr.data;
+       struct net_device *dev = block_cb->indr.dev;
+       struct netlink_ext_ack extack = {};
++      struct nftables_pernet *nft_net;
+       struct net *net = dev_net(dev);
+       struct flow_block_offload bo;
+       nft_flow_block_offload_init(&bo, dev_net(dev), FLOW_BLOCK_UNBIND,
+                                   basechain, &extack);
+-      mutex_lock(&net->nft.commit_mutex);
++      nft_net = net_generic(net, nf_tables_net_id);
++      mutex_lock(&nft_net->commit_mutex);
+       list_del(&block_cb->driver_list);
+       list_move(&block_cb->list, &bo.cb_list);
+       nft_flow_offload_unbind(&bo, basechain);
+-      mutex_unlock(&net->nft.commit_mutex);
++      mutex_unlock(&nft_net->commit_mutex);
+ }
+ static int nft_indr_block_offload_cmd(struct nft_base_chain *basechain,
+@@ -476,9 +480,10 @@ static int nft_flow_offload_chain(struct
+ static void nft_flow_rule_offload_abort(struct net *net,
+                                       struct nft_trans *trans)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       int err = 0;
+-      list_for_each_entry_continue_reverse(trans, &net->nft.commit_list, list) {
++      list_for_each_entry_continue_reverse(trans, &nft_net->commit_list, list) {
+               if (trans->ctx.family != NFPROTO_NETDEV)
+                       continue;
+@@ -524,11 +529,12 @@ static void nft_flow_rule_offload_abort(
+ int nft_flow_rule_offload_commit(struct net *net)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct nft_trans *trans;
+       int err = 0;
+       u8 policy;
+-      list_for_each_entry(trans, &net->nft.commit_list, list) {
++      list_for_each_entry(trans, &nft_net->commit_list, list) {
+               if (trans->ctx.family != NFPROTO_NETDEV)
+                       continue;
+@@ -580,7 +586,7 @@ int nft_flow_rule_offload_commit(struct
+               }
+       }
+-      list_for_each_entry(trans, &net->nft.commit_list, list) {
++      list_for_each_entry(trans, &nft_net->commit_list, list) {
+               if (trans->ctx.family != NFPROTO_NETDEV)
+                       continue;
+@@ -600,15 +606,15 @@ int nft_flow_rule_offload_commit(struct
+       return err;
+ }
+-static struct nft_chain *__nft_offload_get_chain(struct net_device *dev)
++static struct nft_chain *__nft_offload_get_chain(const struct nftables_pernet *nft_net,
++                                               struct net_device *dev)
+ {
+       struct nft_base_chain *basechain;
+-      struct net *net = dev_net(dev);
+       struct nft_hook *hook, *found;
+       const struct nft_table *table;
+       struct nft_chain *chain;
+-      list_for_each_entry(table, &net->nft.tables, list) {
++      list_for_each_entry(table, &nft_net->tables, list) {
+               if (table->family != NFPROTO_NETDEV)
+                       continue;
+@@ -640,19 +646,21 @@ static int nft_offload_netdev_event(stru
+                                   unsigned long event, void *ptr)
+ {
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
++      struct nftables_pernet *nft_net;
+       struct net *net = dev_net(dev);
+       struct nft_chain *chain;
+       if (event != NETDEV_UNREGISTER)
+               return NOTIFY_DONE;
+-      mutex_lock(&net->nft.commit_mutex);
+-      chain = __nft_offload_get_chain(dev);
++      nft_net = net_generic(net, nf_tables_net_id);
++      mutex_lock(&nft_net->commit_mutex);
++      chain = __nft_offload_get_chain(nft_net, dev);
+       if (chain)
+               nft_flow_block_chain(nft_base_chain(chain), dev,
+                                    FLOW_BLOCK_UNBIND);
+-      mutex_unlock(&net->nft.commit_mutex);
++      mutex_unlock(&nft_net->commit_mutex);
+       return NOTIFY_DONE;
+ }
+--- a/net/netfilter/nft_chain_filter.c
++++ b/net/netfilter/nft_chain_filter.c
+@@ -2,6 +2,7 @@
+ #include <linux/kernel.h>
+ #include <linux/netdevice.h>
+ #include <net/net_namespace.h>
++#include <net/netns/generic.h>
+ #include <net/netfilter/nf_tables.h>
+ #include <linux/netfilter_ipv4.h>
+ #include <linux/netfilter_ipv6.h>
+@@ -10,6 +11,8 @@
+ #include <net/netfilter/nf_tables_ipv4.h>
+ #include <net/netfilter/nf_tables_ipv6.h>
++extern unsigned int nf_tables_net_id;
++
+ #ifdef CONFIG_NF_TABLES_IPV4
+ static unsigned int nft_do_chain_ipv4(void *priv,
+                                     struct sk_buff *skb,
+@@ -355,6 +358,7 @@ static int nf_tables_netdev_event(struct
+                                 unsigned long event, void *ptr)
+ {
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
++      struct nftables_pernet *nft_net;
+       struct nft_table *table;
+       struct nft_chain *chain, *nr;
+       struct nft_ctx ctx = {
+@@ -365,8 +369,9 @@ static int nf_tables_netdev_event(struct
+           event != NETDEV_CHANGENAME)
+               return NOTIFY_DONE;
+-      mutex_lock(&ctx.net->nft.commit_mutex);
+-      list_for_each_entry(table, &ctx.net->nft.tables, list) {
++      nft_net = net_generic(ctx.net, nf_tables_net_id);
++      mutex_lock(&nft_net->commit_mutex);
++      list_for_each_entry(table, &nft_net->tables, list) {
+               if (table->family != NFPROTO_NETDEV)
+                       continue;
+@@ -380,7 +385,7 @@ static int nf_tables_netdev_event(struct
+                       nft_netdev_event(event, dev, &ctx);
+               }
+       }
+-      mutex_unlock(&ctx.net->nft.commit_mutex);
++      mutex_unlock(&nft_net->commit_mutex);
+       return NOTIFY_DONE;
+ }
+--- a/net/netfilter/nft_dynset.c
++++ b/net/netfilter/nft_dynset.c
+@@ -11,6 +11,9 @@
+ #include <linux/netfilter/nf_tables.h>
+ #include <net/netfilter/nf_tables.h>
+ #include <net/netfilter/nf_tables_core.h>
++#include <net/netns/generic.h>
++
++extern unsigned int nf_tables_net_id;
+ struct nft_dynset {
+       struct nft_set                  *set;
+@@ -106,13 +109,14 @@ static int nft_dynset_init(const struct
+                          const struct nft_expr *expr,
+                          const struct nlattr * const tb[])
+ {
++      struct nftables_pernet *nft_net = net_generic(ctx->net, nf_tables_net_id);
+       struct nft_dynset *priv = nft_expr_priv(expr);
+       u8 genmask = nft_genmask_next(ctx->net);
+       struct nft_set *set;
+       u64 timeout;
+       int err;
+-      lockdep_assert_held(&ctx->net->nft.commit_mutex);
++      lockdep_assert_held(&nft_net->commit_mutex);
+       if (tb[NFTA_DYNSET_SET_NAME] == NULL ||
+           tb[NFTA_DYNSET_OP] == NULL ||
diff --git a/queue-5.10/netfilter-nftables-rename-set-element-data-activation-deactivation-functions.patch b/queue-5.10/netfilter-nftables-rename-set-element-data-activation-deactivation-functions.patch
new file mode 100644 (file)
index 0000000..8c9da8e
--- /dev/null
@@ -0,0 +1,92 @@
+From stable-owner@vger.kernel.org Thu Jul 13 10:49:53 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Thu, 13 Jul 2023 10:48:56 +0200
+Subject: netfilter: nftables: rename set element data activation/deactivation functions
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, stable@vger.kernel.org, sashal@kernel.org
+Message-ID: <20230713084859.71541-9-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ Upstream commit f8bb7889af58d8e74d2d61c76b1418230f1610fa ]
+
+Rename:
+
+- nft_set_elem_activate() to nft_set_elem_data_activate().
+- nft_set_elem_deactivate() to nft_set_elem_data_deactivate().
+
+To prepare for updates in the set element infrastructure to add support
+for the special catch-all element.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_tables_api.c |   22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -5270,8 +5270,8 @@ void nft_set_elem_destroy(const struct n
+ }
+ EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
+-/* Only called from commit path, nft_set_elem_deactivate() already deals with
+- * the refcounting from the preparation phase.
++/* Only called from commit path, nft_setelem_data_deactivate() already deals
++ * with the refcounting from the preparation phase.
+  */
+ static void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
+                                      const struct nft_set *set, void *elem)
+@@ -5649,9 +5649,9 @@ void nft_data_hold(const struct nft_data
+       }
+ }
+-static void nft_set_elem_activate(const struct net *net,
+-                                const struct nft_set *set,
+-                                struct nft_set_elem *elem)
++static void nft_setelem_data_activate(const struct net *net,
++                                    const struct nft_set *set,
++                                    struct nft_set_elem *elem)
+ {
+       const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
+@@ -5661,9 +5661,9 @@ static void nft_set_elem_activate(const
+               (*nft_set_ext_obj(ext))->use++;
+ }
+-static void nft_set_elem_deactivate(const struct net *net,
+-                                  const struct nft_set *set,
+-                                  struct nft_set_elem *elem)
++static void nft_setelem_data_deactivate(const struct net *net,
++                                      const struct nft_set *set,
++                                      struct nft_set_elem *elem)
+ {
+       const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
+@@ -5740,7 +5740,7 @@ static int nft_del_setelem(struct nft_ct
+       kfree(elem.priv);
+       elem.priv = priv;
+-      nft_set_elem_deactivate(ctx->net, set, &elem);
++      nft_setelem_data_deactivate(ctx->net, set, &elem);
+       nft_trans_elem(trans) = elem;
+       nft_trans_commit_list_add_tail(ctx->net, trans);
+@@ -5774,7 +5774,7 @@ static int nft_flush_set(const struct nf
+       }
+       set->ndeact++;
+-      nft_set_elem_deactivate(ctx->net, set, elem);
++      nft_setelem_data_deactivate(ctx->net, set, elem);
+       nft_trans_elem_set(trans) = set;
+       nft_trans_elem(trans) = *elem;
+       nft_trans_commit_list_add_tail(ctx->net, trans);
+@@ -8413,7 +8413,7 @@ static int __nf_tables_abort(struct net
+               case NFT_MSG_DELSETELEM:
+                       te = (struct nft_trans_elem *)trans->data;
+-                      nft_set_elem_activate(net, te->set, &te->elem);
++                      nft_setelem_data_activate(net, te->set, &te->elem);
+                       te->set->ops->activate(net, te->set, &te->elem);
+                       te->set->ndeact--;
index 3aedddf3611c3872fc8b0913620e834ec898de73..bd6df43263aeec2e232edcd5031a81088bd8ef7e 100644 (file)
@@ -313,3 +313,14 @@ block-add-overflow-checks-for-amiga-partition-support.patch
 mips-dts-ci20-raise-vddcore-voltage-to-1.125-volts.patch
 io_uring-use-io_schedule-in-cqring-wait.patch
 sh-pgtable-3level-fix-cast-to-pointer-from-integer-of-different-size.patch
+netfilter-nf_tables-use-net_generic-infra-for-transaction-data.patch
+netfilter-nf_tables-add-rescheduling-points-during-loop-detection-walks.patch
+netfilter-nf_tables-incorrect-error-path-handling-with-nft_msg_newrule.patch
+netfilter-nf_tables-fix-chain-binding-transaction-logic.patch
+netfilter-nf_tables-add-nft_trans_prepare_error-to-deal-with-bound-set-chain.patch
+netfilter-nf_tables-reject-unbound-anonymous-set-before-commit-phase.patch
+netfilter-nf_tables-reject-unbound-chain-set-before-commit-phase.patch
+netfilter-nftables-rename-set-element-data-activation-deactivation-functions.patch
+netfilter-nf_tables-drop-map-element-references-from-preparation-phase.patch
+netfilter-nf_tables-unbind-non-anonymous-set-if-rule-construction-fails.patch
+netfilter-nf_tables-fix-scheduling-while-atomic-splat.patch