From: Greg Kroah-Hartman Date: Sat, 13 Aug 2022 15:21:57 +0000 (+0200) Subject: 5.19-stable patches X-Git-Tag: v5.15.61~139 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=83c9ff9defad9237438d9768ee25ee80e6029a1e;p=thirdparty%2Fkernel%2Fstable-queue.git 5.19-stable patches added patches: epoll-autoremove-wakers-even-more-aggressively.patch netfilter-nf_tables-disallow-jump-to-implicit-chain-from-set-element.patch netfilter-nf_tables-do-not-allow-chain_id-to-refer-to-another-table.patch netfilter-nf_tables-do-not-allow-rule_id-to-refer-to-another-chain.patch netfilter-nf_tables-do-not-allow-set_id-to-refer-to-another-table.patch netfilter-nf_tables-fix-null-deref-due-to-zeroed-list-head.patch netfilter-nf_tables-upfront-validation-of-data-via-nft_data_init.patch --- diff --git a/queue-5.19/epoll-autoremove-wakers-even-more-aggressively.patch b/queue-5.19/epoll-autoremove-wakers-even-more-aggressively.patch new file mode 100644 index 00000000000..523effa8f50 --- /dev/null +++ b/queue-5.19/epoll-autoremove-wakers-even-more-aggressively.patch @@ -0,0 +1,90 @@ +From a16ceb13961068f7209e34d7984f8e42d2c06159 Mon Sep 17 00:00:00 2001 +From: Benjamin Segall +Date: Wed, 15 Jun 2022 14:24:23 -0700 +Subject: epoll: autoremove wakers even more aggressively + +From: Benjamin Segall + +commit a16ceb13961068f7209e34d7984f8e42d2c06159 upstream. + +If a process is killed or otherwise exits while having active network +connections and many threads waiting on epoll_wait, the threads will all +be woken immediately, but not removed from ep->wq. Then when network +traffic scans ep->wq in wake_up, every wakeup attempt will fail, and will +not remove the entries from the list. + +This means that the cost of the wakeup attempt is far higher than usual, +does not decrease, and this also competes with the dying threads trying to +actually make progress and remove themselves from the wq. + +Handle this by removing visited epoll wq entries unconditionally, rather +than only when the wakeup succeeds - the structure of ep_poll means that +the only potential loss is the timed_out->eavail heuristic, which now can +race and result in a redundant ep_send_events attempt. (But only when +incoming data and a timeout actually race, not on every timeout) + +Shakeel added: + +: We are seeing this issue in production with real workloads and it has +: caused hard lockups. Particularly network heavy workloads with a lot +: of threads in epoll_wait() can easily trigger this issue if they get +: killed (oom-killed in our case). + +Link: https://lkml.kernel.org/r/xm26fsjotqda.fsf@google.com +Signed-off-by: Ben Segall +Tested-by: Shakeel Butt +Cc: Alexander Viro +Cc: Linus Torvalds +Cc: Shakeel Butt +Cc: Eric Dumazet +Cc: Roman Penyaev +Cc: Jason Baron +Cc: Khazhismel Kumykov +Cc: Heiher +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Greg Kroah-Hartman +--- + fs/eventpoll.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +--- a/fs/eventpoll.c ++++ b/fs/eventpoll.c +@@ -1747,6 +1747,21 @@ static struct timespec64 *ep_timeout_to_ + return to; + } + ++/* ++ * autoremove_wake_function, but remove even on failure to wake up, because we ++ * know that default_wake_function/ttwu will only fail if the thread is already ++ * woken, and in that case the ep_poll loop will remove the entry anyways, not ++ * try to reuse it. ++ */ ++static int ep_autoremove_wake_function(struct wait_queue_entry *wq_entry, ++ unsigned int mode, int sync, void *key) ++{ ++ int ret = default_wake_function(wq_entry, mode, sync, key); ++ ++ list_del_init(&wq_entry->entry); ++ return ret; ++} ++ + /** + * ep_poll - Retrieves ready events, and delivers them to the caller-supplied + * event buffer. +@@ -1828,8 +1843,15 @@ static int ep_poll(struct eventpoll *ep, + * normal wakeup path no need to call __remove_wait_queue() + * explicitly, thus ep->lock is not taken, which halts the + * event delivery. ++ * ++ * In fact, we now use an even more aggressive function that ++ * unconditionally removes, because we don't reuse the wait ++ * entry between loop iterations. This lets us also avoid the ++ * performance issue if a process is killed, causing all of its ++ * threads to wake up without being removed normally. + */ + init_wait(&wait); ++ wait.func = ep_autoremove_wake_function; + + write_lock_irq(&ep->lock); + /* diff --git a/queue-5.19/netfilter-nf_tables-disallow-jump-to-implicit-chain-from-set-element.patch b/queue-5.19/netfilter-nf_tables-disallow-jump-to-implicit-chain-from-set-element.patch new file mode 100644 index 00000000000..974a03a5518 --- /dev/null +++ b/queue-5.19/netfilter-nf_tables-disallow-jump-to-implicit-chain-from-set-element.patch @@ -0,0 +1,61 @@ +From f323ef3a0d49e147365284bc1f02212e617b7f09 Mon Sep 17 00:00:00 2001 +From: Pablo Neira Ayuso +Date: Mon, 8 Aug 2022 19:30:07 +0200 +Subject: netfilter: nf_tables: disallow jump to implicit chain from set element + +From: Pablo Neira Ayuso + +commit f323ef3a0d49e147365284bc1f02212e617b7f09 upstream. + +Extend struct nft_data_desc to add a flag field that specifies +nft_data_init() is being called for set element data. + +Use it to disallow jump to implicit chain from set element, only jump +to chain via immediate expression is allowed. + +Fixes: d0e2c7de92c7 ("netfilter: nf_tables: add NFT_CHAIN_BINDING") +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + include/net/netfilter/nf_tables.h | 5 +++++ + net/netfilter/nf_tables_api.c | 4 ++++ + 2 files changed, 9 insertions(+) + +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -206,10 +206,15 @@ struct nft_ctx { + bool report; + }; + ++enum nft_data_desc_flags { ++ NFT_DATA_DESC_SETELEM = (1 << 0), ++}; ++ + struct nft_data_desc { + enum nft_data_types type; + unsigned int size; + unsigned int len; ++ unsigned int flags; + }; + + int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data, +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -5226,6 +5226,7 @@ static int nft_setelem_parse_data(struct + desc->type = dtype; + desc->size = NFT_DATA_VALUE_MAXLEN; + desc->len = set->dlen; ++ desc->flags = NFT_DATA_DESC_SETELEM; + + return nft_data_init(ctx, data, desc, attr); + } +@@ -9611,6 +9612,9 @@ static int nft_verdict_init(const struct + return PTR_ERR(chain); + if (nft_is_base_chain(chain)) + return -EOPNOTSUPP; ++ if (desc->flags & NFT_DATA_DESC_SETELEM && ++ chain->flags & NFT_CHAIN_BINDING) ++ return -EINVAL; + + chain->use++; + data->verdict.chain = chain; diff --git a/queue-5.19/netfilter-nf_tables-do-not-allow-chain_id-to-refer-to-another-table.patch b/queue-5.19/netfilter-nf_tables-do-not-allow-chain_id-to-refer-to-another-table.patch new file mode 100644 index 00000000000..289a14224ec --- /dev/null +++ b/queue-5.19/netfilter-nf_tables-do-not-allow-chain_id-to-refer-to-another-table.patch @@ -0,0 +1,66 @@ +From 95f466d22364a33d183509629d0879885b4f547e Mon Sep 17 00:00:00 2001 +From: Thadeu Lima de Souza Cascardo +Date: Tue, 9 Aug 2022 14:01:47 -0300 +Subject: netfilter: nf_tables: do not allow CHAIN_ID to refer to another table + +From: Thadeu Lima de Souza Cascardo + +commit 95f466d22364a33d183509629d0879885b4f547e upstream. + +When doing lookups for chains on the same batch by using its ID, a chain +from a different table can be used. If a rule is added to a table but +refers to a chain in a different table, it will be linked to the chain in +table2, but would have expressions referring to objects in table1. + +Then, when table1 is removed, the rule will not be removed as its linked to +a chain in table2. When expressions in the rule are processed or removed, +that will lead to a use-after-free. + +When looking for chains by ID, use the table that was used for the lookup +by name, and only return chains belonging to that same table. + +Fixes: 837830a4b439 ("netfilter: nf_tables: add NFTA_RULE_CHAIN_ID attribute") +Signed-off-by: Thadeu Lima de Souza Cascardo +Cc: +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + net/netfilter/nf_tables_api.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -2472,6 +2472,7 @@ err: + } + + static struct nft_chain *nft_chain_lookup_byid(const struct net *net, ++ const struct nft_table *table, + const struct nlattr *nla) + { + struct nftables_pernet *nft_net = nft_pernet(net); +@@ -2482,6 +2483,7 @@ static struct nft_chain *nft_chain_looku + struct nft_chain *chain = trans->ctx.chain; + + if (trans->msg_type == NFT_MSG_NEWCHAIN && ++ chain->table == table && + id == nft_trans_chain_id(trans)) + return chain; + } +@@ -3417,7 +3419,7 @@ static int nf_tables_newrule(struct sk_b + return -EOPNOTSUPP; + + } else if (nla[NFTA_RULE_CHAIN_ID]) { +- chain = nft_chain_lookup_byid(net, nla[NFTA_RULE_CHAIN_ID]); ++ chain = nft_chain_lookup_byid(net, table, nla[NFTA_RULE_CHAIN_ID]); + if (IS_ERR(chain)) { + NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN_ID]); + return PTR_ERR(chain); +@@ -9607,7 +9609,7 @@ static int nft_verdict_init(const struct + tb[NFTA_VERDICT_CHAIN], + genmask); + } else if (tb[NFTA_VERDICT_CHAIN_ID]) { +- chain = nft_chain_lookup_byid(ctx->net, ++ chain = nft_chain_lookup_byid(ctx->net, ctx->table, + tb[NFTA_VERDICT_CHAIN_ID]); + if (IS_ERR(chain)) + return PTR_ERR(chain); diff --git a/queue-5.19/netfilter-nf_tables-do-not-allow-rule_id-to-refer-to-another-chain.patch b/queue-5.19/netfilter-nf_tables-do-not-allow-rule_id-to-refer-to-another-chain.patch new file mode 100644 index 00000000000..c38734589cc --- /dev/null +++ b/queue-5.19/netfilter-nf_tables-do-not-allow-rule_id-to-refer-to-another-chain.patch @@ -0,0 +1,73 @@ +From 36d5b2913219ac853908b0f1c664345e04313856 Mon Sep 17 00:00:00 2001 +From: Thadeu Lima de Souza Cascardo +Date: Tue, 9 Aug 2022 14:01:48 -0300 +Subject: netfilter: nf_tables: do not allow RULE_ID to refer to another chain + +From: Thadeu Lima de Souza Cascardo + +commit 36d5b2913219ac853908b0f1c664345e04313856 upstream. + +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 +Cc: +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + net/netfilter/nf_tables_api.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -3373,6 +3373,7 @@ static int nft_table_validate(struct net + } + + static struct nft_rule *nft_rule_lookup_byid(const struct net *net, ++ const struct nft_chain *chain, + const struct nlattr *nla); + + #define NFT_RULE_MAXEXPRS 128 +@@ -3461,7 +3462,7 @@ static int nf_tables_newrule(struct sk_b + return PTR_ERR(old_rule); + } + } else if (nla[NFTA_RULE_POSITION_ID]) { +- old_rule = nft_rule_lookup_byid(net, nla[NFTA_RULE_POSITION_ID]); ++ old_rule = nft_rule_lookup_byid(net, chain, nla[NFTA_RULE_POSITION_ID]); + if (IS_ERR(old_rule)) { + NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_POSITION_ID]); + return PTR_ERR(old_rule); +@@ -3606,6 +3607,7 @@ err_release_expr: + } + + static struct nft_rule *nft_rule_lookup_byid(const struct net *net, ++ const struct nft_chain *chain, + const struct nlattr *nla) + { + struct nftables_pernet *nft_net = nft_pernet(net); +@@ -3616,6 +3618,7 @@ static struct nft_rule *nft_rule_lookup_ + 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; + } +@@ -3665,7 +3668,7 @@ static int nf_tables_delrule(struct sk_b + + 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); diff --git a/queue-5.19/netfilter-nf_tables-do-not-allow-set_id-to-refer-to-another-table.patch b/queue-5.19/netfilter-nf_tables-do-not-allow-set_id-to-refer-to-another-table.patch new file mode 100644 index 00000000000..797e01c6a09 --- /dev/null +++ b/queue-5.19/netfilter-nf_tables-do-not-allow-set_id-to-refer-to-another-table.patch @@ -0,0 +1,57 @@ +From 470ee20e069a6d05ae549f7d0ef2bdbcee6a81b2 Mon Sep 17 00:00:00 2001 +From: Thadeu Lima de Souza Cascardo +Date: Tue, 9 Aug 2022 14:01:46 -0300 +Subject: netfilter: nf_tables: do not allow SET_ID to refer to another table + +From: Thadeu Lima de Souza Cascardo + +commit 470ee20e069a6d05ae549f7d0ef2bdbcee6a81b2 upstream. + +When doing lookups for sets on the same batch by using its ID, a set from a +different table can be used. + +Then, when the table is removed, a reference to the set may be kept after +the set is freed, leading to a potential use-after-free. + +When looking for sets by ID, use the table that was used for the lookup by +name, and only return sets belonging to that same table. + +This fixes CVE-2022-2586, also reported as ZDI-CAN-17470. + +Reported-by: Team Orca of Sea Security (@seasecresponse) +Fixes: 958bee14d071 ("netfilter: nf_tables: use new transaction infrastructure to handle sets") +Signed-off-by: Thadeu Lima de Souza Cascardo +Cc: +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + net/netfilter/nf_tables_api.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -3842,6 +3842,7 @@ static struct nft_set *nft_set_lookup_by + } + + static struct nft_set *nft_set_lookup_byid(const struct net *net, ++ const struct nft_table *table, + const struct nlattr *nla, u8 genmask) + { + struct nftables_pernet *nft_net = nft_pernet(net); +@@ -3853,6 +3854,7 @@ static struct nft_set *nft_set_lookup_by + struct nft_set *set = nft_trans_set(trans); + + if (id == nft_trans_set_id(trans) && ++ set->table == table && + nft_active_genmask(set, genmask)) + return set; + } +@@ -3873,7 +3875,7 @@ struct nft_set *nft_set_lookup_global(co + if (!nla_set_id) + return set; + +- set = nft_set_lookup_byid(net, nla_set_id, genmask); ++ set = nft_set_lookup_byid(net, table, nla_set_id, genmask); + } + return set; + } diff --git a/queue-5.19/netfilter-nf_tables-fix-null-deref-due-to-zeroed-list-head.patch b/queue-5.19/netfilter-nf_tables-fix-null-deref-due-to-zeroed-list-head.patch new file mode 100644 index 00000000000..305f6ee42a5 --- /dev/null +++ b/queue-5.19/netfilter-nf_tables-fix-null-deref-due-to-zeroed-list-head.patch @@ -0,0 +1,45 @@ +From 580077855a40741cf511766129702d97ff02f4d9 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Tue, 9 Aug 2022 18:34:02 +0200 +Subject: netfilter: nf_tables: fix null deref due to zeroed list head + +From: Florian Westphal + +commit 580077855a40741cf511766129702d97ff02f4d9 upstream. + +In nf_tables_updtable, if nf_tables_table_enable returns an error, +nft_trans_destroy is called to free the transaction object. + +nft_trans_destroy() calls list_del(), but the transaction was never +placed on a list -- the list head is all zeroes, this results in +a null dereference: + +BUG: KASAN: null-ptr-deref in nft_trans_destroy+0x26/0x59 +Call Trace: + nft_trans_destroy+0x26/0x59 + nf_tables_newtable+0x4bc/0x9bc + [..] + +Its sane to assume that nft_trans_destroy() can be called +on the transaction object returned by nft_trans_alloc(), so +make sure the list head is initialised. + +Fixes: 55dd6f93076b ("netfilter: nf_tables: use new transaction infrastructure to handle table") +Reported-by: mingi cho +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + net/netfilter/nf_tables_api.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -153,6 +153,7 @@ static struct nft_trans *nft_trans_alloc + if (trans == NULL) + return NULL; + ++ INIT_LIST_HEAD(&trans->list); + trans->msg_type = msg_type; + trans->ctx = *ctx; + diff --git a/queue-5.19/netfilter-nf_tables-upfront-validation-of-data-via-nft_data_init.patch b/queue-5.19/netfilter-nf_tables-upfront-validation-of-data-via-nft_data_init.patch new file mode 100644 index 00000000000..8079d489c80 --- /dev/null +++ b/queue-5.19/netfilter-nf_tables-upfront-validation-of-data-via-nft_data_init.patch @@ -0,0 +1,513 @@ +From 341b6941608762d8235f3fd1e45e4d7114ed8c2c Mon Sep 17 00:00:00 2001 +From: Pablo Neira Ayuso +Date: Mon, 8 Aug 2022 19:30:06 +0200 +Subject: netfilter: nf_tables: upfront validation of data via nft_data_init() + +From: Pablo Neira Ayuso + +commit 341b6941608762d8235f3fd1e45e4d7114ed8c2c upstream. + +Instead of parsing the data and then validate that type and length are +correct, pass a description of the expected data so it can be validated +upfront before parsing it to bail out earlier. + +This patch adds a new .size field to specify the maximum size of the +data area. The .len field is optional and it is used as an input/output +field, it provides the specific length of the expected data in the input +path. If then .len field is not specified, then obtained length from the +netlink attribute is stored. This is required by cmp, bitwise, range and +immediate, which provide no netlink attribute that describes the data +length. The immediate expression uses the destination register type to +infer the expected data type. + +Relying on opencoded validation of the expected data might lead to +subtle bugs as described in 7e6bc1f6cabc ("netfilter: nf_tables: +stricter validation of element data"). + +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + include/net/netfilter/nf_tables.h | 4 - + net/netfilter/nf_tables_api.c | 78 +++++++++++++++++++------------------- + net/netfilter/nft_bitwise.c | 66 ++++++++++++++++---------------- + net/netfilter/nft_cmp.c | 44 +++++++++------------ + net/netfilter/nft_immediate.c | 22 +++++++++- + net/netfilter/nft_range.c | 27 +++++-------- + 6 files changed, 126 insertions(+), 115 deletions(-) + +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -208,11 +208,11 @@ struct nft_ctx { + + struct nft_data_desc { + enum nft_data_types type; ++ unsigned int size; + unsigned int len; + }; + +-int nft_data_init(const struct nft_ctx *ctx, +- struct nft_data *data, unsigned int size, ++int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data, + struct nft_data_desc *desc, const struct nlattr *nla); + void nft_data_hold(const struct nft_data *data, enum nft_data_types type); + void nft_data_release(const struct nft_data *data, enum nft_data_types type); +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -5202,19 +5202,13 @@ static int nft_setelem_parse_flags(const + 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; +- } ++ struct nft_data_desc desc = { ++ .type = NFT_DATA_VALUE, ++ .size = NFT_DATA_VALUE_MAXLEN, ++ .len = set->klen, ++ }; + +- return 0; ++ return nft_data_init(ctx, key, &desc, attr); + } + + static int nft_setelem_parse_data(struct nft_ctx *ctx, struct nft_set *set, +@@ -5223,24 +5217,17 @@ static int nft_setelem_parse_data(struct + 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 (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; +- } ++ desc->type = dtype; ++ desc->size = NFT_DATA_VALUE_MAXLEN; ++ desc->len = set->dlen; + +- return 0; ++ return nft_data_init(ctx, data, desc, attr); + } + + static void *nft_setelem_catchall_get(const struct net *net, +@@ -9631,7 +9618,7 @@ static int nft_verdict_init(const struct + } + + desc->len = sizeof(data->verdict); +- desc->type = NFT_DATA_VERDICT; ++ + return 0; + } + +@@ -9684,20 +9671,25 @@ nla_put_failure: + } + + static int nft_value_init(const struct nft_ctx *ctx, +- struct nft_data *data, unsigned int size, +- struct nft_data_desc *desc, const struct nlattr *nla) ++ struct nft_data *data, struct nft_data_desc *desc, ++ const struct nlattr *nla) + { + unsigned int len; + + len = nla_len(nla); + if (len == 0) + return -EINVAL; +- if (len > size) ++ if (len > desc->size) + return -EOVERFLOW; ++ if (desc->len) { ++ if (len != desc->len) ++ return -EINVAL; ++ } else { ++ desc->len = len; ++ } + + nla_memcpy(data->data, nla, len); +- desc->type = NFT_DATA_VALUE; +- desc->len = len; ++ + return 0; + } + +@@ -9717,7 +9709,6 @@ static const struct nla_policy nft_data_ + * + * @ctx: context of the expression using the data + * @data: destination struct nft_data +- * @size: maximum data length + * @desc: data description + * @nla: netlink attribute containing data + * +@@ -9727,24 +9718,35 @@ static const struct nla_policy nft_data_ + * The caller can indicate that it only wants to accept data of type + * NFT_DATA_VALUE by passing NULL for the ctx argument. + */ +-int nft_data_init(const struct nft_ctx *ctx, +- struct nft_data *data, unsigned int size, ++int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data, + struct nft_data_desc *desc, const struct nlattr *nla) + { + struct nlattr *tb[NFTA_DATA_MAX + 1]; + int err; + ++ if (WARN_ON_ONCE(!desc->size)) ++ return -EINVAL; ++ + err = nla_parse_nested_deprecated(tb, NFTA_DATA_MAX, nla, + nft_data_policy, NULL); + if (err < 0) + return err; + +- if (tb[NFTA_DATA_VALUE]) +- return nft_value_init(ctx, data, size, desc, +- tb[NFTA_DATA_VALUE]); +- if (tb[NFTA_DATA_VERDICT] && ctx != NULL) +- return nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]); +- return -EINVAL; ++ if (tb[NFTA_DATA_VALUE]) { ++ if (desc->type != NFT_DATA_VALUE) ++ return -EINVAL; ++ ++ err = nft_value_init(ctx, data, desc, tb[NFTA_DATA_VALUE]); ++ } else if (tb[NFTA_DATA_VERDICT] && ctx != NULL) { ++ if (desc->type != NFT_DATA_VERDICT) ++ return -EINVAL; ++ ++ err = nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]); ++ } else { ++ err = -EINVAL; ++ } ++ ++ return err; + } + EXPORT_SYMBOL_GPL(nft_data_init); + +--- a/net/netfilter/nft_bitwise.c ++++ b/net/netfilter/nft_bitwise.c +@@ -93,7 +93,16 @@ static const struct nla_policy nft_bitwi + static int nft_bitwise_init_bool(struct nft_bitwise *priv, + const struct nlattr *const tb[]) + { +- struct nft_data_desc mask, xor; ++ struct nft_data_desc mask = { ++ .type = NFT_DATA_VALUE, ++ .size = sizeof(priv->mask), ++ .len = priv->len, ++ }; ++ struct nft_data_desc xor = { ++ .type = NFT_DATA_VALUE, ++ .size = sizeof(priv->xor), ++ .len = priv->len, ++ }; + int err; + + if (tb[NFTA_BITWISE_DATA]) +@@ -103,37 +112,30 @@ static int nft_bitwise_init_bool(struct + !tb[NFTA_BITWISE_XOR]) + return -EINVAL; + +- err = nft_data_init(NULL, &priv->mask, sizeof(priv->mask), &mask, +- tb[NFTA_BITWISE_MASK]); ++ err = nft_data_init(NULL, &priv->mask, &mask, tb[NFTA_BITWISE_MASK]); + if (err < 0) + return err; +- if (mask.type != NFT_DATA_VALUE || mask.len != priv->len) { +- err = -EINVAL; +- goto err_mask_release; +- } + +- err = nft_data_init(NULL, &priv->xor, sizeof(priv->xor), &xor, +- tb[NFTA_BITWISE_XOR]); ++ err = nft_data_init(NULL, &priv->xor, &xor, tb[NFTA_BITWISE_XOR]); + if (err < 0) +- goto err_mask_release; +- if (xor.type != NFT_DATA_VALUE || xor.len != priv->len) { +- err = -EINVAL; +- goto err_xor_release; +- } ++ goto err_xor_err; + + return 0; + +-err_xor_release: +- nft_data_release(&priv->xor, xor.type); +-err_mask_release: ++err_xor_err: + nft_data_release(&priv->mask, mask.type); ++ + return err; + } + + static int nft_bitwise_init_shift(struct nft_bitwise *priv, + const struct nlattr *const tb[]) + { +- struct nft_data_desc d; ++ struct nft_data_desc desc = { ++ .type = NFT_DATA_VALUE, ++ .size = sizeof(priv->data), ++ .len = sizeof(u32), ++ }; + int err; + + if (tb[NFTA_BITWISE_MASK] || +@@ -143,13 +145,12 @@ static int nft_bitwise_init_shift(struct + if (!tb[NFTA_BITWISE_DATA]) + return -EINVAL; + +- err = nft_data_init(NULL, &priv->data, sizeof(priv->data), &d, +- tb[NFTA_BITWISE_DATA]); ++ err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_BITWISE_DATA]); + if (err < 0) + return err; +- if (d.type != NFT_DATA_VALUE || d.len != sizeof(u32) || +- priv->data.data[0] >= BITS_PER_TYPE(u32)) { +- nft_data_release(&priv->data, d.type); ++ ++ if (priv->data.data[0] >= BITS_PER_TYPE(u32)) { ++ nft_data_release(&priv->data, desc.type); + return -EINVAL; + } + +@@ -339,22 +340,21 @@ static const struct nft_expr_ops nft_bit + static int + nft_bitwise_extract_u32_data(const struct nlattr * const tb, u32 *out) + { +- struct nft_data_desc desc; + struct nft_data data; +- int err = 0; ++ struct nft_data_desc desc = { ++ .type = NFT_DATA_VALUE, ++ .size = sizeof(data), ++ .len = sizeof(u32), ++ }; ++ int err; + +- err = nft_data_init(NULL, &data, sizeof(data), &desc, tb); ++ err = nft_data_init(NULL, &data, &desc, tb); + if (err < 0) + return err; + +- if (desc.type != NFT_DATA_VALUE || desc.len != sizeof(u32)) { +- err = -EINVAL; +- goto err; +- } + *out = data.data[0]; +-err: +- nft_data_release(&data, desc.type); +- return err; ++ ++ return 0; + } + + static int nft_bitwise_fast_init(const struct nft_ctx *ctx, +--- a/net/netfilter/nft_cmp.c ++++ b/net/netfilter/nft_cmp.c +@@ -73,20 +73,16 @@ static int nft_cmp_init(const struct nft + const struct nlattr * const tb[]) + { + struct nft_cmp_expr *priv = nft_expr_priv(expr); +- struct nft_data_desc desc; ++ struct nft_data_desc desc = { ++ .type = NFT_DATA_VALUE, ++ .size = sizeof(priv->data), ++ }; + int err; + +- err = nft_data_init(NULL, &priv->data, sizeof(priv->data), &desc, +- tb[NFTA_CMP_DATA]); ++ err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]); + if (err < 0) + return err; + +- if (desc.type != NFT_DATA_VALUE) { +- err = -EINVAL; +- nft_data_release(&priv->data, desc.type); +- return err; +- } +- + err = nft_parse_register_load(tb[NFTA_CMP_SREG], &priv->sreg, desc.len); + if (err < 0) + return err; +@@ -202,12 +198,14 @@ static int nft_cmp_fast_init(const struc + const struct nlattr * const tb[]) + { + struct nft_cmp_fast_expr *priv = nft_expr_priv(expr); +- struct nft_data_desc desc; + struct nft_data data; ++ struct nft_data_desc desc = { ++ .type = NFT_DATA_VALUE, ++ .size = sizeof(data), ++ }; + int err; + +- err = nft_data_init(NULL, &data, sizeof(data), &desc, +- tb[NFTA_CMP_DATA]); ++ err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]); + if (err < 0) + return err; + +@@ -301,11 +299,13 @@ static int nft_cmp16_fast_init(const str + const struct nlattr * const tb[]) + { + struct nft_cmp16_fast_expr *priv = nft_expr_priv(expr); +- struct nft_data_desc desc; ++ struct nft_data_desc desc = { ++ .type = NFT_DATA_VALUE, ++ .size = sizeof(priv->data), ++ }; + int err; + +- err = nft_data_init(NULL, &priv->data, sizeof(priv->data), &desc, +- tb[NFTA_CMP_DATA]); ++ err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]); + if (err < 0) + return err; + +@@ -368,8 +368,11 @@ const struct nft_expr_ops nft_cmp16_fast + static const struct nft_expr_ops * + nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[]) + { +- struct nft_data_desc desc; + struct nft_data data; ++ struct nft_data_desc desc = { ++ .type = NFT_DATA_VALUE, ++ .size = sizeof(data), ++ }; + enum nft_cmp_ops op; + u8 sreg; + int err; +@@ -392,14 +395,10 @@ nft_cmp_select_ops(const struct nft_ctx + return ERR_PTR(-EINVAL); + } + +- err = nft_data_init(NULL, &data, sizeof(data), &desc, +- tb[NFTA_CMP_DATA]); ++ err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]); + if (err < 0) + return ERR_PTR(err); + +- if (desc.type != NFT_DATA_VALUE) +- goto err1; +- + sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG])); + + if (op == NFT_CMP_EQ || op == NFT_CMP_NEQ) { +@@ -411,9 +410,6 @@ nft_cmp_select_ops(const struct nft_ctx + return &nft_cmp16_fast_ops; + } + return &nft_cmp_ops; +-err1: +- nft_data_release(&data, desc.type); +- return ERR_PTR(-EINVAL); + } + + struct nft_expr_type nft_cmp_type __read_mostly = { +--- a/net/netfilter/nft_immediate.c ++++ b/net/netfilter/nft_immediate.c +@@ -29,20 +29,36 @@ static const struct nla_policy nft_immed + [NFTA_IMMEDIATE_DATA] = { .type = NLA_NESTED }, + }; + ++static enum nft_data_types nft_reg_to_type(const struct nlattr *nla) ++{ ++ enum nft_data_types type; ++ u8 reg; ++ ++ reg = ntohl(nla_get_be32(nla)); ++ if (reg == NFT_REG_VERDICT) ++ type = NFT_DATA_VERDICT; ++ else ++ type = NFT_DATA_VALUE; ++ ++ return type; ++} ++ + static int nft_immediate_init(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nlattr * const tb[]) + { + struct nft_immediate_expr *priv = nft_expr_priv(expr); +- struct nft_data_desc desc; ++ struct nft_data_desc desc = { ++ .size = sizeof(priv->data), ++ }; + int err; + + if (tb[NFTA_IMMEDIATE_DREG] == NULL || + tb[NFTA_IMMEDIATE_DATA] == NULL) + return -EINVAL; + +- err = nft_data_init(ctx, &priv->data, sizeof(priv->data), &desc, +- tb[NFTA_IMMEDIATE_DATA]); ++ desc.type = nft_reg_to_type(tb[NFTA_IMMEDIATE_DREG]); ++ err = nft_data_init(ctx, &priv->data, &desc, tb[NFTA_IMMEDIATE_DATA]); + if (err < 0) + return err; + +--- a/net/netfilter/nft_range.c ++++ b/net/netfilter/nft_range.c +@@ -51,7 +51,14 @@ static int nft_range_init(const struct n + const struct nlattr * const tb[]) + { + struct nft_range_expr *priv = nft_expr_priv(expr); +- struct nft_data_desc desc_from, desc_to; ++ struct nft_data_desc desc_from = { ++ .type = NFT_DATA_VALUE, ++ .size = sizeof(priv->data_from), ++ }; ++ struct nft_data_desc desc_to = { ++ .type = NFT_DATA_VALUE, ++ .size = sizeof(priv->data_to), ++ }; + int err; + u32 op; + +@@ -61,26 +68,16 @@ static int nft_range_init(const struct n + !tb[NFTA_RANGE_TO_DATA]) + return -EINVAL; + +- err = nft_data_init(NULL, &priv->data_from, sizeof(priv->data_from), +- &desc_from, tb[NFTA_RANGE_FROM_DATA]); ++ err = nft_data_init(NULL, &priv->data_from, &desc_from, ++ tb[NFTA_RANGE_FROM_DATA]); + if (err < 0) + return err; + +- if (desc_from.type != NFT_DATA_VALUE) { +- err = -EINVAL; +- goto err1; +- } +- +- err = nft_data_init(NULL, &priv->data_to, sizeof(priv->data_to), +- &desc_to, tb[NFTA_RANGE_TO_DATA]); ++ err = nft_data_init(NULL, &priv->data_to, &desc_to, ++ tb[NFTA_RANGE_TO_DATA]); + if (err < 0) + goto err1; + +- if (desc_to.type != NFT_DATA_VALUE) { +- err = -EINVAL; +- goto err2; +- } +- + if (desc_from.len != desc_to.len) { + err = -EINVAL; + goto err2; diff --git a/queue-5.19/series b/queue-5.19/series index ff5d6324942..5fde6c15da6 100644 --- a/queue-5.19/series +++ b/queue-5.19/series @@ -137,3 +137,10 @@ arm64-dts-uniphier-fix-usb-interrupts-for-pxs3-soc.patch usb-gadget-fix-use-after-free-read-in-usb_udc_uevent.patch usb-dwc3-gadget-refactor-dwc3_repare_one_trb.patch usb-dwc3-gadget-fix-high-speed-multiplier-setting.patch +netfilter-nf_tables-do-not-allow-set_id-to-refer-to-another-table.patch +netfilter-nf_tables-do-not-allow-chain_id-to-refer-to-another-table.patch +netfilter-nf_tables-do-not-allow-rule_id-to-refer-to-another-chain.patch +netfilter-nf_tables-upfront-validation-of-data-via-nft_data_init.patch +netfilter-nf_tables-disallow-jump-to-implicit-chain-from-set-element.patch +netfilter-nf_tables-fix-null-deref-due-to-zeroed-list-head.patch +epoll-autoremove-wakers-even-more-aggressively.patch