]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 16 Jul 2023 19:24:40 +0000 (21:24 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 16 Jul 2023 19:24:40 +0000 (21:24 +0200)
added patches:
netfilter-add-helper-function-to-set-up-the-nfnetlink-header-and-use-it.patch
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-fix-nat-hook-table-deletion.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-unbind-non-anonymous-set-if-rule-construction-fails.patch
netfilter-nf_tables-use-net_generic-infra-for-transaction-data.patch
netfilter-nftables-add-helper-function-to-set-the-base-sequence-number.patch

queue-4.19/netfilter-add-helper-function-to-set-up-the-nfnetlink-header-and-use-it.patch [new file with mode: 0644]
queue-4.19/netfilter-nf_tables-add-nft_trans_prepare_error-to-deal-with-bound-set-chain.patch [new file with mode: 0644]
queue-4.19/netfilter-nf_tables-add-rescheduling-points-during-loop-detection-walks.patch [new file with mode: 0644]
queue-4.19/netfilter-nf_tables-fix-nat-hook-table-deletion.patch [new file with mode: 0644]
queue-4.19/netfilter-nf_tables-fix-scheduling-while-atomic-splat.patch [new file with mode: 0644]
queue-4.19/netfilter-nf_tables-incorrect-error-path-handling-with-nft_msg_newrule.patch [new file with mode: 0644]
queue-4.19/netfilter-nf_tables-reject-unbound-anonymous-set-before-commit-phase.patch [new file with mode: 0644]
queue-4.19/netfilter-nf_tables-unbind-non-anonymous-set-if-rule-construction-fails.patch [new file with mode: 0644]
queue-4.19/netfilter-nf_tables-use-net_generic-infra-for-transaction-data.patch [new file with mode: 0644]
queue-4.19/netfilter-nftables-add-helper-function-to-set-the-base-sequence-number.patch [new file with mode: 0644]
queue-4.19/series

diff --git a/queue-4.19/netfilter-add-helper-function-to-set-up-the-nfnetlink-header-and-use-it.patch b/queue-4.19/netfilter-add-helper-function-to-set-up-the-nfnetlink-header-and-use-it.patch
new file mode 100644 (file)
index 0000000..df60b16
--- /dev/null
@@ -0,0 +1,704 @@
+From pablo@netfilter.org Wed Jul  5 18:55:24 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Wed,  5 Jul 2023 18:55:10 +0200
+Subject: netfilter: add helper function to set up the nfnetlink header and use it
+To: netfilter-devel@vger.kernel.org
+Cc: sashal@kernel.org, gregkh@linuxfoundation.org, stable@vger.kernel.org
+Message-ID: <20230705165516.50145-5-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 19c28b1374fb1073a9ec873a6c10bf5f16b10b9d ]
+
+This patch adds a helper function to set up the netlink and nfnetlink headers.
+Update existing codebase to use it.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/netfilter/nfnetlink.h  |   27 +++++++++
+ net/netfilter/ipset/ip_set_core.c    |   17 +----
+ net/netfilter/nf_conntrack_netlink.c |   77 +++++++-------------------
+ net/netfilter/nf_tables_api.c        |  102 +++++++++--------------------------
+ net/netfilter/nf_tables_trace.c      |    9 ---
+ net/netfilter/nfnetlink_acct.c       |   11 +--
+ net/netfilter/nfnetlink_cthelper.c   |   11 +--
+ net/netfilter/nfnetlink_cttimeout.c  |   22 ++-----
+ net/netfilter/nfnetlink_log.c        |   11 +--
+ net/netfilter/nfnetlink_queue.c      |   12 +---
+ net/netfilter/nft_compat.c           |   11 +--
+ 11 files changed, 102 insertions(+), 208 deletions(-)
+
+--- a/include/linux/netfilter/nfnetlink.h
++++ b/include/linux/netfilter/nfnetlink.h
+@@ -49,6 +49,33 @@ static inline u16 nfnl_msg_type(u8 subsy
+       return subsys << 8 | msg_type;
+ }
++static inline void nfnl_fill_hdr(struct nlmsghdr *nlh, u8 family, u8 version,
++                               __be16 res_id)
++{
++      struct nfgenmsg *nfmsg;
++
++      nfmsg = nlmsg_data(nlh);
++      nfmsg->nfgen_family = family;
++      nfmsg->version = version;
++      nfmsg->res_id = res_id;
++}
++
++static inline struct nlmsghdr *nfnl_msg_put(struct sk_buff *skb, u32 portid,
++                                          u32 seq, int type, int flags,
++                                          u8 family, u8 version,
++                                          __be16 res_id)
++{
++      struct nlmsghdr *nlh;
++
++      nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg), flags);
++      if (!nlh)
++              return NULL;
++
++      nfnl_fill_hdr(nlh, family, version, res_id);
++
++      return nlh;
++}
++
+ void nfnl_lock(__u8 subsys_id);
+ void nfnl_unlock(__u8 subsys_id);
+ #ifdef CONFIG_PROVE_LOCKING
+--- a/net/netfilter/ipset/ip_set_core.c
++++ b/net/netfilter/ipset/ip_set_core.c
+@@ -791,20 +791,9 @@ static struct nlmsghdr *
+ start_msg(struct sk_buff *skb, u32 portid, u32 seq, unsigned int flags,
+         enum ipset_cmd cmd)
+ {
+-      struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+-
+-      nlh = nlmsg_put(skb, portid, seq, nfnl_msg_type(NFNL_SUBSYS_IPSET, cmd),
+-                      sizeof(*nfmsg), flags);
+-      if (!nlh)
+-              return NULL;
+-
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = NFPROTO_IPV4;
+-      nfmsg->version = NFNETLINK_V0;
+-      nfmsg->res_id = 0;
+-
+-      return nlh;
++      return nfnl_msg_put(skb, portid, seq,
++                          nfnl_msg_type(NFNL_SUBSYS_IPSET, cmd), flags,
++                          NFPROTO_IPV4, NFNETLINK_V0, 0);
+ }
+ /* Create a set */
+--- a/net/netfilter/nf_conntrack_netlink.c
++++ b/net/netfilter/nf_conntrack_netlink.c
+@@ -517,20 +517,15 @@ ctnetlink_fill_info(struct sk_buff *skb,
+ {
+       const struct nf_conntrack_zone *zone;
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       struct nlattr *nest_parms;
+       unsigned int flags = portid ? NLM_F_MULTI : 0, event;
+       event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_NEW);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, nf_ct_l3num(ct),
++                         NFNETLINK_V0, 0);
++      if (!nlh)
+               goto nlmsg_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = nf_ct_l3num(ct);
+-      nfmsg->version      = NFNETLINK_V0;
+-      nfmsg->res_id       = 0;
+-
+       zone = nf_ct_zone(ct);
+       nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED);
+@@ -687,7 +682,6 @@ ctnetlink_conntrack_event(unsigned int e
+       const struct nf_conntrack_zone *zone;
+       struct net *net;
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       struct nlattr *nest_parms;
+       struct nf_conn *ct = item->ct;
+       struct sk_buff *skb;
+@@ -717,15 +711,11 @@ ctnetlink_conntrack_event(unsigned int e
+               goto errout;
+       type = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK, type);
+-      nlh = nlmsg_put(skb, item->portid, 0, type, sizeof(*nfmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, item->portid, 0, type, flags, nf_ct_l3num(ct),
++                         NFNETLINK_V0, 0);
++      if (!nlh)
+               goto nlmsg_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = nf_ct_l3num(ct);
+-      nfmsg->version  = NFNETLINK_V0;
+-      nfmsg->res_id   = 0;
+-
+       zone = nf_ct_zone(ct);
+       nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED);
+@@ -2170,20 +2160,15 @@ ctnetlink_ct_stat_cpu_fill_info(struct s
+                               __u16 cpu, const struct ip_conntrack_stat *st)
+ {
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       unsigned int flags = portid ? NLM_F_MULTI : 0, event;
+       event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK,
+                             IPCTNL_MSG_CT_GET_STATS_CPU);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
++                         NFNETLINK_V0, htons(cpu));
++      if (!nlh)
+               goto nlmsg_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = AF_UNSPEC;
+-      nfmsg->version      = NFNETLINK_V0;
+-      nfmsg->res_id       = htons(cpu);
+-
+       if (nla_put_be32(skb, CTA_STATS_FOUND, htonl(st->found)) ||
+           nla_put_be32(skb, CTA_STATS_INVALID, htonl(st->invalid)) ||
+           nla_put_be32(skb, CTA_STATS_IGNORE, htonl(st->ignore)) ||
+@@ -2254,20 +2239,15 @@ ctnetlink_stat_ct_fill_info(struct sk_bu
+                           struct net *net)
+ {
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       unsigned int flags = portid ? NLM_F_MULTI : 0, event;
+       unsigned int nr_conntracks = atomic_read(&net->ct.count);
+       event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_STATS);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
++                         NFNETLINK_V0, 0);
++      if (!nlh)
+               goto nlmsg_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = AF_UNSPEC;
+-      nfmsg->version      = NFNETLINK_V0;
+-      nfmsg->res_id       = 0;
+-
+       if (nla_put_be32(skb, CTA_STATS_GLOBAL_ENTRIES, htonl(nr_conntracks)))
+               goto nla_put_failure;
+@@ -2780,19 +2760,14 @@ ctnetlink_exp_fill_info(struct sk_buff *
+                       int event, const struct nf_conntrack_expect *exp)
+ {
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       unsigned int flags = portid ? NLM_F_MULTI : 0;
+       event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_EXP, event);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags,
++                         exp->tuple.src.l3num, NFNETLINK_V0, 0);
++      if (!nlh)
+               goto nlmsg_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = exp->tuple.src.l3num;
+-      nfmsg->version      = NFNETLINK_V0;
+-      nfmsg->res_id       = 0;
+-
+       if (ctnetlink_exp_dump_expect(skb, exp) < 0)
+               goto nla_put_failure;
+@@ -2812,7 +2787,6 @@ ctnetlink_expect_event(unsigned int even
+       struct nf_conntrack_expect *exp = item->exp;
+       struct net *net = nf_ct_exp_net(exp);
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       struct sk_buff *skb;
+       unsigned int type, group;
+       int flags = 0;
+@@ -2835,15 +2809,11 @@ ctnetlink_expect_event(unsigned int even
+               goto errout;
+       type = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_EXP, type);
+-      nlh = nlmsg_put(skb, item->portid, 0, type, sizeof(*nfmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, item->portid, 0, type, flags,
++                         exp->tuple.src.l3num, NFNETLINK_V0, 0);
++      if (!nlh)
+               goto nlmsg_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = exp->tuple.src.l3num;
+-      nfmsg->version      = NFNETLINK_V0;
+-      nfmsg->res_id       = 0;
+-
+       if (ctnetlink_exp_dump_expect(skb, exp) < 0)
+               goto nla_put_failure;
+@@ -3413,20 +3383,15 @@ ctnetlink_exp_stat_fill_info(struct sk_b
+                            const struct ip_conntrack_stat *st)
+ {
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       unsigned int flags = portid ? NLM_F_MULTI : 0, event;
+       event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK,
+                             IPCTNL_MSG_EXP_GET_STATS_CPU);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
++                         NFNETLINK_V0, htons(cpu));
++      if (!nlh)
+               goto nlmsg_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = AF_UNSPEC;
+-      nfmsg->version      = NFNETLINK_V0;
+-      nfmsg->res_id       = htons(cpu);
+-
+       if (nla_put_be32(skb, CTA_STATS_EXP_NEW, htonl(st->expect_new)) ||
+           nla_put_be32(skb, CTA_STATS_EXP_CREATE, htonl(st->expect_create)) ||
+           nla_put_be32(skb, CTA_STATS_EXP_DELETE, htonl(st->expect_delete)))
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -578,18 +578,13 @@ static int nf_tables_fill_table_info(str
+                                    int family, const struct nft_table *table)
+ {
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, family,
++                         NFNETLINK_V0, nft_base_seq(net));
++      if (!nlh)
+               goto nla_put_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family     = family;
+-      nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = nft_base_seq(net);
+-
+       if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
+           nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
+           nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)) ||
+@@ -1213,18 +1208,13 @@ static int nf_tables_fill_chain_info(str
+                                    const struct nft_chain *chain)
+ {
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, family,
++                         NFNETLINK_V0, nft_base_seq(net));
++      if (!nlh)
+               goto nla_put_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family     = family;
+-      nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = nft_base_seq(net);
+-
+       if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name))
+               goto nla_put_failure;
+       if (nla_put_be64(skb, NFTA_CHAIN_HANDLE, cpu_to_be64(chain->handle),
+@@ -2257,21 +2247,16 @@ static int nf_tables_fill_rule_info(stru
+                                   const struct nft_rule *rule)
+ {
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       const struct nft_expr *expr, *next;
+       struct nlattr *list;
+       const struct nft_rule *prule;
+       u16 type = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
+-      nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, type, flags, family, NFNETLINK_V0,
++                         nft_base_seq(net));
++      if (!nlh)
+               goto nla_put_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family     = family;
+-      nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = nft_base_seq(net);
+-
+       if (nla_put_string(skb, NFTA_RULE_TABLE, table->name))
+               goto nla_put_failure;
+       if (nla_put_string(skb, NFTA_RULE_CHAIN, chain->name))
+@@ -3166,23 +3151,17 @@ static __be64 nf_jiffies64_to_msecs(u64
+ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
+                             const struct nft_set *set, u16 event, u16 flags)
+ {
+-      struct nfgenmsg *nfmsg;
+       struct nlmsghdr *nlh;
+       struct nlattr *desc;
+       u32 portid = ctx->portid;
+       u32 seq = ctx->seq;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
+-                      flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, ctx->family,
++                         NFNETLINK_V0, nft_base_seq(ctx->net));
++      if (!nlh)
+               goto nla_put_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family     = ctx->family;
+-      nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = nft_base_seq(ctx->net);
+-
+       if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
+               goto nla_put_failure;
+       if (nla_put_string(skb, NFTA_SET_NAME, set->name))
+@@ -3996,7 +3975,6 @@ static int nf_tables_dump_set(struct sk_
+       struct nft_set *set;
+       struct nft_set_dump_args args;
+       bool set_found = false;
+-      struct nfgenmsg *nfmsg;
+       struct nlmsghdr *nlh;
+       struct nlattr *nest;
+       u32 portid, seq;
+@@ -4029,16 +4007,11 @@ static int nf_tables_dump_set(struct sk_
+       portid = NETLINK_CB(cb->skb).portid;
+       seq    = cb->nlh->nlmsg_seq;
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
+-                      NLM_F_MULTI);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, NLM_F_MULTI,
++                         table->family, NFNETLINK_V0, nft_base_seq(net));
++      if (!nlh)
+               goto nla_put_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = table->family;
+-      nfmsg->version      = NFNETLINK_V0;
+-      nfmsg->res_id       = nft_base_seq(net);
+-
+       if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, table->name))
+               goto nla_put_failure;
+       if (nla_put_string(skb, NFTA_SET_ELEM_LIST_SET, set->name))
+@@ -4095,22 +4068,16 @@ static int nf_tables_fill_setelem_info(s
+                                      const struct nft_set *set,
+                                      const struct nft_set_elem *elem)
+ {
+-      struct nfgenmsg *nfmsg;
+       struct nlmsghdr *nlh;
+       struct nlattr *nest;
+       int err;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
+-                      flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, ctx->family,
++                         NFNETLINK_V0, nft_base_seq(ctx->net));
++      if (!nlh)
+               goto nla_put_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family     = ctx->family;
+-      nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = nft_base_seq(ctx->net);
+-
+       if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
+               goto nla_put_failure;
+       if (nla_put_string(skb, NFTA_SET_NAME, set->name))
+@@ -5146,19 +5113,14 @@ static int nf_tables_fill_obj_info(struc
+                                  int family, const struct nft_table *table,
+                                  struct nft_object *obj, bool reset)
+ {
+-      struct nfgenmsg *nfmsg;
+       struct nlmsghdr *nlh;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, family,
++                         NFNETLINK_V0, nft_base_seq(net));
++      if (!nlh)
+               goto nla_put_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family     = family;
+-      nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = nft_base_seq(net);
+-
+       if (nla_put_string(skb, NFTA_OBJ_TABLE, table->name) ||
+           nla_put_string(skb, NFTA_OBJ_NAME, obj->name) ||
+           nla_put_be32(skb, NFTA_OBJ_TYPE, htonl(obj->ops->type->type)) ||
+@@ -5806,20 +5768,15 @@ static int nf_tables_fill_flowtable_info
+                                        struct nft_flowtable *flowtable)
+ {
+       struct nlattr *nest, *nest_devs;
+-      struct nfgenmsg *nfmsg;
+       struct nlmsghdr *nlh;
+       int i;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, family,
++                         NFNETLINK_V0, nft_base_seq(net));
++      if (!nlh)
+               goto nla_put_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family     = family;
+-      nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = nft_base_seq(net);
+-
+       if (nla_put_string(skb, NFTA_FLOWTABLE_TABLE, flowtable->table->name) ||
+           nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) ||
+           nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)) ||
+@@ -6045,19 +6002,14 @@ static int nf_tables_fill_gen_info(struc
+                                  u32 portid, u32 seq)
+ {
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       char buf[TASK_COMM_LEN];
+       int event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWGEN);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), 0);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, 0, AF_UNSPEC,
++                         NFNETLINK_V0, nft_base_seq(net));
++      if (!nlh)
+               goto nla_put_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family     = AF_UNSPEC;
+-      nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = nft_base_seq(net);
+-
+       if (nla_put_be32(skb, NFTA_GEN_ID, htonl(net->nft.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)))
+--- a/net/netfilter/nf_tables_trace.c
++++ b/net/netfilter/nf_tables_trace.c
+@@ -186,7 +186,6 @@ static bool nft_trace_have_verdict_chain
+ void nft_trace_notify(struct nft_traceinfo *info)
+ {
+       const struct nft_pktinfo *pkt = info->pkt;
+-      struct nfgenmsg *nfmsg;
+       struct nlmsghdr *nlh;
+       struct sk_buff *skb;
+       unsigned int size;
+@@ -222,15 +221,11 @@ void nft_trace_notify(struct nft_tracein
+               return;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_TRACE);
+-      nlh = nlmsg_put(skb, 0, 0, event, sizeof(struct nfgenmsg), 0);
++      nlh = nfnl_msg_put(skb, 0, 0, event, 0, info->basechain->type->family,
++                         NFNETLINK_V0, 0);
+       if (!nlh)
+               goto nla_put_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family     = info->basechain->type->family;
+-      nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = 0;
+-
+       if (nla_put_be32(skb, NFTA_TRACE_NFPROTO, htonl(nft_pf(pkt))))
+               goto nla_put_failure;
+--- a/net/netfilter/nfnetlink_acct.c
++++ b/net/netfilter/nfnetlink_acct.c
+@@ -135,21 +135,16 @@ nfnl_acct_fill_info(struct sk_buff *skb,
+                  int event, struct nf_acct *acct)
+ {
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       unsigned int flags = portid ? NLM_F_MULTI : 0;
+       u64 pkts, bytes;
+       u32 old_flags;
+       event = nfnl_msg_type(NFNL_SUBSYS_ACCT, event);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
++                         NFNETLINK_V0, 0);
++      if (!nlh)
+               goto nlmsg_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = AF_UNSPEC;
+-      nfmsg->version = NFNETLINK_V0;
+-      nfmsg->res_id = 0;
+-
+       if (nla_put_string(skb, NFACCT_NAME, acct->name))
+               goto nla_put_failure;
+--- a/net/netfilter/nfnetlink_cthelper.c
++++ b/net/netfilter/nfnetlink_cthelper.c
+@@ -532,20 +532,15 @@ nfnl_cthelper_fill_info(struct sk_buff *
+                       int event, struct nf_conntrack_helper *helper)
+ {
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       unsigned int flags = portid ? NLM_F_MULTI : 0;
+       int status;
+       event = nfnl_msg_type(NFNL_SUBSYS_CTHELPER, event);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
++                         NFNETLINK_V0, 0);
++      if (!nlh)
+               goto nlmsg_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = AF_UNSPEC;
+-      nfmsg->version = NFNETLINK_V0;
+-      nfmsg->res_id = 0;
+-
+       if (nla_put_string(skb, NFCTH_NAME, helper->name))
+               goto nla_put_failure;
+--- a/net/netfilter/nfnetlink_cttimeout.c
++++ b/net/netfilter/nfnetlink_cttimeout.c
+@@ -164,20 +164,15 @@ ctnl_timeout_fill_info(struct sk_buff *s
+                      int event, struct ctnl_timeout *timeout)
+ {
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       unsigned int flags = portid ? NLM_F_MULTI : 0;
+       const struct nf_conntrack_l4proto *l4proto = timeout->timeout.l4proto;
+       event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
++                         NFNETLINK_V0, 0);
++      if (!nlh)
+               goto nlmsg_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = AF_UNSPEC;
+-      nfmsg->version = NFNETLINK_V0;
+-      nfmsg->res_id = 0;
+-
+       if (nla_put_string(skb, CTA_TIMEOUT_NAME, timeout->name) ||
+           nla_put_be16(skb, CTA_TIMEOUT_L3PROTO,
+                        htons(timeout->timeout.l3num)) ||
+@@ -396,19 +391,14 @@ cttimeout_default_fill_info(struct net *
+                           const unsigned int *timeouts)
+ {
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       unsigned int flags = portid ? NLM_F_MULTI : 0;
+       event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
++                         NFNETLINK_V0, 0);
++      if (!nlh)
+               goto nlmsg_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = AF_UNSPEC;
+-      nfmsg->version = NFNETLINK_V0;
+-      nfmsg->res_id = 0;
+-
+       if (nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(l4proto->l3proto)) ||
+           nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto))
+               goto nla_put_failure;
+--- a/net/netfilter/nfnetlink_log.c
++++ b/net/netfilter/nfnetlink_log.c
+@@ -404,20 +404,15 @@ __build_packet_message(struct nfnl_log_n
+ {
+       struct nfulnl_msg_packet_hdr pmsg;
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       sk_buff_data_t old_tail = inst->skb->tail;
+       struct sock *sk;
+       const unsigned char *hwhdrp;
+-      nlh = nlmsg_put(inst->skb, 0, 0,
+-                      nfnl_msg_type(NFNL_SUBSYS_ULOG, NFULNL_MSG_PACKET),
+-                      sizeof(struct nfgenmsg), 0);
++      nlh = nfnl_msg_put(inst->skb, 0, 0,
++                         nfnl_msg_type(NFNL_SUBSYS_ULOG, NFULNL_MSG_PACKET),
++                         0, pf, NFNETLINK_V0, htons(inst->group_num));
+       if (!nlh)
+               return -1;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = pf;
+-      nfmsg->version = NFNETLINK_V0;
+-      nfmsg->res_id = htons(inst->group_num);
+       memset(&pmsg, 0, sizeof(pmsg));
+       pmsg.hw_protocol        = skb->protocol;
+--- a/net/netfilter/nfnetlink_queue.c
++++ b/net/netfilter/nfnetlink_queue.c
+@@ -387,7 +387,6 @@ nfqnl_build_packet_message(struct net *n
+       struct nlattr *nla;
+       struct nfqnl_msg_packet_hdr *pmsg;
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       struct sk_buff *entskb = entry->skb;
+       struct net_device *indev;
+       struct net_device *outdev;
+@@ -473,18 +472,15 @@ nfqnl_build_packet_message(struct net *n
+               goto nlmsg_failure;
+       }
+-      nlh = nlmsg_put(skb, 0, 0,
+-                      nfnl_msg_type(NFNL_SUBSYS_QUEUE, NFQNL_MSG_PACKET),
+-                      sizeof(struct nfgenmsg), 0);
++      nlh = nfnl_msg_put(skb, 0, 0,
++                         nfnl_msg_type(NFNL_SUBSYS_QUEUE, NFQNL_MSG_PACKET),
++                         0, entry->state.pf, NFNETLINK_V0,
++                         htons(queue->queue_num));
+       if (!nlh) {
+               skb_tx_error(entskb);
+               kfree_skb(skb);
+               goto nlmsg_failure;
+       }
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = entry->state.pf;
+-      nfmsg->version = NFNETLINK_V0;
+-      nfmsg->res_id = htons(queue->queue_num);
+       nla = __nla_reserve(skb, NFQA_PACKET_HDR, sizeof(*pmsg));
+       pmsg = nla_data(nla);
+--- a/net/netfilter/nft_compat.c
++++ b/net/netfilter/nft_compat.c
+@@ -575,19 +575,14 @@ nfnl_compat_fill_info(struct sk_buff *sk
+                     int rev, int target)
+ {
+       struct nlmsghdr *nlh;
+-      struct nfgenmsg *nfmsg;
+       unsigned int flags = portid ? NLM_F_MULTI : 0;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFT_COMPAT, event);
+-      nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
+-      if (nlh == NULL)
++      nlh = nfnl_msg_put(skb, portid, seq, event, flags, family,
++                         NFNETLINK_V0, 0);
++      if (!nlh)
+               goto nlmsg_failure;
+-      nfmsg = nlmsg_data(nlh);
+-      nfmsg->nfgen_family = family;
+-      nfmsg->version = NFNETLINK_V0;
+-      nfmsg->res_id = 0;
+-
+       if (nla_put_string(skb, NFTA_COMPAT_NAME, name) ||
+           nla_put_be32(skb, NFTA_COMPAT_REV, htonl(rev)) ||
+           nla_put_be32(skb, NFTA_COMPAT_TYPE, htonl(target)))
diff --git a/queue-4.19/netfilter-nf_tables-add-nft_trans_prepare_error-to-deal-with-bound-set-chain.patch b/queue-4.19/netfilter-nf_tables-add-nft_trans_prepare_error-to-deal-with-bound-set-chain.patch
new file mode 100644 (file)
index 0000000..cdbeda5
--- /dev/null
@@ -0,0 +1,101 @@
+From stable-owner@vger.kernel.org Wed Jul  5 18:55:57 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Wed,  5 Jul 2023 18:55:13 +0200
+Subject: netfilter: nf_tables: add NFT_TRANS_PREPARE_ERROR to deal with bound set/chain
+To: netfilter-devel@vger.kernel.org
+Cc: sashal@kernel.org, gregkh@linuxfoundation.org, stable@vger.kernel.org
+Message-ID: <20230705165516.50145-8-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 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 |    1 +
+ net/netfilter/nf_tables_api.c     |   26 ++++++++++++++++++++++----
+ 2 files changed, 23 insertions(+), 4 deletions(-)
+
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -736,6 +736,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
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -120,7 +120,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;
+@@ -134,16 +135,26 @@ 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_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_trans_commit_list_add_tail(struct net *net, struct nft_trans *trans)
+ {
+       struct nftables_pernet *nft_net;
+@@ -2784,7 +2795,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++) {
+@@ -3809,6 +3820,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);
diff --git a/queue-4.19/netfilter-nf_tables-add-rescheduling-points-during-loop-detection-walks.patch b/queue-4.19/netfilter-nf_tables-add-rescheduling-points-during-loop-detection-walks.patch
new file mode 100644 (file)
index 0000000..9c21fe8
--- /dev/null
@@ -0,0 +1,50 @@
+From pablo@netfilter.org Wed Jul  5 18:55:22 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Wed,  5 Jul 2023 18:55:08 +0200
+Subject: netfilter: nf_tables: add rescheduling points during loop detection walks
+To: netfilter-devel@vger.kernel.org
+Cc: sashal@kernel.org, gregkh@linuxfoundation.org, stable@vger.kernel.org
+Message-ID: <20230705165516.50145-3-pablo@netfilter.org>
+
+From: Florian Westphal <fw@strlen.de>
+
+[ 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
+@@ -2552,6 +2552,8 @@ int nft_chain_validate(const struct nft_
+                       if (err < 0)
+                               return err;
+               }
++
++              cond_resched();
+       }
+       return 0;
+@@ -6956,9 +6958,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-4.19/netfilter-nf_tables-fix-nat-hook-table-deletion.patch b/queue-4.19/netfilter-nf_tables-fix-nat-hook-table-deletion.patch
new file mode 100644 (file)
index 0000000..a88acd3
--- /dev/null
@@ -0,0 +1,104 @@
+From pablo@netfilter.org Wed Jul  5 18:55:22 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Wed,  5 Jul 2023 18:55:07 +0200
+Subject: netfilter: nf_tables: fix nat hook table deletion
+To: netfilter-devel@vger.kernel.org
+Cc: sashal@kernel.org, gregkh@linuxfoundation.org, stable@vger.kernel.org
+Message-ID: <20230705165516.50145-2-pablo@netfilter.org>
+
+From: Florian Westphal <fw@strlen.de>
+
+[ 1e9451cbda456a170518b2bfd643e2cb980880bf ]
+
+sybot came up with following transaction:
+ add table ip syz0
+ add chain ip syz0 syz2 { type nat hook prerouting priority 0; policy accept; }
+ add table ip syz0 { flags dormant; }
+ delete chain ip syz0 syz2
+ delete table ip syz0
+
+which yields:
+hook not found, pf 2 num 0
+WARNING: CPU: 0 PID: 6775 at net/netfilter/core.c:413 __nf_unregister_net_hook+0x3e6/0x4a0 net/netfilter/core.c:413
+[..]
+ nft_unregister_basechain_hooks net/netfilter/nf_tables_api.c:206 [inline]
+ nft_table_disable net/netfilter/nf_tables_api.c:835 [inline]
+ nf_tables_table_disable net/netfilter/nf_tables_api.c:868 [inline]
+ nf_tables_commit+0x32d3/0x4d70 net/netfilter/nf_tables_api.c:7550
+ nfnetlink_rcv_batch net/netfilter/nfnetlink.c:486 [inline]
+ nfnetlink_rcv_skb_batch net/netfilter/nfnetlink.c:544 [inline]
+ nfnetlink_rcv+0x14a5/0x1e50 net/netfilter/nfnetlink.c:562
+ netlink_unicast_kernel net/netlink/af_netlink.c:1303 [inline]
+
+Problem is that when I added ability to override base hook registration
+to make nat basechains register with the nat core instead of netfilter
+core, I forgot to update nft_table_disable() to use that instead of
+the 'raw' hook register interface.
+
+In syzbot transaction, the basechain is of 'nat' type. Its registered
+with the nat core.  The switch to 'dormant mode' attempts to delete from
+netfilter core instead.
+
+After updating nft_table_disable/enable to use the correct helper,
+nft_(un)register_basechain_hooks can be folded into the only remaining
+caller.
+
+Because nft_trans_table_enable() won't do anything when the DORMANT flag
+is set, remove the flag first, then re-add it in case re-enablement
+fails, else this patch breaks sequence:
+
+add table ip x { flags dormant; }
+/* add base chains */
+add table ip x
+
+The last 'add' will remove the dormant flags, but won't have any other
+effect -- base chains are not registered.
+Then, next 'set dormant flag' will create another 'hook not found'
+splat.
+
+Reported-by: syzbot+2570f2c036e3da5db176@syzkaller.appspotmail.com
+Fixes: 4e25ceb80b58 ("netfilter: nf_tables: allow chain type to override hook register")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+(cherry picked from commit 1e9451cbda456a170518b2bfd643e2cb980880bf)
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_tables_api.c |   11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -743,7 +743,7 @@ static void nft_table_disable(struct net
+               if (cnt && i++ == cnt)
+                       break;
+-              nf_unregister_net_hook(net, &nft_base_chain(chain)->ops);
++              nf_tables_unregister_hook(net, table, chain);
+       }
+ }
+@@ -758,7 +758,7 @@ static int nf_tables_table_enable(struct
+               if (!nft_is_base_chain(chain))
+                       continue;
+-              err = nf_register_net_hook(net, &nft_base_chain(chain)->ops);
++              err = nf_tables_register_hook(net, table, chain);
+               if (err < 0)
+                       goto err;
+@@ -802,11 +802,12 @@ static int nf_tables_updtable(struct nft
+               nft_trans_table_enable(trans) = false;
+       } else if (!(flags & NFT_TABLE_F_DORMANT) &&
+                  ctx->table->flags & NFT_TABLE_F_DORMANT) {
++              ctx->table->flags &= ~NFT_TABLE_F_DORMANT;
+               ret = nf_tables_table_enable(ctx->net, ctx->table);
+-              if (ret >= 0) {
+-                      ctx->table->flags &= ~NFT_TABLE_F_DORMANT;
++              if (ret >= 0)
+                       nft_trans_table_enable(trans) = true;
+-              }
++              else
++                      ctx->table->flags |= NFT_TABLE_F_DORMANT;
+       }
+       if (ret < 0)
+               goto err;
diff --git a/queue-4.19/netfilter-nf_tables-fix-scheduling-while-atomic-splat.patch b/queue-4.19/netfilter-nf_tables-fix-scheduling-while-atomic-splat.patch
new file mode 100644 (file)
index 0000000..c69f0b5
--- /dev/null
@@ -0,0 +1,39 @@
+From stable-owner@vger.kernel.org Wed Jul  5 18:56:03 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Wed,  5 Jul 2023 18:55:16 +0200
+Subject: netfilter: nf_tables: fix scheduling-while-atomic splat
+To: netfilter-devel@vger.kernel.org
+Cc: sashal@kernel.org, gregkh@linuxfoundation.org, stable@vger.kernel.org
+Message-ID: <20230705165516.50145-11-pablo@netfilter.org>
+
+From: Florian Westphal <fw@strlen.de>
+
+[ 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
+@@ -7021,13 +7021,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-4.19/netfilter-nf_tables-incorrect-error-path-handling-with-nft_msg_newrule.patch b/queue-4.19/netfilter-nf_tables-incorrect-error-path-handling-with-nft_msg_newrule.patch
new file mode 100644 (file)
index 0000000..4e43421
--- /dev/null
@@ -0,0 +1,73 @@
+From stable-owner@vger.kernel.org Wed Jul  5 18:55:56 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Wed,  5 Jul 2023 18:55:12 +0200
+Subject: netfilter: nf_tables: incorrect error path handling with NFT_MSG_NEWRULE
+To: netfilter-devel@vger.kernel.org
+Cc: sashal@kernel.org, gregkh@linuxfoundation.org, stable@vger.kernel.org
+Message-ID: <20230705165516.50145-7-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 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
+@@ -2784,7 +2784,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-4.19/netfilter-nf_tables-reject-unbound-anonymous-set-before-commit-phase.patch b/queue-4.19/netfilter-nf_tables-reject-unbound-anonymous-set-before-commit-phase.patch
new file mode 100644 (file)
index 0000000..19d00b1
--- /dev/null
@@ -0,0 +1,137 @@
+From stable-owner@vger.kernel.org Wed Jul  5 18:55:57 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Wed,  5 Jul 2023 18:55:14 +0200
+Subject: netfilter: nf_tables: reject unbound anonymous set before commit phase
+To: netfilter-devel@vger.kernel.org
+Cc: sashal@kernel.org, gregkh@linuxfoundation.org, stable@vger.kernel.org
+Message-ID: <20230705165516.50145-9-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 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     |   33 ++++++++++++++++++++++++++++++---
+ 2 files changed, 33 insertions(+), 3 deletions(-)
+
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -1320,12 +1320,14 @@ 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
+  *    @ctx: transaction context
+  *    @data: internal information related to the transaction
+  */
+ struct nft_trans {
+       struct list_head                list;
++      struct list_head                binding_list;
+       int                             msg_type;
+       struct nft_ctx                  ctx;
+       char                            data[0];
+@@ -1413,6 +1415,7 @@ void nft_chain_filter_fini(void);
+ 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
+@@ -102,6 +102,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;
+@@ -114,9 +115,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);
+ }
+@@ -160,6 +167,13 @@ 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);
+ }
+@@ -6403,7 +6417,7 @@ static void nf_tables_commit_release(str
+       synchronize_rcu();
+       list_for_each_entry_safe(trans, next, &nft_net->commit_list, list) {
+-              list_del(&trans->list);
++              nft_trans_list_del(trans);
+               nft_commit_release(trans);
+       }
+ }
+@@ -6542,6 +6556,18 @@ static int nf_tables_commit(struct net *
+       struct nft_chain *chain;
+       struct nft_table *table;
++      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;
+@@ -6847,7 +6873,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);
+       }
+@@ -7497,6 +7523,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);
+       mutex_init(&nft_net->commit_mutex);
+       nft_net->base_seq = 1;
+       nft_net->validate_state = NFT_VALIDATE_SKIP;
diff --git a/queue-4.19/netfilter-nf_tables-unbind-non-anonymous-set-if-rule-construction-fails.patch b/queue-4.19/netfilter-nf_tables-unbind-non-anonymous-set-if-rule-construction-fails.patch
new file mode 100644 (file)
index 0000000..874be69
--- /dev/null
@@ -0,0 +1,33 @@
+From stable-owner@vger.kernel.org Wed Jul  5 18:56:29 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Wed,  5 Jul 2023 18:55:15 +0200
+Subject: netfilter: nf_tables: unbind non-anonymous set if rule construction fails
+To: netfilter-devel@vger.kernel.org
+Cc: sashal@kernel.org, gregkh@linuxfoundation.org, stable@vger.kernel.org
+Message-ID: <20230705165516.50145-10-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 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
+@@ -3838,6 +3838,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-4.19/netfilter-nf_tables-use-net_generic-infra-for-transaction-data.patch b/queue-4.19/netfilter-nf_tables-use-net_generic-infra-for-transaction-data.patch
new file mode 100644 (file)
index 0000000..2938e7b
--- /dev/null
@@ -0,0 +1,1032 @@
+From stable-owner@vger.kernel.org Wed Jul  5 18:56:03 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Wed,  5 Jul 2023 18:55:11 +0200
+Subject: netfilter: nf_tables: use net_generic infra for transaction data
+To: netfilter-devel@vger.kernel.org
+Cc: sashal@kernel.org, gregkh@linuxfoundation.org, stable@vger.kernel.org
+Message-ID: <20230705165516.50145-6-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 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      |    5 
+ net/netfilter/nf_tables_api.c     |  303 +++++++++++++++++++++++---------------
+ net/netfilter/nft_chain_filter.c  |   11 +
+ net/netfilter/nft_dynset.c        |    6 
+ 5 files changed, 210 insertions(+), 125 deletions(-)
+
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -1409,4 +1409,14 @@ struct nft_trans_flowtable {
+ int __init nft_chain_filter_init(void);
+ void nft_chain_filter_fini(void);
++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,12 +5,7 @@
+ #include <linux/list.h>
+ struct netns_nftables {
+-      struct list_head        tables;
+-      struct list_head        commit_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
+@@ -22,10 +22,13 @@
+ #include <net/netfilter/nf_tables_core.h>
+ #include <net/netfilter/nf_tables.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);
+@@ -53,7 +56,9 @@ static const struct rhashtable_params nf
+ 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;
+@@ -64,7 +69,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 nft_ctx_init(struct nft_ctx *ctx,
+@@ -117,13 +122,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)
+@@ -137,6 +144,14 @@ static void nft_set_trans_bind(const str
+       }
+ }
++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 nf_tables_register_hook(struct net *net,
+                                  const struct nft_table *table,
+                                  struct nft_chain *chain)
+@@ -187,7 +202,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;
+ }
+@@ -214,7 +229,7 @@ static int nft_trans_chain_add(struct nf
+       if (msg_type == NFT_MSG_NEWCHAIN)
+               nft_activate_next(ctx->net, ctx->chain);
+-      list_add_tail(&trans->list, &ctx->net->nft.commit_list);
++      nft_trans_commit_list_add_tail(ctx->net, trans);
+       return 0;
+ }
+@@ -287,7 +302,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;
+ }
+@@ -342,7 +357,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;
+ }
+@@ -374,7 +389,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;
+ }
+@@ -407,7 +422,7 @@ static int nft_trans_flowtable_add(struc
+               nft_activate_next(ctx->net, flowtable);
+       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;
+ }
+@@ -435,12 +450,14 @@ 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) {
++      nft_net = net_generic(net, nf_tables_net_id);
++      list_for_each_entry_rcu(table, &nft_net->tables, list) {
+               if (!nla_strcmp(nla, table->name) &&
+                   table->family == family &&
+                   nft_active_genmask(table, genmask))
+@@ -454,9 +471,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;
+@@ -509,11 +528,13 @@ __nf_tables_chain_type_lookup(const stru
+ static void nft_request_module(struct net *net, const char *fmt, ...)
+ {
+       char module_name[MODULE_NAME_LEN];
++      struct nftables_pernet *nft_net;
+       LIST_HEAD(commit_list);
+       va_list args;
+       int ret;
+-      list_splice_init(&net->nft.commit_list, &commit_list);
++      nft_net = net_generic(net, nf_tables_net_id);
++      list_splice_init(&nft_net->commit_list, &commit_list);
+       va_start(args, fmt);
+       ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args);
+@@ -521,12 +542,12 @@ static void nft_request_module(struct ne
+       if (ret >= MODULE_NAME_LEN)
+               return;
+-      mutex_unlock(&net->nft.commit_mutex);
++      mutex_unlock(&nft_net->commit_mutex);
+       request_module("%s", module_name);
+-      mutex_lock(&net->nft.commit_mutex);
++      mutex_lock(&nft_net->commit_mutex);
+-      WARN_ON_ONCE(!list_empty(&net->nft.commit_list));
+-      list_splice(&commit_list, &net->nft.commit_list);
++      WARN_ON_ONCE(!list_empty(&nft_net->commit_list));
++      list_splice(&commit_list, &nft_net->commit_list);
+ }
+ #endif
+@@ -563,7 +584,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] = {
+@@ -631,15 +654,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;
+@@ -813,7 +838,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);
+@@ -848,6 +873,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;
+@@ -857,7 +883,7 @@ static int nf_tables_newtable(struct net
+       struct nft_ctx ctx;
+       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)) {
+@@ -907,7 +933,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);
+@@ -987,11 +1013,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;
+@@ -1105,7 +1132,9 @@ nft_chain_lookup_byhandle(const struct n
+ static bool lockdep_commit_lock_is_held(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
+@@ -1302,11 +1331,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;
+@@ -1499,12 +1530,13 @@ 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;
+       struct net_device *dev;
+       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(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK],
+@@ -1773,6 +1805,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;
+@@ -1782,7 +1815,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) &&
+@@ -1795,7 +1828,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:
+@@ -1809,6 +1842,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;
+@@ -1819,7 +1853,7 @@ static int nf_tables_newchain(struct net
+       struct nft_ctx ctx;
+       u64 handle = 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)) {
+@@ -2342,11 +2376,13 @@ static int nf_tables_dump_rules(struct s
+       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;
+@@ -2499,7 +2535,6 @@ static void nf_tables_rule_destroy(const
+ {
+       struct nft_expr *expr, *next;
+-      lockdep_assert_held(&ctx->net->nft.commit_mutex);
+       /*
+        * Careful: some expressions might not be initialized in case this
+        * is called on error from nf_tables_newrule().
+@@ -2579,6 +2614,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;
+@@ -2595,7 +2631,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)) {
+@@ -2743,7 +2779,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);
+       return 0;
+@@ -2765,10 +2801,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 &&
+@@ -2887,12 +2924,13 @@ 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;
+-      lockdep_assert_held(&ctx->net->nft.commit_mutex);
++      lockdep_assert_held(&nft_net->commit_mutex);
+       lockdep_nfnl_nft_mutex_not_held();
+ #ifdef CONFIG_MODULES
+       if (list_empty(&nf_tables_set_types)) {
+@@ -3038,10 +3076,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);
+@@ -3257,14 +3296,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;
+@@ -3971,6 +4012,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;
+@@ -3981,7 +4023,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;
+@@ -4571,7 +4614,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;
+ err6:
+@@ -4596,6 +4639,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;
+@@ -4625,7 +4669,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;
+@@ -4738,7 +4782,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:
+@@ -4772,7 +4816,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:
+@@ -5151,6 +5195,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;
+@@ -5158,9 +5203,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;
+@@ -5826,12 +5872,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;
+@@ -6001,6 +6049,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);
+@@ -6010,7 +6059,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;
+@@ -6043,6 +6092,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;
+@@ -6050,13 +6100,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;
+ }
+@@ -6237,16 +6288,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);
+               /* fall through */
+       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;
+               }
+@@ -6323,14 +6375,15 @@ static void nft_commit_release(struct nf
+ 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, *next;
+-      if (list_empty(&net->nft.commit_list))
++      if (list_empty(&nft_net->commit_list))
+               return;
+       synchronize_rcu();
+-      list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
++      list_for_each_entry_safe(trans, next, &nft_net->commit_list, list) {
+               list_del(&trans->list);
+               nft_commit_release(trans);
+       }
+@@ -6369,9 +6422,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 ||
+@@ -6463,6 +6517,7 @@ static void nft_chain_del(struct nft_cha
+ 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;
+@@ -6473,7 +6528,7 @@ static int nf_tables_commit(struct net *
+               return -EAGAIN;
+       /* 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;
+               if (trans->msg_type == NFT_MSG_NEWRULE ||
+@@ -6489,7 +6544,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);
+       }
+@@ -6498,12 +6553,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) {
+               switch (trans->msg_type) {
+               case NFT_MSG_NEWTABLE:
+                       if (nft_trans_table_update(trans)) {
+@@ -6624,7 +6680,7 @@ static int nf_tables_commit(struct net *
+       nf_tables_commit_release(net);
+       nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
+-      mutex_unlock(&net->nft.commit_mutex);
++      mutex_unlock(&nft_net->commit_mutex);
+       return 0;
+ }
+@@ -6660,10 +6716,11 @@ static void nf_tables_abort_release(stru
+ static int __nf_tables_abort(struct net *net)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       struct nft_trans *trans, *next;
+       struct nft_trans_elem *te;
+-      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:
+@@ -6770,7 +6827,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);
+       }
+@@ -6780,22 +6837,24 @@ static int __nf_tables_abort(struct net
+ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
+ {
++      struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id);
+       int ret = __nf_tables_abort(net);
+-      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;
+@@ -7353,10 +7412,9 @@ int __nft_release_basechain(struct nft_c
+ }
+ EXPORT_SYMBOL_GPL(__nft_release_basechain);
+-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;
+@@ -7366,71 +7424,84 @@ 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.family = table->family;
+-              list_for_each_entry(chain, &table->chains, list)
+-                      nf_tables_unregister_hook(net, table, chain);
+-              /* No packets are walking on these chains anymore. */
+-              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(set);
+-              }
+-              list_for_each_entry_safe(obj, ne, &table->objects, list) {
+-                      list_del(&obj->list);
+-                      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_for_each_entry(chain, &table->chains, list)
++              nf_tables_unregister_hook(net, table, chain);
++      /* No packets are walking on these chains anymore. */
++      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(set);
++      }
++      list_for_each_entry_safe(obj, ne, &table->objects, list) {
++              list_del(&obj->list);
++              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);
+-      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);
++      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_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);
+       __nft_release_tables(net);
+-      mutex_unlock(&net->nft.commit_mutex);
+-      WARN_ON_ONCE(!list_empty(&net->nft.tables));
++      mutex_unlock(&nft_net->commit_mutex);
++      WARN_ON_ONCE(!list_empty(&nft_net->tables));
+ }
+ static struct pernet_operations nf_tables_net_ops = {
+       .init   = nf_tables_init_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/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,
+@@ -315,6 +318,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 = {
+@@ -325,8 +329,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;
+@@ -340,7 +345,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
+@@ -15,6 +15,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;
+@@ -112,13 +115,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-4.19/netfilter-nftables-add-helper-function-to-set-the-base-sequence-number.patch b/queue-4.19/netfilter-nftables-add-helper-function-to-set-the-base-sequence-number.patch
new file mode 100644 (file)
index 0000000..e15f9a4
--- /dev/null
@@ -0,0 +1,117 @@
+From pablo@netfilter.org Wed Jul  5 18:55:23 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Wed,  5 Jul 2023 18:55:09 +0200
+Subject: netfilter: nftables: add helper function to set the base sequence number
+To: netfilter-devel@vger.kernel.org
+Cc: sashal@kernel.org, gregkh@linuxfoundation.org, stable@vger.kernel.org
+Message-ID: <20230705165516.50145-4-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 802b805162a1b7d8391c40ac8a878e9e63287aff ]
+
+This patch adds a helper function to calculate the base sequence number
+field that is stored in the nfnetlink header. Use the helper function
+whenever possible.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_tables_api.c |   23 ++++++++++++++---------
+ 1 file changed, 14 insertions(+), 9 deletions(-)
+
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -561,6 +561,11 @@ nf_tables_chain_type_lookup(struct net *
+       return ERR_PTR(-ENOENT);
+ }
++static __be16 nft_base_seq(const struct net *net)
++{
++      return htons(net->nft.base_seq & 0xffff);
++}
++
+ static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
+       [NFTA_TABLE_NAME]       = { .type = NLA_STRING,
+                                   .len = NFT_TABLE_MAXNAMELEN - 1 },
+@@ -583,7 +588,7 @@ static int nf_tables_fill_table_info(str
+       nfmsg = nlmsg_data(nlh);
+       nfmsg->nfgen_family     = family;
+       nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = htons(net->nft.base_seq & 0xffff);
++      nfmsg->res_id           = nft_base_seq(net);
+       if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
+           nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
+@@ -1218,7 +1223,7 @@ static int nf_tables_fill_chain_info(str
+       nfmsg = nlmsg_data(nlh);
+       nfmsg->nfgen_family     = family;
+       nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = htons(net->nft.base_seq & 0xffff);
++      nfmsg->res_id           = nft_base_seq(net);
+       if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name))
+               goto nla_put_failure;
+@@ -2265,7 +2270,7 @@ static int nf_tables_fill_rule_info(stru
+       nfmsg = nlmsg_data(nlh);
+       nfmsg->nfgen_family     = family;
+       nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = htons(net->nft.base_seq & 0xffff);
++      nfmsg->res_id           = nft_base_seq(net);
+       if (nla_put_string(skb, NFTA_RULE_TABLE, table->name))
+               goto nla_put_failure;
+@@ -3176,7 +3181,7 @@ static int nf_tables_fill_set(struct sk_
+       nfmsg = nlmsg_data(nlh);
+       nfmsg->nfgen_family     = ctx->family;
+       nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = htons(ctx->net->nft.base_seq & 0xffff);
++      nfmsg->res_id           = nft_base_seq(ctx->net);
+       if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
+               goto nla_put_failure;
+@@ -4032,7 +4037,7 @@ static int nf_tables_dump_set(struct sk_
+       nfmsg = nlmsg_data(nlh);
+       nfmsg->nfgen_family = table->family;
+       nfmsg->version      = NFNETLINK_V0;
+-      nfmsg->res_id       = htons(net->nft.base_seq & 0xffff);
++      nfmsg->res_id       = nft_base_seq(net);
+       if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, table->name))
+               goto nla_put_failure;
+@@ -4104,7 +4109,7 @@ static int nf_tables_fill_setelem_info(s
+       nfmsg = nlmsg_data(nlh);
+       nfmsg->nfgen_family     = ctx->family;
+       nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = htons(ctx->net->nft.base_seq & 0xffff);
++      nfmsg->res_id           = nft_base_seq(ctx->net);
+       if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
+               goto nla_put_failure;
+@@ -5152,7 +5157,7 @@ static int nf_tables_fill_obj_info(struc
+       nfmsg = nlmsg_data(nlh);
+       nfmsg->nfgen_family     = family;
+       nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = htons(net->nft.base_seq & 0xffff);
++      nfmsg->res_id           = nft_base_seq(net);
+       if (nla_put_string(skb, NFTA_OBJ_TABLE, table->name) ||
+           nla_put_string(skb, NFTA_OBJ_NAME, obj->name) ||
+@@ -5813,7 +5818,7 @@ static int nf_tables_fill_flowtable_info
+       nfmsg = nlmsg_data(nlh);
+       nfmsg->nfgen_family     = family;
+       nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = htons(net->nft.base_seq & 0xffff);
++      nfmsg->res_id           = nft_base_seq(net);
+       if (nla_put_string(skb, NFTA_FLOWTABLE_TABLE, flowtable->table->name) ||
+           nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) ||
+@@ -6051,7 +6056,7 @@ static int nf_tables_fill_gen_info(struc
+       nfmsg = nlmsg_data(nlh);
+       nfmsg->nfgen_family     = AF_UNSPEC;
+       nfmsg->version          = NFNETLINK_V0;
+-      nfmsg->res_id           = htons(net->nft.base_seq & 0xffff);
++      nfmsg->res_id           = nft_base_seq(net);
+       if (nla_put_be32(skb, NFTA_GEN_ID, htonl(net->nft.base_seq)) ||
+           nla_put_be32(skb, NFTA_GEN_PROC_PID, htonl(task_pid_nr(current))) ||
index a9e164a778b71b15184ca4b6622561007465ae1e..8483c8d1b0cb547465fffcb1eb692c2302eb846c 100644 (file)
@@ -122,3 +122,13 @@ arm-orion5x-fix-d2net-gpio-initialization.patch
 spi-spi-fsl-spi-remove-always-true-conditional-in-fsl_spi_do_one_msg.patch
 spi-spi-fsl-spi-relax-message-sanity-checking-a-little.patch
 spi-spi-fsl-spi-allow-changing-bits_per_word-while-cs-is-still-active.patch
+netfilter-nf_tables-fix-nat-hook-table-deletion.patch
+netfilter-nf_tables-add-rescheduling-points-during-loop-detection-walks.patch
+netfilter-nftables-add-helper-function-to-set-the-base-sequence-number.patch
+netfilter-add-helper-function-to-set-up-the-nfnetlink-header-and-use-it.patch
+netfilter-nf_tables-use-net_generic-infra-for-transaction-data.patch
+netfilter-nf_tables-incorrect-error-path-handling-with-nft_msg_newrule.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-unbind-non-anonymous-set-if-rule-construction-fails.patch
+netfilter-nf_tables-fix-scheduling-while-atomic-splat.patch