--- /dev/null
+From f94534f5e7ea596eb8bd571c5bf68ac19d7b6049 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 17:06:09 +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 48f8d3d2b6d7c..acd0566a35860 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -4140,11 +4140,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;
+@@ -4163,17 +4180,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);
+@@ -4364,13 +4375,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;
+@@ -4425,15 +4436,12 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
+ timeout = set->timeout;
+ }
+
+- 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)
+@@ -4455,13 +4463,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);
+@@ -4478,18 +4486,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
+@@ -4572,9 +4580,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;
+ }
+@@ -4670,7 +4678,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;
+@@ -4681,11 +4688,10 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
+ err = nla_parse_nested(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);
+
+@@ -4695,37 +4701,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,
+ 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;
+@@ -4736,13 +4736,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
+
--- /dev/null
+From 845fb6f66565390250f29ac0d65e0855f6a5c760 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 17:06:10 +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 | 39 +++++++++++++++++++++----------
+ 2 files changed, 31 insertions(+), 12 deletions(-)
+
+diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
+index 2cd847212a048..1b4f47a878060 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -225,6 +225,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 acd0566a35860..c1cbcfb58b476 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -4158,6 +4158,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)
+ {
+@@ -4382,7 +4401,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;
+@@ -4463,15 +4481,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 = {
+@@ -4485,14 +4499,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);
+ }
+@@ -4513,7 +4527,8 @@ 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,
++ elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data,
++ elem.data.val.data,
+ timeout, GFP_KERNEL);
+ if (elem.priv == NULL)
+ goto err3;
+@@ -4580,7 +4595,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
+
--- /dev/null
+From de1a1cdba5dfd25a98b1476e1f544e7331b24854 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 17:06:13 +0200
+Subject: netfilter: nf_tables: do not allow RULE_ID to refer to another chain
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+[ 36d5b2913219ac853908b0f1c664345e04313856 ]
+
+When doing lookups for rules on the same batch by using its ID, a rule from
+a different chain can be used. If a rule is added to a chain but tries to
+be positioned next to a rule from a different chain, it will be linked to
+chain2, but the use counter on chain1 would be the one to be incremented.
+
+When looking for rules by ID, use the chain that was used for the lookup by
+name. The chain used in the context copied to the transaction needs to
+match that same chain. That way, struct nft_rule does not need to get
+enlarged with another member.
+
+Fixes: 1a94e38d254b ("netfilter: nf_tables: add NFTA_RULE_ID attribute")
+Fixes: 75dd48e2e420 ("netfilter: nf_tables: Support RULE_ID reference in new rule")
+Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nf_tables_api.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 5cafa90f9d807..62bc4cd0b7bec 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -2769,6 +2769,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
+ }
+
+ static struct nft_rule *nft_rule_lookup_byid(const struct net *net,
++ const struct nft_chain *chain,
+ const struct nlattr *nla)
+ {
+ u32 id = ntohl(nla_get_be32(nla));
+@@ -2778,6 +2779,7 @@ static struct nft_rule *nft_rule_lookup_byid(const struct net *net,
+ struct nft_rule *rule = nft_trans_rule(trans);
+
+ if (trans->msg_type == NFT_MSG_NEWRULE &&
++ trans->ctx.chain == chain &&
+ id == nft_trans_rule_id(trans))
+ return rule;
+ }
+@@ -2824,7 +2826,7 @@ static int nf_tables_delrule(struct net *net, struct sock *nlsk,
+
+ err = nft_delrule(&ctx, rule);
+ } else if (nla[NFTA_RULE_ID]) {
+- rule = nft_rule_lookup_byid(net, nla[NFTA_RULE_ID]);
++ rule = nft_rule_lookup_byid(net, chain, nla[NFTA_RULE_ID]);
+ if (IS_ERR(rule)) {
+ NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_ID]);
+ return PTR_ERR(rule);
+--
+2.39.2
+
--- /dev/null
+From 59d3ea150fe52ea1089c5f2fb4f1a2ab3e6fbba8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 17:06:11 +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 c1cbcfb58b476..ab1e0f0962a2b 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -4163,13 +4163,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
+
--- /dev/null
+From 5fc53006c93357c0d1ecfda17fd1b983e12d576b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 17:06:12 +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 ab1e0f0962a2b..5cafa90f9d807 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -4440,6 +4440,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] ||
+@@ -4474,10 +4483,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->table, nla[NFTA_SET_ELEM_OBJREF],
+ set->objtype, genmask);
+ if (IS_ERR(obj)) {
+--
+2.39.2
+
--- /dev/null
+From c833032b7cae0331325827ee7978b5798acad5c0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 17:06:08 +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 dacdb1feb2e9a..48f8d3d2b6d7c 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -6978,26 +6978,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;
+ }
+
+ /**
+@@ -7048,7 +7045,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, ®);
++ if (err < 0)
++ return err;
++
+ err = nft_validate_register_load(reg, len);
+ if (err < 0)
+ return err;
+@@ -7117,7 +7117,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, ®);
++ if (err < 0)
++ return err;
++
+ err = nft_validate_register_store(ctx, reg, data, type, len);
+ if (err < 0)
+ return err;
+--
+2.39.2
+
--- /dev/null
+From e08d65023b8039bb1ad6b28e931debb8229569a4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 17:06:05 +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 | 5 ++--
+ include/net/netfilter/nft_masq.h | 4 +--
+ include/net/netfilter/nft_redir.h | 4 +--
+ 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 | 14 ++++-------
+ net/netfilter/nft_meta.c | 5 ++--
+ 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 | 14 ++++-------
+ net/netfilter/nft_tproxy.c | 14 +++++------
+ 26 files changed, 130 insertions(+), 132 deletions(-)
+
+diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
+index 78f5f0426e6b6..e7b1e241f6f6e 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -194,7 +194,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 8da837d2aaf99..c81c12a825de4 100644
+--- a/include/net/netfilter/nf_tables_core.h
++++ b/include/net/netfilter/nf_tables_core.h
+@@ -21,7 +21,8 @@ void nf_tables_core_module_exit(void);
+
+ struct nft_cmp_fast_expr {
+ u32 data;
+- enum nft_registers sreg:8;
++ u32 mask;
++ u8 sreg;
+ u8 len;
+ };
+
+@@ -54,7 +55,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_masq.h b/include/net/netfilter/nft_masq.h
+index e51ab3815797b..e69a8277b70b3 100644
+--- a/include/net/netfilter/nft_masq.h
++++ b/include/net/netfilter/nft_masq.h
+@@ -4,8 +4,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;
+ };
+
+ extern const struct nla_policy nft_masq_policy[];
+diff --git a/include/net/netfilter/nft_redir.h b/include/net/netfilter/nft_redir.h
+index 4a970737c03c8..2b4036c94cb3e 100644
+--- a/include/net/netfilter/nft_redir.h
++++ b/include/net/netfilter/nft_redir.h
+@@ -3,8 +3,8 @@
+ #define _NFT_REDIR_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;
+ };
+
+diff --git a/net/ipv4/netfilter/nft_dup_ipv4.c b/net/ipv4/netfilter/nft_dup_ipv4.c
+index 0af3d8df70dd7..157bca240edce 100644
+--- a/net/ipv4/netfilter/nft_dup_ipv4.c
++++ b/net/ipv4/netfilter/nft_dup_ipv4.c
+@@ -16,8 +16,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,
+@@ -43,16 +43,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 d8b5b60b7d531..d8bb7c85287cb 100644
+--- a/net/ipv6/netfilter/nft_dup_ipv6.c
++++ b/net/ipv6/netfilter/nft_dup_ipv6.c
+@@ -16,8 +16,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,
+@@ -41,16 +41,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 e20bde9cc7b12..3b4cb6a9e85d5 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -7026,7 +7026,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;
+@@ -7037,7 +7037,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 058ee84ea531b..23a8a9d119876 100644
+--- a/net/netfilter/nft_bitwise.c
++++ b/net/netfilter/nft_bitwise.c
+@@ -18,7 +18,7 @@
+ #include <net/netfilter/nf_tables.h>
+
+ struct nft_bitwise {
+- enum nft_registers sreg:8;
++ u8 sreg;
+ enum nft_registers dreg:8;
+ u8 len;
+ struct nft_data mask;
+@@ -68,8 +68,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 13d4e421a6b33..c81d618137ce8 100644
+--- a/net/netfilter/nft_byteorder.c
++++ b/net/netfilter/nft_byteorder.c
+@@ -19,7 +19,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;
+@@ -133,14 +133,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 7007045c08498..36bf64ebc8926 100644
+--- a/net/netfilter/nft_cmp.c
++++ b/net/netfilter/nft_cmp.c
+@@ -19,7 +19,7 @@
+
+ struct nft_cmp_expr {
+ struct nft_data data;
+- enum nft_registers sreg:8;
++ u8 sreg;
+ u8 len;
+ enum nft_cmp_ops op:8;
+ };
+@@ -88,8 +88,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;
+
+@@ -139,8 +138,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 5dd87748afa8a..045e350ba03ea 100644
+--- a/net/netfilter/nft_ct.c
++++ b/net/netfilter/nft_ct.c
+@@ -30,7 +30,7 @@ struct nft_ct {
+ enum ip_conntrack_dir dir:8;
+ union {
+ enum nft_registers dreg:8;
+- enum nft_registers sreg:8;
++ u8 sreg;
+ };
+ };
+
+@@ -581,8 +581,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 2cc1e0ef56e88..e862f916efa09 100644
+--- a/net/netfilter/nft_dup_netdev.c
++++ b/net/netfilter/nft_dup_netdev.c
+@@ -16,7 +16,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,
+@@ -42,8 +42,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 const struct nft_expr_ops nft_dup_netdev_ingress_ops;
+diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
+index ea73130427eb8..c5d42e704f043 100644
+--- a/net/netfilter/nft_dynset.c
++++ b/net/netfilter/nft_dynset.c
+@@ -20,8 +20,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;
+@@ -166,8 +166,8 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
+ tb[NFTA_DYNSET_TIMEOUT])));
+ }
+
+- 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;
+
+@@ -177,8 +177,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 93fee41060192..340520f10b686 100644
+--- a/net/netfilter/nft_exthdr.c
++++ b/net/netfilter/nft_exthdr.c
+@@ -23,7 +23,7 @@ struct nft_exthdr {
+ u8 len;
+ u8 op;
+ enum nft_registers dreg:8;
+- enum nft_registers sreg:8;
++ u8 sreg;
+ u8 flags;
+ };
+
+@@ -308,11 +308,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_dump_common(struct sk_buff *skb, const struct nft_exthdr *priv)
+diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c
+index 10a12e0949299..2efbe78de3b22 100644
+--- a/net/netfilter/nft_fwd_netdev.c
++++ b/net/netfilter/nft_fwd_netdev.c
+@@ -20,7 +20,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,
+@@ -49,8 +49,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 const struct nft_expr_ops nft_fwd_netdev_ingress_ops;
+@@ -69,8 +69,8 @@ static int nft_fwd_netdev_dump(struct sk_buff *skb, 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;
+ };
+
+@@ -148,8 +148,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) {
+@@ -163,11 +161,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 const struct nft_expr_ops nft_fwd_netdev_ingress_ops;
+diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c
+index b8f23f75aea6c..d08a14cfe56b7 100644
+--- a/net/netfilter/nft_hash.c
++++ b/net/netfilter/nft_hash.c
+@@ -18,7 +18,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;
+@@ -136,7 +136,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);
+@@ -147,6 +146,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;
+@@ -161,8 +164,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 cb9e937a5ce02..671f124d56b34 100644
+--- a/net/netfilter/nft_lookup.c
++++ b/net/netfilter/nft_lookup.c
+@@ -20,7 +20,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;
+@@ -76,8 +76,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 9d8655bc1bea6..4ecfebc2fdc4a 100644
+--- a/net/netfilter/nft_masq.c
++++ b/net/netfilter/nft_masq.c
+@@ -53,19 +53,15 @@ 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 297fe7d97c182..7af90ed221113 100644
+--- a/net/netfilter/nft_meta.c
++++ b/net/netfilter/nft_meta.c
+@@ -31,7 +31,7 @@ struct nft_meta {
+ enum nft_meta_keys key:8;
+ union {
+ enum nft_registers dreg:8;
+- enum nft_registers sreg:8;
++ u8 sreg;
+ };
+ };
+
+@@ -448,8 +448,7 @@ static 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 2c3d7ff6f58a7..aa6149cc8c87c 100644
+--- a/net/netfilter/nft_nat.c
++++ b/net/netfilter/nft_nat.c
+@@ -27,10 +27,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;
+@@ -160,18 +160,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 {
+@@ -181,19 +178,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 eff2173db7e4b..615f0fcf711c6 100644
+--- a/net/netfilter/nft_objref.c
++++ b/net/netfilter/nft_objref.c
+@@ -97,7 +97,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;
+ };
+
+@@ -139,8 +139,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 5732b32ab9320..6c5312fecac5c 100644
+--- a/net/netfilter/nft_payload.c
++++ b/net/netfilter/nft_payload.c
+@@ -338,7 +338,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]));
+@@ -369,7 +368,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 98613658d4ac5..de5f1bda9d6f1 100644
+--- a/net/netfilter/nft_queue.c
++++ b/net/netfilter/nft_queue.c
+@@ -22,10 +22,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,
+@@ -114,8 +114,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 2e1d2ec2f52a4..a5f74e5b8184f 100644
+--- a/net/netfilter/nft_range.c
++++ b/net/netfilter/nft_range.c
+@@ -18,7 +18,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;
+ };
+@@ -90,8 +90,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 c64cbe78dee7b..08a05bd1e8178 100644
+--- a/net/netfilter/nft_redir.c
++++ b/net/netfilter/nft_redir.c
+@@ -49,19 +49,15 @@ 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
+
--- /dev/null
+From c663e11f66e0903251869d9b49f11d8710d28dfe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 17:06:06 +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 +-
+ 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 | 7 +++---
+ 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 +++---
+ 19 files changed, 92 insertions(+), 81 deletions(-)
+
+diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
+index e7b1e241f6f6e..bf957156e9b76 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -195,10 +195,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 c81c12a825de4..6a3f76e012be3 100644
+--- a/include/net/netfilter/nf_tables_core.h
++++ b/include/net/netfilter/nf_tables_core.h
+@@ -28,7 +28,7 @@ struct nft_cmp_fast_expr {
+
+ struct nft_immediate_expr {
+ struct nft_data data;
+- enum nft_registers dreg:8;
++ u8 dreg;
+ u8 dlen;
+ };
+
+@@ -48,7 +48,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 a88f92737308d..1f87267395291 100644
+--- a/include/net/netfilter/nft_fib.h
++++ b/include/net/netfilter/nft_fib.h
+@@ -3,7 +3,7 @@
+ #define _NFT_FIB_H_
+
+ struct nft_fib {
+- enum nft_registers dreg:8;
++ u8 dreg;
+ u8 result;
+ u32 flags;
+ };
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 3b4cb6a9e85d5..b86d9c14cbd69 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -3687,6 +3687,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,
+@@ -7067,10 +7073,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;
+
+@@ -7102,7 +7109,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 23a8a9d119876..c1055251ebdeb 100644
+--- a/net/netfilter/nft_bitwise.c
++++ b/net/netfilter/nft_bitwise.c
+@@ -19,7 +19,7 @@
+
+ struct nft_bitwise {
+ u8 sreg;
+- enum nft_registers dreg:8;
++ u8 dreg;
+ u8 len;
+ struct nft_data mask;
+ struct nft_data xor;
+@@ -73,9 +73,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 c81d618137ce8..5e1fbdd7b2846 100644
+--- a/net/netfilter/nft_byteorder.c
++++ b/net/netfilter/nft_byteorder.c
+@@ -20,7 +20,7 @@
+
+ struct nft_byteorder {
+ u8 sreg;
+- enum nft_registers dreg:8;
++ u8 dreg;
+ enum nft_byteorder_ops op:8;
+ u8 len;
+ u8 size;
+@@ -144,9 +144,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 045e350ba03ea..f29f02805bcc0 100644
+--- a/net/netfilter/nft_ct.c
++++ b/net/netfilter/nft_ct.c
+@@ -29,7 +29,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;
+ };
+ };
+@@ -486,9 +486,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 340520f10b686..8d0f14cd7cc3e 100644
+--- a/net/netfilter/nft_exthdr.c
++++ b/net/netfilter/nft_exthdr.c
+@@ -22,7 +22,7 @@ struct nft_exthdr {
+ u8 offset;
+ u8 len;
+ u8 op;
+- enum nft_registers dreg:8;
++ u8 dreg;
+ u8 sreg;
+ u8 flags;
+ };
+@@ -258,12 +258,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 21df8cccea658..ce6891337304d 100644
+--- a/net/netfilter/nft_fib.c
++++ b/net/netfilter/nft_fib.c
+@@ -88,7 +88,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:
+@@ -108,8 +107,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 d08a14cfe56b7..513419aca9c66 100644
+--- a/net/netfilter/nft_hash.c
++++ b/net/netfilter/nft_hash.c
+@@ -19,7 +19,7 @@
+
+ struct nft_jhash {
+ u8 sreg;
+- enum nft_registers dreg:8;
++ u8 dreg;
+ u8 len;
+ bool autogen_seed:1;
+ u32 modulus;
+@@ -65,7 +65,7 @@ static void nft_jhash_map_eval(const struct nft_expr *expr,
+ }
+
+ struct nft_symhash {
+- enum nft_registers dreg:8;
++ u8 dreg;
+ u32 modulus;
+ u32 offset;
+ struct nft_set *map;
+@@ -136,8 +136,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;
+@@ -164,8 +162,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_jhash_map_init(const struct nft_ctx *ctx,
+@@ -195,8 +193,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;
+@@ -204,8 +200,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_symhash_map_init(const struct nft_ctx *ctx,
+diff --git a/net/netfilter/nft_immediate.c b/net/netfilter/nft_immediate.c
+index 3f6d1d2a62818..af4e2a4bce93e 100644
+--- a/net/netfilter/nft_immediate.c
++++ b/net/netfilter/nft_immediate.c
+@@ -50,9 +50,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 671f124d56b34..3c380fb326511 100644
+--- a/net/netfilter/nft_lookup.c
++++ b/net/netfilter/nft_lookup.c
+@@ -21,7 +21,7 @@
+ struct nft_lookup {
+ struct nft_set *set;
+ u8 sreg;
+- enum nft_registers dreg:8;
++ u8 dreg;
+ bool invert;
+ struct nft_set_binding binding;
+ };
+@@ -100,9 +100,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 7af90ed221113..061a29bd30661 100644
+--- a/net/netfilter/nft_meta.c
++++ b/net/netfilter/nft_meta.c
+@@ -30,7 +30,7 @@
+ struct nft_meta {
+ enum nft_meta_keys key:8;
+ union {
+- enum nft_registers dreg:8;
++ u8 dreg;
+ u8 sreg;
+ };
+ };
+@@ -358,9 +358,8 @@ static 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);
+ }
+
+ static int nft_meta_get_validate(const struct nft_ctx *ctx,
+diff --git a/net/netfilter/nft_numgen.c b/net/netfilter/nft_numgen.c
+index 3cc1b3dc3c3cd..8ff82f17ecba9 100644
+--- a/net/netfilter/nft_numgen.c
++++ b/net/netfilter/nft_numgen.c
+@@ -20,7 +20,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;
+@@ -70,11 +70,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,
+@@ -104,7 +103,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;
+ };
+@@ -144,10 +143,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 4fac2d9a4b885..af2ce7a8c5877 100644
+--- a/net/netfilter/nft_osf.c
++++ b/net/netfilter/nft_osf.c
+@@ -5,7 +5,7 @@
+ #include <linux/netfilter/nfnetlink_osf.h>
+
+ struct nft_osf {
+- enum nft_registers dreg:8;
++ u8 dreg;
+ };
+
+ static const struct nla_policy nft_osf_policy[NFTA_OSF_MAX + 1] = {
+@@ -55,9 +55,9 @@ static int nft_osf_init(const struct nft_ctx *ctx,
+ if (!tb[NFTA_OSF_DREG])
+ return -EINVAL;
+
+- 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 6c5312fecac5c..77cfd5182784f 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 76dba9f6b6f62..edce109ef4b01 100644
+--- a/net/netfilter/nft_rt.c
++++ b/net/netfilter/nft_rt.c
+@@ -18,7 +18,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)
+@@ -134,9 +134,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 3fc55c81f16ac..ab69a34210a8d 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;
+ };
+
+ static void nft_tunnel_get_eval(const struct nft_expr *expr,
+@@ -72,10 +72,8 @@ static int nft_tunnel_get_init(const struct nft_ctx *ctx,
+ return -EOPNOTSUPP;
+ }
+
+- priv->dreg = nft_parse_register(tb[NFTA_TUNNEL_DREG]);
+-
+- 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,
+--
+2.39.2
+
--- /dev/null
+From d2723bc54c1a9e00597d17290a9908a24c7ef6ab Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 16 May 2023 17:06:07 +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 bf957156e9b76..2cd847212a048 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -191,7 +191,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 b86d9c14cbd69..dacdb1feb2e9a 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -6987,7 +6987,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;
+
+@@ -6999,7 +6999,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
+
ceph-force-updating-the-msg-pointer-in-non-split-case.patch
tpm-tpm_tis-disable-interrupts-for-more-lenovo-devices.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-do-not-allow-rule_id-to-refer-to.patch