]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.4
authorSasha Levin <sashal@kernel.org>
Mon, 22 May 2023 18:28:25 +0000 (14:28 -0400)
committerSasha Levin <sashal@kernel.org>
Mon, 22 May 2023 18:28:25 +0000 (14:28 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-5.4/netfilter-nf_tables-add-nft_setelem_parse_key.patch [new file with mode: 0644]
queue-5.4/netfilter-nf_tables-allow-up-to-64-bytes-in-the-set-.patch [new file with mode: 0644]
queue-5.4/netfilter-nf_tables-hold-mutex-on-netns-pre_exit-pat.patch [new file with mode: 0644]
queue-5.4/netfilter-nf_tables-stricter-validation-of-element-d.patch [new file with mode: 0644]
queue-5.4/netfilter-nf_tables-validate-nfta_set_elem_objref-ba.patch [new file with mode: 0644]
queue-5.4/netfilter-nf_tables-validate-registers-coming-from-u.patch [new file with mode: 0644]
queue-5.4/netfilter-nftables-add-nft_parse_register_load-and-u.patch [new file with mode: 0644]
queue-5.4/netfilter-nftables-add-nft_parse_register_store-and-.patch [new file with mode: 0644]
queue-5.4/netfilter-nftables-statify-nft_parse_register.patch [new file with mode: 0644]
queue-5.4/series

diff --git a/queue-5.4/netfilter-nf_tables-add-nft_setelem_parse_key.patch b/queue-5.4/netfilter-nf_tables-add-nft_setelem_parse_key.patch
new file mode 100644 (file)
index 0000000..02a8ac3
--- /dev/null
@@ -0,0 +1,250 @@
+From 633b23fb13a3abd54d7ceabd455f06db140d67d6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 16:44:31 +0200
+Subject: netfilter: nf_tables: add nft_setelem_parse_key()
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 20a1452c35425b2cef76f21f8395ef069dfddfa9 ]
+
+Add helper function to parse the set element key netlink attribute.
+
+v4: No changes
+v3: New patch
+
+[sbrivio: refactor error paths and labels; use NFT_DATA_VALUE_MAXLEN
+  instead of sizeof(*key) in helper, value can be longer than that;
+  rebase]
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_tables_api.c | 91 +++++++++++++++++------------------
+ 1 file changed, 45 insertions(+), 46 deletions(-)
+
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index a90bf82ea1435..13a8a78b8ee8b 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -4292,11 +4292,28 @@ static int nft_setelem_parse_flags(const struct nft_set *set,
+       return 0;
+ }
++static int nft_setelem_parse_key(struct nft_ctx *ctx, struct nft_set *set,
++                               struct nft_data *key, struct nlattr *attr)
++{
++      struct nft_data_desc desc;
++      int err;
++
++      err = nft_data_init(ctx, key, NFT_DATA_VALUE_MAXLEN, &desc, attr);
++      if (err < 0)
++              return err;
++
++      if (desc.type != NFT_DATA_VALUE || desc.len != set->klen) {
++              nft_data_release(key, desc.type);
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
+ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+                           const struct nlattr *attr)
+ {
+       struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
+-      struct nft_data_desc desc;
+       struct nft_set_elem elem;
+       struct sk_buff *skb;
+       uint32_t flags = 0;
+@@ -4315,17 +4332,11 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+       if (err < 0)
+               return err;
+-      err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &desc,
+-                          nla[NFTA_SET_ELEM_KEY]);
++      err = nft_setelem_parse_key(ctx, set, &elem.key.val,
++                                  nla[NFTA_SET_ELEM_KEY]);
+       if (err < 0)
+               return err;
+-      err = -EINVAL;
+-      if (desc.type != NFT_DATA_VALUE || desc.len != set->klen) {
+-              nft_data_release(&elem.key.val, desc.type);
+-              return err;
+-      }
+-
+       priv = set->ops->get(ctx->net, set, &elem, flags);
+       if (IS_ERR(priv))
+               return PTR_ERR(priv);
+@@ -4518,13 +4529,13 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+ {
+       struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
+       u8 genmask = nft_genmask_next(ctx->net);
+-      struct nft_data_desc d1, d2;
+       struct nft_set_ext_tmpl tmpl;
+       struct nft_set_ext *ext, *ext2;
+       struct nft_set_elem elem;
+       struct nft_set_binding *binding;
+       struct nft_object *obj = NULL;
+       struct nft_userdata *udata;
++      struct nft_data_desc desc;
+       struct nft_data data;
+       enum nft_registers dreg;
+       struct nft_trans *trans;
+@@ -4590,15 +4601,12 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+                       return err;
+       }
+-      err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &d1,
+-                          nla[NFTA_SET_ELEM_KEY]);
++      err = nft_setelem_parse_key(ctx, set, &elem.key.val,
++                                  nla[NFTA_SET_ELEM_KEY]);
+       if (err < 0)
+               goto err1;
+-      err = -EINVAL;
+-      if (d1.type != NFT_DATA_VALUE || d1.len != set->klen)
+-              goto err2;
+-      nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, d1.len);
++      nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+       if (timeout > 0) {
+               nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
+               if (timeout != set->timeout)
+@@ -4621,13 +4629,13 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+       }
+       if (nla[NFTA_SET_ELEM_DATA] != NULL) {
+-              err = nft_data_init(ctx, &data, sizeof(data), &d2,
++              err = nft_data_init(ctx, &data, sizeof(data), &desc,
+                                   nla[NFTA_SET_ELEM_DATA]);
+               if (err < 0)
+                       goto err2;
+               err = -EINVAL;
+-              if (set->dtype != NFT_DATA_VERDICT && d2.len != set->dlen)
++              if (set->dtype != NFT_DATA_VERDICT && desc.len != set->dlen)
+                       goto err3;
+               dreg = nft_type_to_reg(set->dtype);
+@@ -4644,18 +4652,18 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+                       err = nft_validate_register_store(&bind_ctx, dreg,
+                                                         &data,
+-                                                        d2.type, d2.len);
++                                                        desc.type, desc.len);
+                       if (err < 0)
+                               goto err3;
+-                      if (d2.type == NFT_DATA_VERDICT &&
++                      if (desc.type == NFT_DATA_VERDICT &&
+                           (data.verdict.code == NFT_GOTO ||
+                            data.verdict.code == NFT_JUMP))
+                               nft_validate_state_update(ctx->net,
+                                                         NFT_VALIDATE_NEED);
+               }
+-              nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, d2.len);
++              nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, desc.len);
+       }
+       /* The full maximum length of userdata can exceed the maximum
+@@ -4738,9 +4746,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+       kfree(elem.priv);
+ err3:
+       if (nla[NFTA_SET_ELEM_DATA] != NULL)
+-              nft_data_release(&data, d2.type);
++              nft_data_release(&data, desc.type);
+ err2:
+-      nft_data_release(&elem.key.val, d1.type);
++      nft_data_release(&elem.key.val, NFT_DATA_VALUE);
+ err1:
+       return err;
+ }
+@@ -4836,7 +4844,6 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
+ {
+       struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
+       struct nft_set_ext_tmpl tmpl;
+-      struct nft_data_desc desc;
+       struct nft_set_elem elem;
+       struct nft_set_ext *ext;
+       struct nft_trans *trans;
+@@ -4847,11 +4854,10 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
+       err = nla_parse_nested_deprecated(nla, NFTA_SET_ELEM_MAX, attr,
+                                         nft_set_elem_policy, NULL);
+       if (err < 0)
+-              goto err1;
++              return err;
+-      err = -EINVAL;
+       if (nla[NFTA_SET_ELEM_KEY] == NULL)
+-              goto err1;
++              return -EINVAL;
+       nft_set_ext_prepare(&tmpl);
+@@ -4861,37 +4867,31 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
+       if (flags != 0)
+               nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
+-      err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &desc,
+-                          nla[NFTA_SET_ELEM_KEY]);
++      err = nft_setelem_parse_key(ctx, set, &elem.key.val,
++                                  nla[NFTA_SET_ELEM_KEY]);
+       if (err < 0)
+-              goto err1;
+-
+-      err = -EINVAL;
+-      if (desc.type != NFT_DATA_VALUE || desc.len != set->klen)
+-              goto err2;
++              return err;
+-      nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, desc.len);
++      nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+       err = -ENOMEM;
+       elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, NULL, 0,
+                                     0, GFP_KERNEL);
+       if (elem.priv == NULL)
+-              goto err2;
++              goto fail_elem;
+       ext = nft_set_elem_ext(set, elem.priv);
+       if (flags)
+               *nft_set_ext_flags(ext) = flags;
+       trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set);
+-      if (trans == NULL) {
+-              err = -ENOMEM;
+-              goto err3;
+-      }
++      if (trans == NULL)
++              goto fail_trans;
+       priv = set->ops->deactivate(ctx->net, set, &elem);
+       if (priv == NULL) {
+               err = -ENOENT;
+-              goto err4;
++              goto fail_ops;
+       }
+       kfree(elem.priv);
+       elem.priv = priv;
+@@ -4902,13 +4902,12 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
+       list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+       return 0;
+-err4:
++fail_ops:
+       kfree(trans);
+-err3:
++fail_trans:
+       kfree(elem.priv);
+-err2:
+-      nft_data_release(&elem.key.val, desc.type);
+-err1:
++fail_elem:
++      nft_data_release(&elem.key.val, NFT_DATA_VALUE);
+       return err;
+ }
+-- 
+2.39.2
+
diff --git a/queue-5.4/netfilter-nf_tables-allow-up-to-64-bytes-in-the-set-.patch b/queue-5.4/netfilter-nf_tables-allow-up-to-64-bytes-in-the-set-.patch
new file mode 100644 (file)
index 0000000..69b59a2
--- /dev/null
@@ -0,0 +1,132 @@
+From 2308733e8d55ddfc0529b673c8f2339d9313d542 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 16:44:32 +0200
+Subject: netfilter: nf_tables: allow up to 64 bytes in the set element data
+ area
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ fdb9c405e35bdc6e305b9b4e20ebc141ed14fc81 ]
+
+So far, the set elements could store up to 128-bits in the data area.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_tables.h |  4 +++
+ net/netfilter/nf_tables_api.c     | 41 +++++++++++++++++++++----------
+ 2 files changed, 32 insertions(+), 13 deletions(-)
+
+diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
+index ba5f97f5c490e..a8cc2750990f9 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -239,6 +239,10 @@ struct nft_set_elem {
+               u32             buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
+               struct nft_data val;
+       } key;
++      union {
++              u32             buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
++              struct nft_data val;
++      } data;
+       void                    *priv;
+ };
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 13a8a78b8ee8b..8648b3ced6221 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -4310,6 +4310,25 @@ static int nft_setelem_parse_key(struct nft_ctx *ctx, struct nft_set *set,
+       return 0;
+ }
++static int nft_setelem_parse_data(struct nft_ctx *ctx, struct nft_set *set,
++                                struct nft_data_desc *desc,
++                                struct nft_data *data,
++                                struct nlattr *attr)
++{
++      int err;
++
++      err = nft_data_init(ctx, data, NFT_DATA_VALUE_MAXLEN, desc, attr);
++      if (err < 0)
++              return err;
++
++      if (desc->type != NFT_DATA_VERDICT && desc->len != set->dlen) {
++              nft_data_release(data, desc->type);
++              return -EINVAL;
++      }
++
++      return 0;
++}
++
+ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+                           const struct nlattr *attr)
+ {
+@@ -4536,7 +4555,6 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+       struct nft_object *obj = NULL;
+       struct nft_userdata *udata;
+       struct nft_data_desc desc;
+-      struct nft_data data;
+       enum nft_registers dreg;
+       struct nft_trans *trans;
+       u32 flags = 0;
+@@ -4629,15 +4647,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+       }
+       if (nla[NFTA_SET_ELEM_DATA] != NULL) {
+-              err = nft_data_init(ctx, &data, sizeof(data), &desc,
+-                                  nla[NFTA_SET_ELEM_DATA]);
++              err = nft_setelem_parse_data(ctx, set, &desc, &elem.data.val,
++                                           nla[NFTA_SET_ELEM_DATA]);
+               if (err < 0)
+                       goto err2;
+-              err = -EINVAL;
+-              if (set->dtype != NFT_DATA_VERDICT && desc.len != set->dlen)
+-                      goto err3;
+-
+               dreg = nft_type_to_reg(set->dtype);
+               list_for_each_entry(binding, &set->bindings, list) {
+                       struct nft_ctx bind_ctx = {
+@@ -4651,14 +4665,14 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+                               continue;
+                       err = nft_validate_register_store(&bind_ctx, dreg,
+-                                                        &data,
++                                                        &elem.data.val,
+                                                         desc.type, desc.len);
+                       if (err < 0)
+                               goto err3;
+                       if (desc.type == NFT_DATA_VERDICT &&
+-                          (data.verdict.code == NFT_GOTO ||
+-                           data.verdict.code == NFT_JUMP))
++                          (elem.data.val.verdict.code == NFT_GOTO ||
++                           elem.data.val.verdict.code == NFT_JUMP))
+                               nft_validate_state_update(ctx->net,
+                                                         NFT_VALIDATE_NEED);
+               }
+@@ -4679,8 +4693,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+       }
+       err = -ENOMEM;
+-      elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, data.data,
+-                                    timeout, expiration, GFP_KERNEL);
++      elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data,
++                                    elem.data.val.data, timeout, expiration,
++                                    GFP_KERNEL);
+       if (elem.priv == NULL)
+               goto err3;
+@@ -4746,7 +4761,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+       kfree(elem.priv);
+ err3:
+       if (nla[NFTA_SET_ELEM_DATA] != NULL)
+-              nft_data_release(&data, desc.type);
++              nft_data_release(&elem.data.val, desc.type);
+ err2:
+       nft_data_release(&elem.key.val, NFT_DATA_VALUE);
+ err1:
+-- 
+2.39.2
+
diff --git a/queue-5.4/netfilter-nf_tables-hold-mutex-on-netns-pre_exit-pat.patch b/queue-5.4/netfilter-nf_tables-hold-mutex-on-netns-pre_exit-pat.patch
new file mode 100644 (file)
index 0000000..6df336b
--- /dev/null
@@ -0,0 +1,35 @@
+From d2227be0586c0031c775ffe845967d7e83567bb4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 16:44:35 +0200
+Subject: netfilter: nf_tables: hold mutex on netns pre_exit path
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 3923b1e4406680d57da7e873da77b1683035d83f ]
+
+clean_net() runs in workqueue while walking over the lists, grab mutex.
+
+Fixes: 767d1216bff8 ("netfilter: nftables: fix possible UAF over chains from packet path in netns")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_tables_api.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index e4eef4947cc75..909076ef157e8 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -7866,7 +7866,9 @@ static int __net_init nf_tables_init_net(struct net *net)
+ static void __net_exit nf_tables_pre_exit_net(struct net *net)
+ {
++      mutex_lock(&net->nft.commit_mutex);
+       __nft_release_hooks(net);
++      mutex_unlock(&net->nft.commit_mutex);
+ }
+ static void __net_exit nf_tables_exit_net(struct net *net)
+-- 
+2.39.2
+
diff --git a/queue-5.4/netfilter-nf_tables-stricter-validation-of-element-d.patch b/queue-5.4/netfilter-nf_tables-stricter-validation-of-element-d.patch
new file mode 100644 (file)
index 0000000..afb8bd9
--- /dev/null
@@ -0,0 +1,49 @@
+From 85d6a0c346a89b06a391a0d502c524877bde3247 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 16:44:33 +0200
+Subject: netfilter: nf_tables: stricter validation of element data
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 7e6bc1f6cabcd30aba0b11219d8e01b952eacbb6 ]
+
+Make sure element data type and length do not mismatch the one specified
+by the set declaration.
+
+Fixes: 7d7402642eaf ("netfilter: nf_tables: variable sized set element keys / data")
+Reported-by: Hugues ANGUELKOV <hanguelkov@randorisec.fr>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_tables_api.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 8648b3ced6221..c82c4635c0a96 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -4315,13 +4315,20 @@ static int nft_setelem_parse_data(struct nft_ctx *ctx, struct nft_set *set,
+                                 struct nft_data *data,
+                                 struct nlattr *attr)
+ {
++      u32 dtype;
+       int err;
+       err = nft_data_init(ctx, data, NFT_DATA_VALUE_MAXLEN, desc, attr);
+       if (err < 0)
+               return err;
+-      if (desc->type != NFT_DATA_VERDICT && desc->len != set->dlen) {
++      if (set->dtype == NFT_DATA_VERDICT)
++              dtype = NFT_DATA_VERDICT;
++      else
++              dtype = NFT_DATA_VALUE;
++
++      if (dtype != desc->type ||
++          set->dlen != desc->len) {
+               nft_data_release(data, desc->type);
+               return -EINVAL;
+       }
+-- 
+2.39.2
+
diff --git a/queue-5.4/netfilter-nf_tables-validate-nfta_set_elem_objref-ba.patch b/queue-5.4/netfilter-nf_tables-validate-nfta_set_elem_objref-ba.patch
new file mode 100644 (file)
index 0000000..32ec984
--- /dev/null
@@ -0,0 +1,57 @@
+From 8321589c67e4b29ff1a05531674cb298a08bac32 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 16:44:34 +0200
+Subject: netfilter: nf_tables: validate NFTA_SET_ELEM_OBJREF based on
+ NFT_SET_OBJECT flag
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 5a2f3dc31811e93be15522d9eb13ed61460b76c8 ]
+
+If the NFTA_SET_ELEM_OBJREF netlink attribute is present and
+NFT_SET_OBJECT flag is set on, report EINVAL.
+
+Move existing sanity check earlier to validate that NFT_SET_OBJECT
+requires NFTA_SET_ELEM_OBJREF.
+
+Fixes: 8aeff920dcc9 ("netfilter: nf_tables: add stateful object reference to set elements")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_tables_api.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index c82c4635c0a96..e4eef4947cc75 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -4595,6 +4595,15 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+                       return -EINVAL;
+       }
++      if (set->flags & NFT_SET_OBJECT) {
++              if (!nla[NFTA_SET_ELEM_OBJREF] &&
++                  !(flags & NFT_SET_ELEM_INTERVAL_END))
++                      return -EINVAL;
++      } else {
++              if (nla[NFTA_SET_ELEM_OBJREF])
++                      return -EINVAL;
++      }
++
+       if ((flags & NFT_SET_ELEM_INTERVAL_END) &&
+            (nla[NFTA_SET_ELEM_DATA] ||
+             nla[NFTA_SET_ELEM_OBJREF] ||
+@@ -4639,10 +4648,6 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+       }
+       if (nla[NFTA_SET_ELEM_OBJREF] != NULL) {
+-              if (!(set->flags & NFT_SET_OBJECT)) {
+-                      err = -EINVAL;
+-                      goto err2;
+-              }
+               obj = nft_obj_lookup(ctx->net, ctx->table,
+                                    nla[NFTA_SET_ELEM_OBJREF],
+                                    set->objtype, genmask);
+-- 
+2.39.2
+
diff --git a/queue-5.4/netfilter-nf_tables-validate-registers-coming-from-u.patch b/queue-5.4/netfilter-nf_tables-validate-registers-coming-from-u.patch
new file mode 100644 (file)
index 0000000..90334d9
--- /dev/null
@@ -0,0 +1,85 @@
+From 01f18fd7566655edf8f9c8ca6895c13cc372ce2a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 16:44:30 +0200
+Subject: netfilter: nf_tables: validate registers coming from userspace.
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 6e1acfa387b9ff82cfc7db8cc3b6959221a95851 ]
+
+Bail out in case userspace uses unsupported registers.
+
+Fixes: 49499c3e6e18 ("netfilter: nf_tables: switch registers to 32 bit addressing")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_tables_api.c | 31 +++++++++++++++++--------------
+ 1 file changed, 17 insertions(+), 14 deletions(-)
+
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 8a0095664e619..a90bf82ea1435 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -7384,26 +7384,23 @@ int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest)
+ }
+ EXPORT_SYMBOL_GPL(nft_parse_u32_check);
+-/**
+- *    nft_parse_register - parse a register value from a netlink attribute
+- *
+- *    @attr: netlink attribute
+- *
+- *    Parse and translate a register value from a netlink attribute.
+- *    Registers used to be 128 bit wide, these register numbers will be
+- *    mapped to the corresponding 32 bit register numbers.
+- */
+-static unsigned int nft_parse_register(const struct nlattr *attr)
++static int nft_parse_register(const struct nlattr *attr, u32 *preg)
+ {
+       unsigned int reg;
+       reg = ntohl(nla_get_be32(attr));
+       switch (reg) {
+       case NFT_REG_VERDICT...NFT_REG_4:
+-              return reg * NFT_REG_SIZE / NFT_REG32_SIZE;
++              *preg = reg * NFT_REG_SIZE / NFT_REG32_SIZE;
++              break;
++      case NFT_REG32_00...NFT_REG32_15:
++              *preg = reg + NFT_REG_SIZE / NFT_REG32_SIZE - NFT_REG32_00;
++              break;
+       default:
+-              return reg + NFT_REG_SIZE / NFT_REG32_SIZE - NFT_REG32_00;
++              return -ERANGE;
+       }
++
++      return 0;
+ }
+ /**
+@@ -7454,7 +7451,10 @@ int nft_parse_register_load(const struct nlattr *attr, u8 *sreg, u32 len)
+       u32 reg;
+       int err;
+-      reg = nft_parse_register(attr);
++      err = nft_parse_register(attr, &reg);
++      if (err < 0)
++              return err;
++
+       err = nft_validate_register_load(reg, len);
+       if (err < 0)
+               return err;
+@@ -7523,7 +7523,10 @@ int nft_parse_register_store(const struct nft_ctx *ctx,
+       int err;
+       u32 reg;
+-      reg = nft_parse_register(attr);
++      err = nft_parse_register(attr, &reg);
++      if (err < 0)
++              return err;
++
+       err = nft_validate_register_store(ctx, reg, data, type, len);
+       if (err < 0)
+               return err;
+-- 
+2.39.2
+
diff --git a/queue-5.4/netfilter-nftables-add-nft_parse_register_load-and-u.patch b/queue-5.4/netfilter-nftables-add-nft_parse_register_load-and-u.patch
new file mode 100644 (file)
index 0000000..00ff46b
--- /dev/null
@@ -0,0 +1,844 @@
+From bd5801d3135969cec2bd75859b12148c22c1ef47 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 16:44:27 +0200
+Subject: netfilter: nftables: add nft_parse_register_load() and use it
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 4f16d25c68ec844299a4df6ecbb0234eaf88a935 ]
+
+This new function combines the netlink register attribute parser
+and the load validation function.
+
+This update requires to replace:
+
+       enum nft_registers      sreg:8;
+
+in many of the expression private areas otherwise compiler complains
+with:
+
+       error: cannot take address of bit-field â€˜sreg’
+
+when passing the register field as reference.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_tables.h      |  2 +-
+ include/net/netfilter/nf_tables_core.h |  4 +--
+ include/net/netfilter/nft_meta.h       |  2 +-
+ net/ipv4/netfilter/nft_dup_ipv4.c      | 18 ++++++-------
+ net/ipv6/netfilter/nft_dup_ipv6.c      | 18 ++++++-------
+ net/netfilter/nf_tables_api.c          | 18 +++++++++++--
+ net/netfilter/nft_bitwise.c            |  6 ++---
+ net/netfilter/nft_byteorder.c          |  6 ++---
+ net/netfilter/nft_cmp.c                |  8 +++---
+ net/netfilter/nft_ct.c                 |  5 ++--
+ net/netfilter/nft_dup_netdev.c         |  6 ++---
+ net/netfilter/nft_dynset.c             | 12 ++++-----
+ net/netfilter/nft_exthdr.c             |  6 ++---
+ net/netfilter/nft_fwd_netdev.c         | 18 ++++++-------
+ net/netfilter/nft_hash.c               | 10 +++++---
+ net/netfilter/nft_lookup.c             |  6 ++---
+ net/netfilter/nft_masq.c               | 18 ++++++-------
+ net/netfilter/nft_meta.c               |  3 +--
+ net/netfilter/nft_nat.c                | 35 +++++++++++---------------
+ net/netfilter/nft_objref.c             |  6 ++---
+ net/netfilter/nft_payload.c            |  4 +--
+ net/netfilter/nft_queue.c              | 12 ++++-----
+ net/netfilter/nft_range.c              |  6 ++---
+ net/netfilter/nft_redir.c              | 18 ++++++-------
+ net/netfilter/nft_tproxy.c             | 14 +++++------
+ 25 files changed, 129 insertions(+), 132 deletions(-)
+
+diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
+index ad2a52a6c478b..78181f017681b 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -208,7 +208,7 @@ int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest);
+ unsigned int nft_parse_register(const struct nlattr *attr);
+ int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int reg);
+-int nft_validate_register_load(enum nft_registers reg, unsigned int len);
++int nft_parse_register_load(const struct nlattr *attr, u8 *sreg, u32 len);
+ int nft_validate_register_store(const struct nft_ctx *ctx,
+                               enum nft_registers reg,
+                               const struct nft_data *data,
+diff --git a/include/net/netfilter/nf_tables_core.h b/include/net/netfilter/nf_tables_core.h
+index 7281895fa6d99..c57ecb9e157cd 100644
+--- a/include/net/netfilter/nf_tables_core.h
++++ b/include/net/netfilter/nf_tables_core.h
+@@ -25,7 +25,7 @@ void nf_tables_core_module_exit(void);
+ struct nft_cmp_fast_expr {
+       u32                     data;
+-      enum nft_registers      sreg:8;
++      u8                      sreg;
+       u8                      len;
+ };
+@@ -58,7 +58,7 @@ struct nft_payload_set {
+       enum nft_payload_bases  base:8;
+       u8                      offset;
+       u8                      len;
+-      enum nft_registers      sreg:8;
++      u8                      sreg;
+       u8                      csum_type;
+       u8                      csum_offset;
+       u8                      csum_flags;
+diff --git a/include/net/netfilter/nft_meta.h b/include/net/netfilter/nft_meta.h
+index 07e2fd507963a..946fa8c83798e 100644
+--- a/include/net/netfilter/nft_meta.h
++++ b/include/net/netfilter/nft_meta.h
+@@ -8,7 +8,7 @@ struct nft_meta {
+       enum nft_meta_keys      key:8;
+       union {
+               enum nft_registers      dreg:8;
+-              enum nft_registers      sreg:8;
++              u8              sreg;
+       };
+ };
+diff --git a/net/ipv4/netfilter/nft_dup_ipv4.c b/net/ipv4/netfilter/nft_dup_ipv4.c
+index abf89b9720940..330349b5d6a4f 100644
+--- a/net/ipv4/netfilter/nft_dup_ipv4.c
++++ b/net/ipv4/netfilter/nft_dup_ipv4.c
+@@ -13,8 +13,8 @@
+ #include <net/netfilter/ipv4/nf_dup_ipv4.h>
+ struct nft_dup_ipv4 {
+-      enum nft_registers      sreg_addr:8;
+-      enum nft_registers      sreg_dev:8;
++      u8      sreg_addr;
++      u8      sreg_dev;
+ };
+ static void nft_dup_ipv4_eval(const struct nft_expr *expr,
+@@ -40,16 +40,16 @@ static int nft_dup_ipv4_init(const struct nft_ctx *ctx,
+       if (tb[NFTA_DUP_SREG_ADDR] == NULL)
+               return -EINVAL;
+-      priv->sreg_addr = nft_parse_register(tb[NFTA_DUP_SREG_ADDR]);
+-      err = nft_validate_register_load(priv->sreg_addr, sizeof(struct in_addr));
++      err = nft_parse_register_load(tb[NFTA_DUP_SREG_ADDR], &priv->sreg_addr,
++                                    sizeof(struct in_addr));
+       if (err < 0)
+               return err;
+-      if (tb[NFTA_DUP_SREG_DEV] != NULL) {
+-              priv->sreg_dev = nft_parse_register(tb[NFTA_DUP_SREG_DEV]);
+-              return nft_validate_register_load(priv->sreg_dev, sizeof(int));
+-      }
+-      return 0;
++      if (tb[NFTA_DUP_SREG_DEV])
++              err = nft_parse_register_load(tb[NFTA_DUP_SREG_DEV],
++                                            &priv->sreg_dev, sizeof(int));
++
++      return err;
+ }
+ static int nft_dup_ipv4_dump(struct sk_buff *skb, const struct nft_expr *expr)
+diff --git a/net/ipv6/netfilter/nft_dup_ipv6.c b/net/ipv6/netfilter/nft_dup_ipv6.c
+index 2af32200507d0..c4aa8d27e0401 100644
+--- a/net/ipv6/netfilter/nft_dup_ipv6.c
++++ b/net/ipv6/netfilter/nft_dup_ipv6.c
+@@ -13,8 +13,8 @@
+ #include <net/netfilter/ipv6/nf_dup_ipv6.h>
+ struct nft_dup_ipv6 {
+-      enum nft_registers      sreg_addr:8;
+-      enum nft_registers      sreg_dev:8;
++      u8      sreg_addr;
++      u8      sreg_dev;
+ };
+ static void nft_dup_ipv6_eval(const struct nft_expr *expr,
+@@ -38,16 +38,16 @@ static int nft_dup_ipv6_init(const struct nft_ctx *ctx,
+       if (tb[NFTA_DUP_SREG_ADDR] == NULL)
+               return -EINVAL;
+-      priv->sreg_addr = nft_parse_register(tb[NFTA_DUP_SREG_ADDR]);
+-      err = nft_validate_register_load(priv->sreg_addr, sizeof(struct in6_addr));
++      err = nft_parse_register_load(tb[NFTA_DUP_SREG_ADDR], &priv->sreg_addr,
++                                    sizeof(struct in6_addr));
+       if (err < 0)
+               return err;
+-      if (tb[NFTA_DUP_SREG_DEV] != NULL) {
+-              priv->sreg_dev = nft_parse_register(tb[NFTA_DUP_SREG_DEV]);
+-              return nft_validate_register_load(priv->sreg_dev, sizeof(int));
+-      }
+-      return 0;
++      if (tb[NFTA_DUP_SREG_DEV])
++              err = nft_parse_register_load(tb[NFTA_DUP_SREG_DEV],
++                                            &priv->sreg_dev, sizeof(int));
++
++      return err;
+ }
+ static int nft_dup_ipv6_dump(struct sk_buff *skb, const struct nft_expr *expr)
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 7794fa4c669d6..26390fb986215 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -7432,7 +7432,7 @@ EXPORT_SYMBOL_GPL(nft_dump_register);
+  *    Validate that the input register is one of the general purpose
+  *    registers and that the length of the load is within the bounds.
+  */
+-int nft_validate_register_load(enum nft_registers reg, unsigned int len)
++static int nft_validate_register_load(enum nft_registers reg, unsigned int len)
+ {
+       if (reg < NFT_REG_1 * NFT_REG_SIZE / NFT_REG32_SIZE)
+               return -EINVAL;
+@@ -7443,7 +7443,21 @@ int nft_validate_register_load(enum nft_registers reg, unsigned int len)
+       return 0;
+ }
+-EXPORT_SYMBOL_GPL(nft_validate_register_load);
++
++int nft_parse_register_load(const struct nlattr *attr, u8 *sreg, u32 len)
++{
++      u32 reg;
++      int err;
++
++      reg = nft_parse_register(attr);
++      err = nft_validate_register_load(reg, len);
++      if (err < 0)
++              return err;
++
++      *sreg = reg;
++      return 0;
++}
++EXPORT_SYMBOL_GPL(nft_parse_register_load);
+ /**
+  *    nft_validate_register_store - validate an expressions' register store
+diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
+index 10e9d50e4e193..850c6b5713b43 100644
+--- a/net/netfilter/nft_bitwise.c
++++ b/net/netfilter/nft_bitwise.c
+@@ -16,7 +16,7 @@
+ #include <net/netfilter/nf_tables_offload.h>
+ struct nft_bitwise {
+-      enum nft_registers      sreg:8;
++      u8                      sreg;
+       enum nft_registers      dreg:8;
+       u8                      len;
+       struct nft_data         mask;
+@@ -65,8 +65,8 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
+       priv->len = len;
+-      priv->sreg = nft_parse_register(tb[NFTA_BITWISE_SREG]);
+-      err = nft_validate_register_load(priv->sreg, priv->len);
++      err = nft_parse_register_load(tb[NFTA_BITWISE_SREG], &priv->sreg,
++                                    priv->len);
+       if (err < 0)
+               return err;
+diff --git a/net/netfilter/nft_byteorder.c b/net/netfilter/nft_byteorder.c
+index 12bed3f7bbc6d..0960563cd5a19 100644
+--- a/net/netfilter/nft_byteorder.c
++++ b/net/netfilter/nft_byteorder.c
+@@ -16,7 +16,7 @@
+ #include <net/netfilter/nf_tables.h>
+ struct nft_byteorder {
+-      enum nft_registers      sreg:8;
++      u8                      sreg;
+       enum nft_registers      dreg:8;
+       enum nft_byteorder_ops  op:8;
+       u8                      len;
+@@ -131,14 +131,14 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
+               return -EINVAL;
+       }
+-      priv->sreg = nft_parse_register(tb[NFTA_BYTEORDER_SREG]);
+       err = nft_parse_u32_check(tb[NFTA_BYTEORDER_LEN], U8_MAX, &len);
+       if (err < 0)
+               return err;
+       priv->len = len;
+-      err = nft_validate_register_load(priv->sreg, priv->len);
++      err = nft_parse_register_load(tb[NFTA_BYTEORDER_SREG], &priv->sreg,
++                                    priv->len);
+       if (err < 0)
+               return err;
+diff --git a/net/netfilter/nft_cmp.c b/net/netfilter/nft_cmp.c
+index ae730dba60c8e..a7c1e7c4381a1 100644
+--- a/net/netfilter/nft_cmp.c
++++ b/net/netfilter/nft_cmp.c
+@@ -17,7 +17,7 @@
+ struct nft_cmp_expr {
+       struct nft_data         data;
+-      enum nft_registers      sreg:8;
++      u8                      sreg;
+       u8                      len;
+       enum nft_cmp_ops        op:8;
+ };
+@@ -86,8 +86,7 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
+               return err;
+       }
+-      priv->sreg = nft_parse_register(tb[NFTA_CMP_SREG]);
+-      err = nft_validate_register_load(priv->sreg, desc.len);
++      err = nft_parse_register_load(tb[NFTA_CMP_SREG], &priv->sreg, desc.len);
+       if (err < 0)
+               return err;
+@@ -169,8 +168,7 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx,
+       if (err < 0)
+               return err;
+-      priv->sreg = nft_parse_register(tb[NFTA_CMP_SREG]);
+-      err = nft_validate_register_load(priv->sreg, desc.len);
++      err = nft_parse_register_load(tb[NFTA_CMP_SREG], &priv->sreg, desc.len);
+       if (err < 0)
+               return err;
+diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
+index 28991730728b9..edc6b8ae06480 100644
+--- a/net/netfilter/nft_ct.c
++++ b/net/netfilter/nft_ct.c
+@@ -28,7 +28,7 @@ struct nft_ct {
+       enum ip_conntrack_dir   dir:8;
+       union {
+               enum nft_registers      dreg:8;
+-              enum nft_registers      sreg:8;
++              u8              sreg;
+       };
+ };
+@@ -600,8 +600,7 @@ static int nft_ct_set_init(const struct nft_ctx *ctx,
+               }
+       }
+-      priv->sreg = nft_parse_register(tb[NFTA_CT_SREG]);
+-      err = nft_validate_register_load(priv->sreg, len);
++      err = nft_parse_register_load(tb[NFTA_CT_SREG], &priv->sreg, len);
+       if (err < 0)
+               goto err1;
+diff --git a/net/netfilter/nft_dup_netdev.c b/net/netfilter/nft_dup_netdev.c
+index 6007089e1c2f7..a5b560ee0337a 100644
+--- a/net/netfilter/nft_dup_netdev.c
++++ b/net/netfilter/nft_dup_netdev.c
+@@ -14,7 +14,7 @@
+ #include <net/netfilter/nf_dup_netdev.h>
+ struct nft_dup_netdev {
+-      enum nft_registers      sreg_dev:8;
++      u8      sreg_dev;
+ };
+ static void nft_dup_netdev_eval(const struct nft_expr *expr,
+@@ -40,8 +40,8 @@ static int nft_dup_netdev_init(const struct nft_ctx *ctx,
+       if (tb[NFTA_DUP_SREG_DEV] == NULL)
+               return -EINVAL;
+-      priv->sreg_dev = nft_parse_register(tb[NFTA_DUP_SREG_DEV]);
+-      return nft_validate_register_load(priv->sreg_dev, sizeof(int));
++      return nft_parse_register_load(tb[NFTA_DUP_SREG_DEV], &priv->sreg_dev,
++                                     sizeof(int));
+ }
+ static int nft_dup_netdev_dump(struct sk_buff *skb, const struct nft_expr *expr)
+diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
+index 7f9e6c90f7271..9f064f7b31d6d 100644
+--- a/net/netfilter/nft_dynset.c
++++ b/net/netfilter/nft_dynset.c
+@@ -16,8 +16,8 @@ struct nft_dynset {
+       struct nft_set                  *set;
+       struct nft_set_ext_tmpl         tmpl;
+       enum nft_dynset_ops             op:8;
+-      enum nft_registers              sreg_key:8;
+-      enum nft_registers              sreg_data:8;
++      u8                              sreg_key;
++      u8                              sreg_data;
+       bool                            invert;
+       u64                             timeout;
+       struct nft_expr                 *expr;
+@@ -177,8 +177,8 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
+                       return err;
+       }
+-      priv->sreg_key = nft_parse_register(tb[NFTA_DYNSET_SREG_KEY]);
+-      err = nft_validate_register_load(priv->sreg_key, set->klen);
++      err = nft_parse_register_load(tb[NFTA_DYNSET_SREG_KEY], &priv->sreg_key,
++                                    set->klen);
+       if (err < 0)
+               return err;
+@@ -188,8 +188,8 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
+               if (set->dtype == NFT_DATA_VERDICT)
+                       return -EOPNOTSUPP;
+-              priv->sreg_data = nft_parse_register(tb[NFTA_DYNSET_SREG_DATA]);
+-              err = nft_validate_register_load(priv->sreg_data, set->dlen);
++              err = nft_parse_register_load(tb[NFTA_DYNSET_SREG_DATA],
++                                            &priv->sreg_data, set->dlen);
+               if (err < 0)
+                       return err;
+       } else if (set->flags & NFT_SET_MAP)
+diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c
+index faa0844c01fb8..f2b36b9c2b53c 100644
+--- a/net/netfilter/nft_exthdr.c
++++ b/net/netfilter/nft_exthdr.c
+@@ -20,7 +20,7 @@ struct nft_exthdr {
+       u8                      len;
+       u8                      op;
+       enum nft_registers      dreg:8;
+-      enum nft_registers      sreg:8;
++      u8                      sreg;
+       u8                      flags;
+ };
+@@ -403,11 +403,11 @@ static int nft_exthdr_tcp_set_init(const struct nft_ctx *ctx,
+       priv->type   = nla_get_u8(tb[NFTA_EXTHDR_TYPE]);
+       priv->offset = offset;
+       priv->len    = len;
+-      priv->sreg   = nft_parse_register(tb[NFTA_EXTHDR_SREG]);
+       priv->flags  = flags;
+       priv->op     = op;
+-      return nft_validate_register_load(priv->sreg, priv->len);
++      return nft_parse_register_load(tb[NFTA_EXTHDR_SREG], &priv->sreg,
++                                     priv->len);
+ }
+ static int nft_exthdr_ipv4_init(const struct nft_ctx *ctx,
+diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c
+index 3b0dcd170551b..7730409f6f091 100644
+--- a/net/netfilter/nft_fwd_netdev.c
++++ b/net/netfilter/nft_fwd_netdev.c
+@@ -18,7 +18,7 @@
+ #include <net/ip.h>
+ struct nft_fwd_netdev {
+-      enum nft_registers      sreg_dev:8;
++      u8      sreg_dev;
+ };
+ static void nft_fwd_netdev_eval(const struct nft_expr *expr,
+@@ -50,8 +50,8 @@ static int nft_fwd_netdev_init(const struct nft_ctx *ctx,
+       if (tb[NFTA_FWD_SREG_DEV] == NULL)
+               return -EINVAL;
+-      priv->sreg_dev = nft_parse_register(tb[NFTA_FWD_SREG_DEV]);
+-      return nft_validate_register_load(priv->sreg_dev, sizeof(int));
++      return nft_parse_register_load(tb[NFTA_FWD_SREG_DEV], &priv->sreg_dev,
++                                     sizeof(int));
+ }
+ static int nft_fwd_netdev_dump(struct sk_buff *skb, const struct nft_expr *expr)
+@@ -83,8 +83,8 @@ static bool nft_fwd_netdev_offload_action(const struct nft_expr *expr)
+ }
+ struct nft_fwd_neigh {
+-      enum nft_registers      sreg_dev:8;
+-      enum nft_registers      sreg_addr:8;
++      u8                      sreg_dev;
++      u8                      sreg_addr;
+       u8                      nfproto;
+ };
+@@ -162,8 +162,6 @@ static int nft_fwd_neigh_init(const struct nft_ctx *ctx,
+           !tb[NFTA_FWD_NFPROTO])
+               return -EINVAL;
+-      priv->sreg_dev = nft_parse_register(tb[NFTA_FWD_SREG_DEV]);
+-      priv->sreg_addr = nft_parse_register(tb[NFTA_FWD_SREG_ADDR]);
+       priv->nfproto = ntohl(nla_get_be32(tb[NFTA_FWD_NFPROTO]));
+       switch (priv->nfproto) {
+@@ -177,11 +175,13 @@ static int nft_fwd_neigh_init(const struct nft_ctx *ctx,
+               return -EOPNOTSUPP;
+       }
+-      err = nft_validate_register_load(priv->sreg_dev, sizeof(int));
++      err = nft_parse_register_load(tb[NFTA_FWD_SREG_DEV], &priv->sreg_dev,
++                                    sizeof(int));
+       if (err < 0)
+               return err;
+-      return nft_validate_register_load(priv->sreg_addr, addr_len);
++      return nft_parse_register_load(tb[NFTA_FWD_SREG_ADDR], &priv->sreg_addr,
++                                     addr_len);
+ }
+ static int nft_fwd_neigh_dump(struct sk_buff *skb, const struct nft_expr *expr)
+diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c
+index b836d550b9199..3b01ad0a02dfe 100644
+--- a/net/netfilter/nft_hash.c
++++ b/net/netfilter/nft_hash.c
+@@ -14,7 +14,7 @@
+ #include <linux/jhash.h>
+ struct nft_jhash {
+-      enum nft_registers      sreg:8;
++      u8                      sreg;
+       enum nft_registers      dreg:8;
+       u8                      len;
+       bool                    autogen_seed:1;
+@@ -83,7 +83,6 @@ static int nft_jhash_init(const struct nft_ctx *ctx,
+       if (tb[NFTA_HASH_OFFSET])
+               priv->offset = ntohl(nla_get_be32(tb[NFTA_HASH_OFFSET]));
+-      priv->sreg = nft_parse_register(tb[NFTA_HASH_SREG]);
+       priv->dreg = nft_parse_register(tb[NFTA_HASH_DREG]);
+       err = nft_parse_u32_check(tb[NFTA_HASH_LEN], U8_MAX, &len);
+@@ -94,6 +93,10 @@ static int nft_jhash_init(const struct nft_ctx *ctx,
+       priv->len = len;
++      err = nft_parse_register_load(tb[NFTA_HASH_SREG], &priv->sreg, len);
++      if (err < 0)
++              return err;
++
+       priv->modulus = ntohl(nla_get_be32(tb[NFTA_HASH_MODULUS]));
+       if (priv->modulus < 1)
+               return -ERANGE;
+@@ -108,8 +111,7 @@ static int nft_jhash_init(const struct nft_ctx *ctx,
+               get_random_bytes(&priv->seed, sizeof(priv->seed));
+       }
+-      return nft_validate_register_load(priv->sreg, len) &&
+-             nft_validate_register_store(ctx, priv->dreg, NULL,
++      return nft_validate_register_store(ctx, priv->dreg, NULL,
+                                          NFT_DATA_VALUE, sizeof(u32));
+ }
+diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c
+index 4eb4d076927e4..349591dabb36a 100644
+--- a/net/netfilter/nft_lookup.c
++++ b/net/netfilter/nft_lookup.c
+@@ -17,7 +17,7 @@
+ struct nft_lookup {
+       struct nft_set                  *set;
+-      enum nft_registers              sreg:8;
++      u8                              sreg;
+       enum nft_registers              dreg:8;
+       bool                            invert;
+       struct nft_set_binding          binding;
+@@ -73,8 +73,8 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
+       if (IS_ERR(set))
+               return PTR_ERR(set);
+-      priv->sreg = nft_parse_register(tb[NFTA_LOOKUP_SREG]);
+-      err = nft_validate_register_load(priv->sreg, set->klen);
++      err = nft_parse_register_load(tb[NFTA_LOOKUP_SREG], &priv->sreg,
++                                    set->klen);
+       if (err < 0)
+               return err;
+diff --git a/net/netfilter/nft_masq.c b/net/netfilter/nft_masq.c
+index 39dc94f2491e3..c2f04885347e7 100644
+--- a/net/netfilter/nft_masq.c
++++ b/net/netfilter/nft_masq.c
+@@ -15,8 +15,8 @@
+ struct nft_masq {
+       u32                     flags;
+-      enum nft_registers      sreg_proto_min:8;
+-      enum nft_registers      sreg_proto_max:8;
++      u8                      sreg_proto_min;
++      u8                      sreg_proto_max;
+ };
+ static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = {
+@@ -54,19 +54,15 @@ static int nft_masq_init(const struct nft_ctx *ctx,
+       }
+       if (tb[NFTA_MASQ_REG_PROTO_MIN]) {
+-              priv->sreg_proto_min =
+-                      nft_parse_register(tb[NFTA_MASQ_REG_PROTO_MIN]);
+-
+-              err = nft_validate_register_load(priv->sreg_proto_min, plen);
++              err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MIN],
++                                            &priv->sreg_proto_min, plen);
+               if (err < 0)
+                       return err;
+               if (tb[NFTA_MASQ_REG_PROTO_MAX]) {
+-                      priv->sreg_proto_max =
+-                              nft_parse_register(tb[NFTA_MASQ_REG_PROTO_MAX]);
+-
+-                      err = nft_validate_register_load(priv->sreg_proto_max,
+-                                                       plen);
++                      err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MAX],
++                                                    &priv->sreg_proto_max,
++                                                    plen);
+                       if (err < 0)
+                               return err;
+               } else {
+diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
+index dda1e55d5801a..28761430d9ee4 100644
+--- a/net/netfilter/nft_meta.c
++++ b/net/netfilter/nft_meta.c
+@@ -475,8 +475,7 @@ int nft_meta_set_init(const struct nft_ctx *ctx,
+               return -EOPNOTSUPP;
+       }
+-      priv->sreg = nft_parse_register(tb[NFTA_META_SREG]);
+-      err = nft_validate_register_load(priv->sreg, len);
++      err = nft_parse_register_load(tb[NFTA_META_SREG], &priv->sreg, len);
+       if (err < 0)
+               return err;
+diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c
+index 0c5bc3c37ecf4..50fbd3c1d9f19 100644
+--- a/net/netfilter/nft_nat.c
++++ b/net/netfilter/nft_nat.c
+@@ -21,10 +21,10 @@
+ #include <net/ip.h>
+ struct nft_nat {
+-      enum nft_registers      sreg_addr_min:8;
+-      enum nft_registers      sreg_addr_max:8;
+-      enum nft_registers      sreg_proto_min:8;
+-      enum nft_registers      sreg_proto_max:8;
++      u8                      sreg_addr_min;
++      u8                      sreg_addr_max;
++      u8                      sreg_proto_min;
++      u8                      sreg_proto_max;
+       enum nf_nat_manip_type  type:8;
+       u8                      family;
+       u16                     flags;
+@@ -154,18 +154,15 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
+       priv->family = family;
+       if (tb[NFTA_NAT_REG_ADDR_MIN]) {
+-              priv->sreg_addr_min =
+-                      nft_parse_register(tb[NFTA_NAT_REG_ADDR_MIN]);
+-              err = nft_validate_register_load(priv->sreg_addr_min, alen);
++              err = nft_parse_register_load(tb[NFTA_NAT_REG_ADDR_MIN],
++                                            &priv->sreg_addr_min, alen);
+               if (err < 0)
+                       return err;
+               if (tb[NFTA_NAT_REG_ADDR_MAX]) {
+-                      priv->sreg_addr_max =
+-                              nft_parse_register(tb[NFTA_NAT_REG_ADDR_MAX]);
+-
+-                      err = nft_validate_register_load(priv->sreg_addr_max,
+-                                                       alen);
++                      err = nft_parse_register_load(tb[NFTA_NAT_REG_ADDR_MAX],
++                                                    &priv->sreg_addr_max,
++                                                    alen);
+                       if (err < 0)
+                               return err;
+               } else {
+@@ -175,19 +172,15 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
+       plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
+       if (tb[NFTA_NAT_REG_PROTO_MIN]) {
+-              priv->sreg_proto_min =
+-                      nft_parse_register(tb[NFTA_NAT_REG_PROTO_MIN]);
+-
+-              err = nft_validate_register_load(priv->sreg_proto_min, plen);
++              err = nft_parse_register_load(tb[NFTA_NAT_REG_PROTO_MIN],
++                                            &priv->sreg_proto_min, plen);
+               if (err < 0)
+                       return err;
+               if (tb[NFTA_NAT_REG_PROTO_MAX]) {
+-                      priv->sreg_proto_max =
+-                              nft_parse_register(tb[NFTA_NAT_REG_PROTO_MAX]);
+-
+-                      err = nft_validate_register_load(priv->sreg_proto_max,
+-                                                       plen);
++                      err = nft_parse_register_load(tb[NFTA_NAT_REG_PROTO_MAX],
++                                                    &priv->sreg_proto_max,
++                                                    plen);
+                       if (err < 0)
+                               return err;
+               } else {
+diff --git a/net/netfilter/nft_objref.c b/net/netfilter/nft_objref.c
+index 74c61278e6bd3..7032b80592b20 100644
+--- a/net/netfilter/nft_objref.c
++++ b/net/netfilter/nft_objref.c
+@@ -95,7 +95,7 @@ static const struct nft_expr_ops nft_objref_ops = {
+ struct nft_objref_map {
+       struct nft_set          *set;
+-      enum nft_registers      sreg:8;
++      u8                      sreg;
+       struct nft_set_binding  binding;
+ };
+@@ -137,8 +137,8 @@ static int nft_objref_map_init(const struct nft_ctx *ctx,
+       if (!(set->flags & NFT_SET_OBJECT))
+               return -EINVAL;
+-      priv->sreg = nft_parse_register(tb[NFTA_OBJREF_SET_SREG]);
+-      err = nft_validate_register_load(priv->sreg, set->klen);
++      err = nft_parse_register_load(tb[NFTA_OBJREF_SET_SREG], &priv->sreg,
++                                    set->klen);
+       if (err < 0)
+               return err;
+diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
+index 6ed6ccef5e1ad..ce670c959a99e 100644
+--- a/net/netfilter/nft_payload.c
++++ b/net/netfilter/nft_payload.c
+@@ -564,7 +564,6 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
+       priv->base        = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
+       priv->offset      = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
+       priv->len         = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
+-      priv->sreg        = nft_parse_register(tb[NFTA_PAYLOAD_SREG]);
+       if (tb[NFTA_PAYLOAD_CSUM_TYPE])
+               csum_type = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_CSUM_TYPE]));
+@@ -595,7 +594,8 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
+       }
+       priv->csum_type = csum_type;
+-      return nft_validate_register_load(priv->sreg, priv->len);
++      return nft_parse_register_load(tb[NFTA_PAYLOAD_SREG], &priv->sreg,
++                                     priv->len);
+ }
+ static int nft_payload_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
+diff --git a/net/netfilter/nft_queue.c b/net/netfilter/nft_queue.c
+index 5ece0a6aa8c3c..94a4f0a5a28e4 100644
+--- a/net/netfilter/nft_queue.c
++++ b/net/netfilter/nft_queue.c
+@@ -19,10 +19,10 @@
+ static u32 jhash_initval __read_mostly;
+ struct nft_queue {
+-      enum nft_registers      sreg_qnum:8;
+-      u16                     queuenum;
+-      u16                     queues_total;
+-      u16                     flags;
++      u8      sreg_qnum;
++      u16     queuenum;
++      u16     queues_total;
++      u16     flags;
+ };
+ static void nft_queue_eval(const struct nft_expr *expr,
+@@ -111,8 +111,8 @@ static int nft_queue_sreg_init(const struct nft_ctx *ctx,
+       struct nft_queue *priv = nft_expr_priv(expr);
+       int err;
+-      priv->sreg_qnum = nft_parse_register(tb[NFTA_QUEUE_SREG_QNUM]);
+-      err = nft_validate_register_load(priv->sreg_qnum, sizeof(u32));
++      err = nft_parse_register_load(tb[NFTA_QUEUE_SREG_QNUM],
++                                    &priv->sreg_qnum, sizeof(u32));
+       if (err < 0)
+               return err;
+diff --git a/net/netfilter/nft_range.c b/net/netfilter/nft_range.c
+index 89efcc5a533d2..e4a1c44d7f513 100644
+--- a/net/netfilter/nft_range.c
++++ b/net/netfilter/nft_range.c
+@@ -15,7 +15,7 @@
+ struct nft_range_expr {
+       struct nft_data         data_from;
+       struct nft_data         data_to;
+-      enum nft_registers      sreg:8;
++      u8                      sreg;
+       u8                      len;
+       enum nft_range_ops      op:8;
+ };
+@@ -86,8 +86,8 @@ static int nft_range_init(const struct nft_ctx *ctx, const struct nft_expr *expr
+               goto err2;
+       }
+-      priv->sreg = nft_parse_register(tb[NFTA_RANGE_SREG]);
+-      err = nft_validate_register_load(priv->sreg, desc_from.len);
++      err = nft_parse_register_load(tb[NFTA_RANGE_SREG], &priv->sreg,
++                                    desc_from.len);
+       if (err < 0)
+               goto err2;
+diff --git a/net/netfilter/nft_redir.c b/net/netfilter/nft_redir.c
+index d75de63189b61..81a191eb5c368 100644
+--- a/net/netfilter/nft_redir.c
++++ b/net/netfilter/nft_redir.c
+@@ -14,8 +14,8 @@
+ #include <net/netfilter/nf_tables.h>
+ struct nft_redir {
+-      enum nft_registers      sreg_proto_min:8;
+-      enum nft_registers      sreg_proto_max:8;
++      u8                      sreg_proto_min;
++      u8                      sreg_proto_max;
+       u16                     flags;
+ };
+@@ -50,19 +50,15 @@ static int nft_redir_init(const struct nft_ctx *ctx,
+       plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
+       if (tb[NFTA_REDIR_REG_PROTO_MIN]) {
+-              priv->sreg_proto_min =
+-                      nft_parse_register(tb[NFTA_REDIR_REG_PROTO_MIN]);
+-
+-              err = nft_validate_register_load(priv->sreg_proto_min, plen);
++              err = nft_parse_register_load(tb[NFTA_REDIR_REG_PROTO_MIN],
++                                            &priv->sreg_proto_min, plen);
+               if (err < 0)
+                       return err;
+               if (tb[NFTA_REDIR_REG_PROTO_MAX]) {
+-                      priv->sreg_proto_max =
+-                              nft_parse_register(tb[NFTA_REDIR_REG_PROTO_MAX]);
+-
+-                      err = nft_validate_register_load(priv->sreg_proto_max,
+-                                                       plen);
++                      err = nft_parse_register_load(tb[NFTA_REDIR_REG_PROTO_MAX],
++                                                    &priv->sreg_proto_max,
++                                                    plen);
+                       if (err < 0)
+                               return err;
+               } else {
+diff --git a/net/netfilter/nft_tproxy.c b/net/netfilter/nft_tproxy.c
+index a0e30bf4a845c..db780b5985abc 100644
+--- a/net/netfilter/nft_tproxy.c
++++ b/net/netfilter/nft_tproxy.c
+@@ -13,9 +13,9 @@
+ #endif
+ struct nft_tproxy {
+-      enum nft_registers      sreg_addr:8;
+-      enum nft_registers      sreg_port:8;
+-      u8                      family;
++      u8      sreg_addr;
++      u8      sreg_port;
++      u8      family;
+ };
+ static void nft_tproxy_eval_v4(const struct nft_expr *expr,
+@@ -254,15 +254,15 @@ static int nft_tproxy_init(const struct nft_ctx *ctx,
+       }
+       if (tb[NFTA_TPROXY_REG_ADDR]) {
+-              priv->sreg_addr = nft_parse_register(tb[NFTA_TPROXY_REG_ADDR]);
+-              err = nft_validate_register_load(priv->sreg_addr, alen);
++              err = nft_parse_register_load(tb[NFTA_TPROXY_REG_ADDR],
++                                            &priv->sreg_addr, alen);
+               if (err < 0)
+                       return err;
+       }
+       if (tb[NFTA_TPROXY_REG_PORT]) {
+-              priv->sreg_port = nft_parse_register(tb[NFTA_TPROXY_REG_PORT]);
+-              err = nft_validate_register_load(priv->sreg_port, sizeof(u16));
++              err = nft_parse_register_load(tb[NFTA_TPROXY_REG_PORT],
++                                            &priv->sreg_port, sizeof(u16));
+               if (err < 0)
+                       return err;
+       }
+-- 
+2.39.2
+
diff --git a/queue-5.4/netfilter-nftables-add-nft_parse_register_store-and-.patch b/queue-5.4/netfilter-nftables-add-nft_parse_register_store-and-.patch
new file mode 100644 (file)
index 0000000..5276a1c
--- /dev/null
@@ -0,0 +1,650 @@
+From 4985cc7eea3721cbdf1fee35b9663aa8d783263d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 16:44:28 +0200
+Subject: netfilter: nftables: add nft_parse_register_store() and use it
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 345023b0db315648ccc3c1a36aee88304a8b4d91 ]
+
+This new function combines the netlink register attribute parser
+and the store validation function.
+
+This update requires to replace:
+
+        enum nft_registers      dreg:8;
+
+in many of the expression private areas otherwise compiler complains
+with:
+
+        error: cannot take address of bit-field â€˜dreg’
+
+when passing the register field as reference.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_tables.h      |  8 +++---
+ include/net/netfilter/nf_tables_core.h |  4 +--
+ include/net/netfilter/nft_fib.h        |  2 +-
+ include/net/netfilter/nft_meta.h       |  2 +-
+ net/bridge/netfilter/nft_meta_bridge.c |  5 ++--
+ net/netfilter/nf_tables_api.c          | 34 ++++++++++++++++++++++----
+ net/netfilter/nft_bitwise.c            |  8 +++---
+ net/netfilter/nft_byteorder.c          |  8 +++---
+ net/netfilter/nft_ct.c                 |  7 +++---
+ net/netfilter/nft_exthdr.c             |  8 +++---
+ net/netfilter/nft_fib.c                |  5 ++--
+ net/netfilter/nft_hash.c               | 17 ++++++-------
+ net/netfilter/nft_immediate.c          |  6 ++---
+ net/netfilter/nft_lookup.c             |  8 +++---
+ net/netfilter/nft_meta.c               |  5 ++--
+ net/netfilter/nft_numgen.c             | 15 +++++-------
+ net/netfilter/nft_osf.c                |  8 +++---
+ net/netfilter/nft_payload.c            |  6 ++---
+ net/netfilter/nft_rt.c                 |  7 +++---
+ net/netfilter/nft_socket.c             |  7 +++---
+ net/netfilter/nft_tunnel.c             |  8 +++---
+ net/netfilter/nft_xfrm.c               |  7 +++---
+ 22 files changed, 97 insertions(+), 88 deletions(-)
+
+diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
+index 78181f017681b..446f70132d827 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -209,10 +209,10 @@ unsigned int nft_parse_register(const struct nlattr *attr);
+ int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int reg);
+ int nft_parse_register_load(const struct nlattr *attr, u8 *sreg, u32 len);
+-int nft_validate_register_store(const struct nft_ctx *ctx,
+-                              enum nft_registers reg,
+-                              const struct nft_data *data,
+-                              enum nft_data_types type, unsigned int len);
++int nft_parse_register_store(const struct nft_ctx *ctx,
++                           const struct nlattr *attr, u8 *dreg,
++                           const struct nft_data *data,
++                           enum nft_data_types type, unsigned int len);
+ /**
+  *    struct nft_userdata - user defined data associated with an object
+diff --git a/include/net/netfilter/nf_tables_core.h b/include/net/netfilter/nf_tables_core.h
+index c57ecb9e157cd..6a3fd54c69c17 100644
+--- a/include/net/netfilter/nf_tables_core.h
++++ b/include/net/netfilter/nf_tables_core.h
+@@ -31,7 +31,7 @@ struct nft_cmp_fast_expr {
+ struct nft_immediate_expr {
+       struct nft_data         data;
+-      enum nft_registers      dreg:8;
++      u8                      dreg;
+       u8                      dlen;
+ };
+@@ -51,7 +51,7 @@ struct nft_payload {
+       enum nft_payload_bases  base:8;
+       u8                      offset;
+       u8                      len;
+-      enum nft_registers      dreg:8;
++      u8                      dreg;
+ };
+ struct nft_payload_set {
+diff --git a/include/net/netfilter/nft_fib.h b/include/net/netfilter/nft_fib.h
+index 628b6fa579cd8..237f3757637e1 100644
+--- a/include/net/netfilter/nft_fib.h
++++ b/include/net/netfilter/nft_fib.h
+@@ -5,7 +5,7 @@
+ #include <net/netfilter/nf_tables.h>
+ struct nft_fib {
+-      enum nft_registers      dreg:8;
++      u8                      dreg;
+       u8                      result;
+       u32                     flags;
+ };
+diff --git a/include/net/netfilter/nft_meta.h b/include/net/netfilter/nft_meta.h
+index 946fa8c83798e..2dce55c736f40 100644
+--- a/include/net/netfilter/nft_meta.h
++++ b/include/net/netfilter/nft_meta.h
+@@ -7,7 +7,7 @@
+ struct nft_meta {
+       enum nft_meta_keys      key:8;
+       union {
+-              enum nft_registers      dreg:8;
++              u8              dreg;
+               u8              sreg;
+       };
+ };
+diff --git a/net/bridge/netfilter/nft_meta_bridge.c b/net/bridge/netfilter/nft_meta_bridge.c
+index 7c9e92b2f806c..0c28fa4647b73 100644
+--- a/net/bridge/netfilter/nft_meta_bridge.c
++++ b/net/bridge/netfilter/nft_meta_bridge.c
+@@ -87,9 +87,8 @@ static int nft_meta_bridge_get_init(const struct nft_ctx *ctx,
+               return nft_meta_get_init(ctx, expr, tb);
+       }
+-      priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
+-      return nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                         NFT_DATA_VALUE, len);
++      return nft_parse_register_store(ctx, tb[NFTA_META_DREG], &priv->dreg,
++                                      NULL, NFT_DATA_VALUE, len);
+ }
+ static struct nft_expr_type nft_meta_bridge_type;
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 26390fb986215..0ccbe8751085a 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -3839,6 +3839,12 @@ static int nf_tables_delset(struct net *net, struct sock *nlsk,
+       return nft_delset(&ctx, set);
+ }
++static int nft_validate_register_store(const struct nft_ctx *ctx,
++                                     enum nft_registers reg,
++                                     const struct nft_data *data,
++                                     enum nft_data_types type,
++                                     unsigned int len);
++
+ static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
+                                       struct nft_set *set,
+                                       const struct nft_set_iter *iter,
+@@ -7473,10 +7479,11 @@ EXPORT_SYMBOL_GPL(nft_parse_register_load);
+  *    A value of NULL for the data means that its runtime gathered
+  *    data.
+  */
+-int nft_validate_register_store(const struct nft_ctx *ctx,
+-                              enum nft_registers reg,
+-                              const struct nft_data *data,
+-                              enum nft_data_types type, unsigned int len)
++static int nft_validate_register_store(const struct nft_ctx *ctx,
++                                     enum nft_registers reg,
++                                     const struct nft_data *data,
++                                     enum nft_data_types type,
++                                     unsigned int len)
+ {
+       int err;
+@@ -7508,7 +7515,24 @@ int nft_validate_register_store(const struct nft_ctx *ctx,
+               return 0;
+       }
+ }
+-EXPORT_SYMBOL_GPL(nft_validate_register_store);
++
++int nft_parse_register_store(const struct nft_ctx *ctx,
++                           const struct nlattr *attr, u8 *dreg,
++                           const struct nft_data *data,
++                           enum nft_data_types type, unsigned int len)
++{
++      int err;
++      u32 reg;
++
++      reg = nft_parse_register(attr);
++      err = nft_validate_register_store(ctx, reg, data, type, len);
++      if (err < 0)
++              return err;
++
++      *dreg = reg;
++      return 0;
++}
++EXPORT_SYMBOL_GPL(nft_parse_register_store);
+ static const struct nla_policy nft_verdict_policy[NFTA_VERDICT_MAX + 1] = {
+       [NFTA_VERDICT_CODE]     = { .type = NLA_U32 },
+diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
+index 850c6b5713b43..ccab2e66d754b 100644
+--- a/net/netfilter/nft_bitwise.c
++++ b/net/netfilter/nft_bitwise.c
+@@ -17,7 +17,7 @@
+ struct nft_bitwise {
+       u8                      sreg;
+-      enum nft_registers      dreg:8;
++      u8                      dreg;
+       u8                      len;
+       struct nft_data         mask;
+       struct nft_data         xor;
+@@ -70,9 +70,9 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
+       if (err < 0)
+               return err;
+-      priv->dreg = nft_parse_register(tb[NFTA_BITWISE_DREG]);
+-      err = nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                        NFT_DATA_VALUE, priv->len);
++      err = nft_parse_register_store(ctx, tb[NFTA_BITWISE_DREG],
++                                     &priv->dreg, NULL, NFT_DATA_VALUE,
++                                     priv->len);
+       if (err < 0)
+               return err;
+diff --git a/net/netfilter/nft_byteorder.c b/net/netfilter/nft_byteorder.c
+index 0960563cd5a19..9d5947ab8d4ef 100644
+--- a/net/netfilter/nft_byteorder.c
++++ b/net/netfilter/nft_byteorder.c
+@@ -17,7 +17,7 @@
+ struct nft_byteorder {
+       u8                      sreg;
+-      enum nft_registers      dreg:8;
++      u8                      dreg;
+       enum nft_byteorder_ops  op:8;
+       u8                      len;
+       u8                      size;
+@@ -142,9 +142,9 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
+       if (err < 0)
+               return err;
+-      priv->dreg = nft_parse_register(tb[NFTA_BYTEORDER_DREG]);
+-      return nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                         NFT_DATA_VALUE, priv->len);
++      return nft_parse_register_store(ctx, tb[NFTA_BYTEORDER_DREG],
++                                      &priv->dreg, NULL, NFT_DATA_VALUE,
++                                      priv->len);
+ }
+ static int nft_byteorder_dump(struct sk_buff *skb, const struct nft_expr *expr)
+diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
+index edc6b8ae06480..7e269f7378cc0 100644
+--- a/net/netfilter/nft_ct.c
++++ b/net/netfilter/nft_ct.c
+@@ -27,7 +27,7 @@ struct nft_ct {
+       enum nft_ct_keys        key:8;
+       enum ip_conntrack_dir   dir:8;
+       union {
+-              enum nft_registers      dreg:8;
++              u8              dreg;
+               u8              sreg;
+       };
+ };
+@@ -498,9 +498,8 @@ static int nft_ct_get_init(const struct nft_ctx *ctx,
+               }
+       }
+-      priv->dreg = nft_parse_register(tb[NFTA_CT_DREG]);
+-      err = nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                        NFT_DATA_VALUE, len);
++      err = nft_parse_register_store(ctx, tb[NFTA_CT_DREG], &priv->dreg, NULL,
++                                     NFT_DATA_VALUE, len);
+       if (err < 0)
+               return err;
+diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c
+index f2b36b9c2b53c..670dd146fb2b1 100644
+--- a/net/netfilter/nft_exthdr.c
++++ b/net/netfilter/nft_exthdr.c
+@@ -19,7 +19,7 @@ struct nft_exthdr {
+       u8                      offset;
+       u8                      len;
+       u8                      op;
+-      enum nft_registers      dreg:8;
++      u8                      dreg;
+       u8                      sreg;
+       u8                      flags;
+ };
+@@ -353,12 +353,12 @@ static int nft_exthdr_init(const struct nft_ctx *ctx,
+       priv->type   = nla_get_u8(tb[NFTA_EXTHDR_TYPE]);
+       priv->offset = offset;
+       priv->len    = len;
+-      priv->dreg   = nft_parse_register(tb[NFTA_EXTHDR_DREG]);
+       priv->flags  = flags;
+       priv->op     = op;
+-      return nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                         NFT_DATA_VALUE, priv->len);
++      return nft_parse_register_store(ctx, tb[NFTA_EXTHDR_DREG],
++                                      &priv->dreg, NULL, NFT_DATA_VALUE,
++                                      priv->len);
+ }
+ static int nft_exthdr_tcp_set_init(const struct nft_ctx *ctx,
+diff --git a/net/netfilter/nft_fib.c b/net/netfilter/nft_fib.c
+index cfac0964f48db..d2777aff5943d 100644
+--- a/net/netfilter/nft_fib.c
++++ b/net/netfilter/nft_fib.c
+@@ -86,7 +86,6 @@ int nft_fib_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
+               return -EINVAL;
+       priv->result = ntohl(nla_get_be32(tb[NFTA_FIB_RESULT]));
+-      priv->dreg = nft_parse_register(tb[NFTA_FIB_DREG]);
+       switch (priv->result) {
+       case NFT_FIB_RESULT_OIF:
+@@ -106,8 +105,8 @@ int nft_fib_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
+               return -EINVAL;
+       }
+-      err = nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                        NFT_DATA_VALUE, len);
++      err = nft_parse_register_store(ctx, tb[NFTA_FIB_DREG], &priv->dreg,
++                                     NULL, NFT_DATA_VALUE, len);
+       if (err < 0)
+               return err;
+diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c
+index 3b01ad0a02dfe..2ff6c7759494b 100644
+--- a/net/netfilter/nft_hash.c
++++ b/net/netfilter/nft_hash.c
+@@ -15,7 +15,7 @@
+ struct nft_jhash {
+       u8                      sreg;
+-      enum nft_registers      dreg:8;
++      u8                      dreg;
+       u8                      len;
+       bool                    autogen_seed:1;
+       u32                     modulus;
+@@ -38,7 +38,7 @@ static void nft_jhash_eval(const struct nft_expr *expr,
+ }
+ struct nft_symhash {
+-      enum nft_registers      dreg:8;
++      u8                      dreg;
+       u32                     modulus;
+       u32                     offset;
+ };
+@@ -83,8 +83,6 @@ static int nft_jhash_init(const struct nft_ctx *ctx,
+       if (tb[NFTA_HASH_OFFSET])
+               priv->offset = ntohl(nla_get_be32(tb[NFTA_HASH_OFFSET]));
+-      priv->dreg = nft_parse_register(tb[NFTA_HASH_DREG]);
+-
+       err = nft_parse_u32_check(tb[NFTA_HASH_LEN], U8_MAX, &len);
+       if (err < 0)
+               return err;
+@@ -111,8 +109,8 @@ static int nft_jhash_init(const struct nft_ctx *ctx,
+               get_random_bytes(&priv->seed, sizeof(priv->seed));
+       }
+-      return nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                         NFT_DATA_VALUE, sizeof(u32));
++      return nft_parse_register_store(ctx, tb[NFTA_HASH_DREG], &priv->dreg,
++                                      NULL, NFT_DATA_VALUE, sizeof(u32));
+ }
+ static int nft_symhash_init(const struct nft_ctx *ctx,
+@@ -128,8 +126,6 @@ static int nft_symhash_init(const struct nft_ctx *ctx,
+       if (tb[NFTA_HASH_OFFSET])
+               priv->offset = ntohl(nla_get_be32(tb[NFTA_HASH_OFFSET]));
+-      priv->dreg = nft_parse_register(tb[NFTA_HASH_DREG]);
+-
+       priv->modulus = ntohl(nla_get_be32(tb[NFTA_HASH_MODULUS]));
+       if (priv->modulus < 1)
+               return -ERANGE;
+@@ -137,8 +133,9 @@ static int nft_symhash_init(const struct nft_ctx *ctx,
+       if (priv->offset + priv->modulus - 1 < priv->offset)
+               return -EOVERFLOW;
+-      return nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                         NFT_DATA_VALUE, sizeof(u32));
++      return nft_parse_register_store(ctx, tb[NFTA_HASH_DREG],
++                                      &priv->dreg, NULL, NFT_DATA_VALUE,
++                                      sizeof(u32));
+ }
+ static int nft_jhash_dump(struct sk_buff *skb,
+diff --git a/net/netfilter/nft_immediate.c b/net/netfilter/nft_immediate.c
+index 98a8149be094b..6a95d532eaecc 100644
+--- a/net/netfilter/nft_immediate.c
++++ b/net/netfilter/nft_immediate.c
+@@ -48,9 +48,9 @@ static int nft_immediate_init(const struct nft_ctx *ctx,
+       priv->dlen = desc.len;
+-      priv->dreg = nft_parse_register(tb[NFTA_IMMEDIATE_DREG]);
+-      err = nft_validate_register_store(ctx, priv->dreg, &priv->data,
+-                                        desc.type, desc.len);
++      err = nft_parse_register_store(ctx, tb[NFTA_IMMEDIATE_DREG],
++                                     &priv->dreg, &priv->data, desc.type,
++                                     desc.len);
+       if (err < 0)
+               goto err1;
+diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c
+index 349591dabb36a..e0ffd463a1320 100644
+--- a/net/netfilter/nft_lookup.c
++++ b/net/netfilter/nft_lookup.c
+@@ -18,7 +18,7 @@
+ struct nft_lookup {
+       struct nft_set                  *set;
+       u8                              sreg;
+-      enum nft_registers              dreg:8;
++      u8                              dreg;
+       bool                            invert;
+       struct nft_set_binding          binding;
+ };
+@@ -97,9 +97,9 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
+               if (!(set->flags & NFT_SET_MAP))
+                       return -EINVAL;
+-              priv->dreg = nft_parse_register(tb[NFTA_LOOKUP_DREG]);
+-              err = nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                                set->dtype, set->dlen);
++              err = nft_parse_register_store(ctx, tb[NFTA_LOOKUP_DREG],
++                                             &priv->dreg, NULL, set->dtype,
++                                             set->dlen);
+               if (err < 0)
+                       return err;
+       } else if (set->flags & NFT_SET_MAP)
+diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
+index 28761430d9ee4..ec2798ff822e6 100644
+--- a/net/netfilter/nft_meta.c
++++ b/net/netfilter/nft_meta.c
+@@ -380,9 +380,8 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
+               return -EOPNOTSUPP;
+       }
+-      priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
+-      return nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                         NFT_DATA_VALUE, len);
++      return nft_parse_register_store(ctx, tb[NFTA_META_DREG], &priv->dreg,
++                                      NULL, NFT_DATA_VALUE, len);
+ }
+ EXPORT_SYMBOL_GPL(nft_meta_get_init);
+diff --git a/net/netfilter/nft_numgen.c b/net/netfilter/nft_numgen.c
+index 48edb9d5f0125..7bbca252e7fc5 100644
+--- a/net/netfilter/nft_numgen.c
++++ b/net/netfilter/nft_numgen.c
+@@ -16,7 +16,7 @@
+ static DEFINE_PER_CPU(struct rnd_state, nft_numgen_prandom_state);
+ struct nft_ng_inc {
+-      enum nft_registers      dreg:8;
++      u8                      dreg;
+       u32                     modulus;
+       atomic_t                counter;
+       u32                     offset;
+@@ -66,11 +66,10 @@ static int nft_ng_inc_init(const struct nft_ctx *ctx,
+       if (priv->offset + priv->modulus - 1 < priv->offset)
+               return -EOVERFLOW;
+-      priv->dreg = nft_parse_register(tb[NFTA_NG_DREG]);
+       atomic_set(&priv->counter, priv->modulus - 1);
+-      return nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                         NFT_DATA_VALUE, sizeof(u32));
++      return nft_parse_register_store(ctx, tb[NFTA_NG_DREG], &priv->dreg,
++                                      NULL, NFT_DATA_VALUE, sizeof(u32));
+ }
+ static int nft_ng_dump(struct sk_buff *skb, enum nft_registers dreg,
+@@ -100,7 +99,7 @@ static int nft_ng_inc_dump(struct sk_buff *skb, const struct nft_expr *expr)
+ }
+ struct nft_ng_random {
+-      enum nft_registers      dreg:8;
++      u8                      dreg;
+       u32                     modulus;
+       u32                     offset;
+ };
+@@ -140,10 +139,8 @@ static int nft_ng_random_init(const struct nft_ctx *ctx,
+       prandom_init_once(&nft_numgen_prandom_state);
+-      priv->dreg = nft_parse_register(tb[NFTA_NG_DREG]);
+-
+-      return nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                         NFT_DATA_VALUE, sizeof(u32));
++      return nft_parse_register_store(ctx, tb[NFTA_NG_DREG], &priv->dreg,
++                                      NULL, NFT_DATA_VALUE, sizeof(u32));
+ }
+ static int nft_ng_random_dump(struct sk_buff *skb, const struct nft_expr *expr)
+diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c
+index d966a3aff1d33..b7c2bc01f8a27 100644
+--- a/net/netfilter/nft_osf.c
++++ b/net/netfilter/nft_osf.c
+@@ -6,7 +6,7 @@
+ #include <linux/netfilter/nfnetlink_osf.h>
+ struct nft_osf {
+-      enum nft_registers      dreg:8;
++      u8                      dreg;
+       u8                      ttl;
+       u32                     flags;
+ };
+@@ -83,9 +83,9 @@ static int nft_osf_init(const struct nft_ctx *ctx,
+               priv->flags = flags;
+       }
+-      priv->dreg = nft_parse_register(tb[NFTA_OSF_DREG]);
+-      err = nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                        NFT_DATA_VALUE, NFT_OSF_MAXGENRELEN);
++      err = nft_parse_register_store(ctx, tb[NFTA_OSF_DREG], &priv->dreg,
++                                     NULL, NFT_DATA_VALUE,
++                                     NFT_OSF_MAXGENRELEN);
+       if (err < 0)
+               return err;
+diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
+index ce670c959a99e..54298fcd82f0e 100644
+--- a/net/netfilter/nft_payload.c
++++ b/net/netfilter/nft_payload.c
+@@ -135,10 +135,10 @@ static int nft_payload_init(const struct nft_ctx *ctx,
+       priv->base   = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
+       priv->offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
+       priv->len    = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
+-      priv->dreg   = nft_parse_register(tb[NFTA_PAYLOAD_DREG]);
+-      return nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                         NFT_DATA_VALUE, priv->len);
++      return nft_parse_register_store(ctx, tb[NFTA_PAYLOAD_DREG],
++                                      &priv->dreg, NULL, NFT_DATA_VALUE,
++                                      priv->len);
+ }
+ static int nft_payload_dump(struct sk_buff *skb, const struct nft_expr *expr)
+diff --git a/net/netfilter/nft_rt.c b/net/netfilter/nft_rt.c
+index 7cfcb0e2f7ee1..bcd01a63e38f1 100644
+--- a/net/netfilter/nft_rt.c
++++ b/net/netfilter/nft_rt.c
+@@ -15,7 +15,7 @@
+ struct nft_rt {
+       enum nft_rt_keys        key:8;
+-      enum nft_registers      dreg:8;
++      u8                      dreg;
+ };
+ static u16 get_tcpmss(const struct nft_pktinfo *pkt, const struct dst_entry *skbdst)
+@@ -141,9 +141,8 @@ static int nft_rt_get_init(const struct nft_ctx *ctx,
+               return -EOPNOTSUPP;
+       }
+-      priv->dreg = nft_parse_register(tb[NFTA_RT_DREG]);
+-      return nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                         NFT_DATA_VALUE, len);
++      return nft_parse_register_store(ctx, tb[NFTA_RT_DREG], &priv->dreg,
++                                      NULL, NFT_DATA_VALUE, len);
+ }
+ static int nft_rt_get_dump(struct sk_buff *skb,
+diff --git a/net/netfilter/nft_socket.c b/net/netfilter/nft_socket.c
+index 4026ec38526f6..7e4f7063f4811 100644
+--- a/net/netfilter/nft_socket.c
++++ b/net/netfilter/nft_socket.c
+@@ -10,7 +10,7 @@
+ struct nft_socket {
+       enum nft_socket_keys            key:8;
+       union {
+-              enum nft_registers      dreg:8;
++              u8                      dreg;
+       };
+ };
+@@ -119,9 +119,8 @@ static int nft_socket_init(const struct nft_ctx *ctx,
+               return -EOPNOTSUPP;
+       }
+-      priv->dreg = nft_parse_register(tb[NFTA_SOCKET_DREG]);
+-      return nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                         NFT_DATA_VALUE, len);
++      return nft_parse_register_store(ctx, tb[NFTA_SOCKET_DREG], &priv->dreg,
++                                      NULL, NFT_DATA_VALUE, len);
+ }
+ static int nft_socket_dump(struct sk_buff *skb,
+diff --git a/net/netfilter/nft_tunnel.c b/net/netfilter/nft_tunnel.c
+index 4e850c81ad8d8..b2070f9f98ffa 100644
+--- a/net/netfilter/nft_tunnel.c
++++ b/net/netfilter/nft_tunnel.c
+@@ -14,7 +14,7 @@
+ struct nft_tunnel {
+       enum nft_tunnel_keys    key:8;
+-      enum nft_registers      dreg:8;
++      u8                      dreg;
+       enum nft_tunnel_mode    mode:8;
+ };
+@@ -92,8 +92,6 @@ static int nft_tunnel_get_init(const struct nft_ctx *ctx,
+               return -EOPNOTSUPP;
+       }
+-      priv->dreg = nft_parse_register(tb[NFTA_TUNNEL_DREG]);
+-
+       if (tb[NFTA_TUNNEL_MODE]) {
+               priv->mode = ntohl(nla_get_be32(tb[NFTA_TUNNEL_MODE]));
+               if (priv->mode > NFT_TUNNEL_MODE_MAX)
+@@ -102,8 +100,8 @@ static int nft_tunnel_get_init(const struct nft_ctx *ctx,
+               priv->mode = NFT_TUNNEL_MODE_NONE;
+       }
+-      return nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                         NFT_DATA_VALUE, len);
++      return nft_parse_register_store(ctx, tb[NFTA_TUNNEL_DREG], &priv->dreg,
++                                      NULL, NFT_DATA_VALUE, len);
+ }
+ static int nft_tunnel_get_dump(struct sk_buff *skb,
+diff --git a/net/netfilter/nft_xfrm.c b/net/netfilter/nft_xfrm.c
+index 06d5cabf1d7c4..cbbbc4ecad3ae 100644
+--- a/net/netfilter/nft_xfrm.c
++++ b/net/netfilter/nft_xfrm.c
+@@ -24,7 +24,7 @@ static const struct nla_policy nft_xfrm_policy[NFTA_XFRM_MAX + 1] = {
+ struct nft_xfrm {
+       enum nft_xfrm_keys      key:8;
+-      enum nft_registers      dreg:8;
++      u8                      dreg;
+       u8                      dir;
+       u8                      spnum;
+ };
+@@ -86,9 +86,8 @@ static int nft_xfrm_get_init(const struct nft_ctx *ctx,
+       priv->spnum = spnum;
+-      priv->dreg = nft_parse_register(tb[NFTA_XFRM_DREG]);
+-      return nft_validate_register_store(ctx, priv->dreg, NULL,
+-                                         NFT_DATA_VALUE, len);
++      return nft_parse_register_store(ctx, tb[NFTA_XFRM_DREG], &priv->dreg,
++                                      NULL, NFT_DATA_VALUE, len);
+ }
+ /* Return true if key asks for daddr/saddr and current
+-- 
+2.39.2
+
diff --git a/queue-5.4/netfilter-nftables-statify-nft_parse_register.patch b/queue-5.4/netfilter-nftables-statify-nft_parse_register.patch
new file mode 100644 (file)
index 0000000..ec45b13
--- /dev/null
@@ -0,0 +1,54 @@
+From 01259507f2d300176d93272e2d5c1d379c69e69a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 16:44:29 +0200
+Subject: netfilter: nftables: statify nft_parse_register()
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 08a01c11a5bb3de9b0a9c9b2685867e50eda9910 ]
+
+This function is not used anymore by any extension, statify it.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_tables.h | 1 -
+ net/netfilter/nf_tables_api.c     | 3 +--
+ 2 files changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
+index 446f70132d827..ba5f97f5c490e 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -205,7 +205,6 @@ static inline enum nft_registers nft_type_to_reg(enum nft_data_types type)
+ }
+ int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest);
+-unsigned int nft_parse_register(const struct nlattr *attr);
+ int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int reg);
+ int nft_parse_register_load(const struct nlattr *attr, u8 *sreg, u32 len);
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 0ccbe8751085a..8a0095664e619 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -7393,7 +7393,7 @@ EXPORT_SYMBOL_GPL(nft_parse_u32_check);
+  *    Registers used to be 128 bit wide, these register numbers will be
+  *    mapped to the corresponding 32 bit register numbers.
+  */
+-unsigned int nft_parse_register(const struct nlattr *attr)
++static unsigned int nft_parse_register(const struct nlattr *attr)
+ {
+       unsigned int reg;
+@@ -7405,7 +7405,6 @@ unsigned int nft_parse_register(const struct nlattr *attr)
+               return reg + NFT_REG_SIZE / NFT_REG32_SIZE - NFT_REG32_00;
+       }
+ }
+-EXPORT_SYMBOL_GPL(nft_parse_register);
+ /**
+  *    nft_dump_register - dump a register value to a netlink attribute
+-- 
+2.39.2
+
index f435d2135d2586affda562d18daeb66ef601a805..6e31ca45cd6db4d2f1f5658d0336a639f45b1c4f 100644 (file)
@@ -101,3 +101,12 @@ ceph-force-updating-the-msg-pointer-in-non-split-case.patch
 tpm-tpm_tis-disable-interrupts-for-more-lenovo-devices.patch
 powerpc-64s-radix-fix-soft-dirty-tracking.patch
 nilfs2-fix-use-after-free-bug-of-nilfs_root-in-nilfs_evict_inode.patch
+netfilter-nftables-add-nft_parse_register_load-and-u.patch
+netfilter-nftables-add-nft_parse_register_store-and-.patch
+netfilter-nftables-statify-nft_parse_register.patch
+netfilter-nf_tables-validate-registers-coming-from-u.patch
+netfilter-nf_tables-add-nft_setelem_parse_key.patch
+netfilter-nf_tables-allow-up-to-64-bytes-in-the-set-.patch
+netfilter-nf_tables-stricter-validation-of-element-d.patch
+netfilter-nf_tables-validate-nfta_set_elem_objref-ba.patch
+netfilter-nf_tables-hold-mutex-on-netns-pre_exit-pat.patch