--- /dev/null
+From jszhang@kernel.org Sat Aug 3 13:45:23 2024
+From: Jisheng Zhang <jszhang@kernel.org>
+Date: Sat, 3 Aug 2024 19:30:44 +0800
+Subject: net: stmmac: Enable mac_managed_pm phylink config
+To: stable@kernel.org, Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: netdev@vger.kernel.org, Shenwei Wang <shenwei.wang@nxp.com>, Florian Fainelli <f.fainelli@gmail.com>, "David S . Miller" <davem@davemloft.net>
+Message-ID: <20240803113044.2285-1-jszhang@kernel.org>
+
+From: Shenwei Wang <shenwei.wang@nxp.com>
+
+commit f151c147b3afcf92dedff53f5f0e965414e4fd2c upstream
+
+Enable the mac_managed_pm configuration in the phylink_config
+structure to avoid the kernel warning during system resume.
+
+Fixes: 744d23c71af3 ("net: phy: Warn about incorrect mdio_bus_phy_resume() state")
+Signed-off-by: Shenwei Wang <shenwei.wang@nxp.com>
+Acked-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -1286,6 +1286,8 @@ static int stmmac_phy_setup(struct stmma
+ if (!fwnode)
+ fwnode = dev_fwnode(priv->device);
+
++ priv->phylink_config.mac_managed_pm = true;
++
+ phylink = phylink_create(&priv->phylink_config, fwnode,
+ mode, &stmmac_phylink_mac_ops);
+ if (IS_ERR(phylink))
--- /dev/null
+From stable+bounces-66447-greg=kroah.com@vger.kernel.org Mon Aug 12 12:25:26 2024
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Mon, 12 Aug 2024 12:24:45 +0200
+Subject: netfilter: nf_tables: allow clone callbacks to sleep
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, sashal@kernel.org, stable@vger.kernel.org
+Message-ID: <20240812102446.369777-5-pablo@netfilter.org>
+
+From: Florian Westphal <fw@strlen.de>
+
+commit fa23e0d4b756d25829e124d6b670a4c6bbd4bf7e upstream.
+
+Sven Auhagen reports transaction failures with following error:
+ ./main.nft:13:1-26: Error: Could not process rule: Cannot allocate memory
+ percpu: allocation failed, size=16 align=8 atomic=1, atomic alloc failed, no space left
+
+This points to failing pcpu allocation with GFP_ATOMIC flag.
+However, transactions happen from user context and are allowed to sleep.
+
+One case where we can call into percpu allocator with GFP_ATOMIC is
+nft_counter expression.
+
+Normally this happens from control plane, so this could use GFP_KERNEL
+instead. But one use case, element insertion from packet path,
+needs to use GFP_ATOMIC allocations (nft_dynset expression).
+
+At this time, .clone callbacks always use GFP_ATOMIC for this reason.
+
+Add gfp_t argument to the .clone function and pass GFP_KERNEL or
+GFP_ATOMIC flag depending on context, this allows all clone memory
+allocations to sleep for the normal (transaction) case.
+
+Cc: Sven Auhagen <sven.auhagen@voleatech.de>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/netfilter/nf_tables.h | 4 ++--
+ net/netfilter/nf_tables_api.c | 8 ++++----
+ net/netfilter/nft_connlimit.c | 4 ++--
+ net/netfilter/nft_counter.c | 4 ++--
+ net/netfilter/nft_dynset.c | 2 +-
+ net/netfilter/nft_last.c | 4 ++--
+ net/netfilter/nft_limit.c | 14 ++++++++------
+ net/netfilter/nft_quota.c | 4 ++--
+ 8 files changed, 23 insertions(+), 21 deletions(-)
+
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -374,7 +374,7 @@ static inline void *nft_expr_priv(const
+ return (void *)expr->data;
+ }
+
+-int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src);
++int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src, gfp_t gfp);
+ void nft_expr_destroy(const struct nft_ctx *ctx, struct nft_expr *expr);
+ int nft_expr_dump(struct sk_buff *skb, unsigned int attr,
+ const struct nft_expr *expr);
+@@ -872,7 +872,7 @@ struct nft_expr_ops {
+ struct nft_regs *regs,
+ const struct nft_pktinfo *pkt);
+ int (*clone)(struct nft_expr *dst,
+- const struct nft_expr *src);
++ const struct nft_expr *src, gfp_t gfp);
+ unsigned int size;
+
+ int (*init)(const struct nft_ctx *ctx,
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -3049,7 +3049,7 @@ err_expr_parse:
+ return ERR_PTR(err);
+ }
+
+-int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src)
++int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src, gfp_t gfp)
+ {
+ int err;
+
+@@ -3057,7 +3057,7 @@ int nft_expr_clone(struct nft_expr *dst,
+ return -EINVAL;
+
+ dst->ops = src->ops;
+- err = src->ops->clone(dst, src);
++ err = src->ops->clone(dst, src, gfp);
+ if (err < 0)
+ return err;
+
+@@ -5954,7 +5954,7 @@ int nft_set_elem_expr_clone(const struct
+ if (!expr)
+ goto err_expr;
+
+- err = nft_expr_clone(expr, set->exprs[i]);
++ err = nft_expr_clone(expr, set->exprs[i], GFP_KERNEL_ACCOUNT);
+ if (err < 0) {
+ kfree(expr);
+ goto err_expr;
+@@ -5982,7 +5982,7 @@ static int nft_set_elem_expr_setup(struc
+
+ for (i = 0; i < num_exprs; i++) {
+ expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
+- err = nft_expr_clone(expr, expr_array[i]);
++ err = nft_expr_clone(expr, expr_array[i], GFP_KERNEL_ACCOUNT);
+ if (err < 0)
+ goto err_elem_expr_setup;
+
+--- a/net/netfilter/nft_connlimit.c
++++ b/net/netfilter/nft_connlimit.c
+@@ -209,12 +209,12 @@ static void nft_connlimit_destroy(const
+ nft_connlimit_do_destroy(ctx, priv);
+ }
+
+-static int nft_connlimit_clone(struct nft_expr *dst, const struct nft_expr *src)
++static int nft_connlimit_clone(struct nft_expr *dst, const struct nft_expr *src, gfp_t gfp)
+ {
+ struct nft_connlimit *priv_dst = nft_expr_priv(dst);
+ struct nft_connlimit *priv_src = nft_expr_priv(src);
+
+- priv_dst->list = kmalloc(sizeof(*priv_dst->list), GFP_ATOMIC);
++ priv_dst->list = kmalloc(sizeof(*priv_dst->list), gfp);
+ if (!priv_dst->list)
+ return -ENOMEM;
+
+--- a/net/netfilter/nft_counter.c
++++ b/net/netfilter/nft_counter.c
+@@ -225,7 +225,7 @@ static void nft_counter_destroy(const st
+ nft_counter_do_destroy(priv);
+ }
+
+-static int nft_counter_clone(struct nft_expr *dst, const struct nft_expr *src)
++static int nft_counter_clone(struct nft_expr *dst, const struct nft_expr *src, gfp_t gfp)
+ {
+ struct nft_counter_percpu_priv *priv = nft_expr_priv(src);
+ struct nft_counter_percpu_priv *priv_clone = nft_expr_priv(dst);
+@@ -235,7 +235,7 @@ static int nft_counter_clone(struct nft_
+
+ nft_counter_fetch(priv, &total);
+
+- cpu_stats = alloc_percpu_gfp(struct nft_counter, GFP_ATOMIC);
++ cpu_stats = alloc_percpu_gfp(struct nft_counter, gfp);
+ if (cpu_stats == NULL)
+ return -ENOMEM;
+
+--- a/net/netfilter/nft_dynset.c
++++ b/net/netfilter/nft_dynset.c
+@@ -35,7 +35,7 @@ static int nft_dynset_expr_setup(const s
+
+ for (i = 0; i < priv->num_exprs; i++) {
+ expr = nft_setelem_expr_at(elem_expr, elem_expr->size);
+- if (nft_expr_clone(expr, priv->expr_array[i]) < 0)
++ if (nft_expr_clone(expr, priv->expr_array[i], GFP_ATOMIC) < 0)
+ return -1;
+
+ elem_expr->size += priv->expr_array[i]->ops->size;
+--- a/net/netfilter/nft_last.c
++++ b/net/netfilter/nft_last.c
+@@ -101,12 +101,12 @@ static void nft_last_destroy(const struc
+ kfree(priv->last);
+ }
+
+-static int nft_last_clone(struct nft_expr *dst, const struct nft_expr *src)
++static int nft_last_clone(struct nft_expr *dst, const struct nft_expr *src, gfp_t gfp)
+ {
+ struct nft_last_priv *priv_dst = nft_expr_priv(dst);
+ struct nft_last_priv *priv_src = nft_expr_priv(src);
+
+- priv_dst->last = kzalloc(sizeof(*priv_dst->last), GFP_ATOMIC);
++ priv_dst->last = kzalloc(sizeof(*priv_dst->last), gfp);
+ if (!priv_dst->last)
+ return -ENOMEM;
+
+--- a/net/netfilter/nft_limit.c
++++ b/net/netfilter/nft_limit.c
+@@ -150,7 +150,7 @@ static void nft_limit_destroy(const stru
+ }
+
+ static int nft_limit_clone(struct nft_limit_priv *priv_dst,
+- const struct nft_limit_priv *priv_src)
++ const struct nft_limit_priv *priv_src, gfp_t gfp)
+ {
+ priv_dst->tokens_max = priv_src->tokens_max;
+ priv_dst->rate = priv_src->rate;
+@@ -158,7 +158,7 @@ static int nft_limit_clone(struct nft_li
+ priv_dst->burst = priv_src->burst;
+ priv_dst->invert = priv_src->invert;
+
+- priv_dst->limit = kmalloc(sizeof(*priv_dst->limit), GFP_ATOMIC);
++ priv_dst->limit = kmalloc(sizeof(*priv_dst->limit), gfp);
+ if (!priv_dst->limit)
+ return -ENOMEM;
+
+@@ -222,14 +222,15 @@ static void nft_limit_pkts_destroy(const
+ nft_limit_destroy(ctx, &priv->limit);
+ }
+
+-static int nft_limit_pkts_clone(struct nft_expr *dst, const struct nft_expr *src)
++static int nft_limit_pkts_clone(struct nft_expr *dst, const struct nft_expr *src,
++ gfp_t gfp)
+ {
+ struct nft_limit_priv_pkts *priv_dst = nft_expr_priv(dst);
+ struct nft_limit_priv_pkts *priv_src = nft_expr_priv(src);
+
+ priv_dst->cost = priv_src->cost;
+
+- return nft_limit_clone(&priv_dst->limit, &priv_src->limit);
++ return nft_limit_clone(&priv_dst->limit, &priv_src->limit, gfp);
+ }
+
+ static struct nft_expr_type nft_limit_type;
+@@ -279,12 +280,13 @@ static void nft_limit_bytes_destroy(cons
+ nft_limit_destroy(ctx, priv);
+ }
+
+-static int nft_limit_bytes_clone(struct nft_expr *dst, const struct nft_expr *src)
++static int nft_limit_bytes_clone(struct nft_expr *dst, const struct nft_expr *src,
++ gfp_t gfp)
+ {
+ struct nft_limit_priv *priv_dst = nft_expr_priv(dst);
+ struct nft_limit_priv *priv_src = nft_expr_priv(src);
+
+- return nft_limit_clone(priv_dst, priv_src);
++ return nft_limit_clone(priv_dst, priv_src, gfp);
+ }
+
+ static const struct nft_expr_ops nft_limit_bytes_ops = {
+--- a/net/netfilter/nft_quota.c
++++ b/net/netfilter/nft_quota.c
+@@ -232,7 +232,7 @@ static void nft_quota_destroy(const stru
+ return nft_quota_do_destroy(ctx, priv);
+ }
+
+-static int nft_quota_clone(struct nft_expr *dst, const struct nft_expr *src)
++static int nft_quota_clone(struct nft_expr *dst, const struct nft_expr *src, gfp_t gfp)
+ {
+ struct nft_quota *priv_dst = nft_expr_priv(dst);
+ struct nft_quota *priv_src = nft_expr_priv(src);
+@@ -240,7 +240,7 @@ static int nft_quota_clone(struct nft_ex
+ priv_dst->quota = priv_src->quota;
+ priv_dst->flags = priv_src->flags;
+
+- priv_dst->consumed = kmalloc(sizeof(*priv_dst->consumed), GFP_ATOMIC);
++ priv_dst->consumed = kmalloc(sizeof(*priv_dst->consumed), gfp);
+ if (!priv_dst->consumed)
+ return -ENOMEM;
+
--- /dev/null
+From stable+bounces-66446-greg=kroah.com@vger.kernel.org Mon Aug 12 12:25:23 2024
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Mon, 12 Aug 2024 12:24:44 +0200
+Subject: netfilter: nf_tables: bail out if stateful expression provides no .clone
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, sashal@kernel.org, stable@vger.kernel.org
+Message-ID: <20240812102446.369777-4-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit 3c13725f43dcf43ad8a9bcd6a9f12add19a8f93e upstream.
+
+All existing NFT_EXPR_STATEFUL provide a .clone interface, remove
+fallback to copy content of stateful expression since this is never
+exercised and bail out if .clone interface is not defined.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_tables_api.c | 15 +++++++--------
+ 1 file changed, 7 insertions(+), 8 deletions(-)
+
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -3053,14 +3053,13 @@ int nft_expr_clone(struct nft_expr *dst,
+ {
+ int err;
+
+- if (src->ops->clone) {
+- dst->ops = src->ops;
+- err = src->ops->clone(dst, src);
+- if (err < 0)
+- return err;
+- } else {
+- memcpy(dst, src, src->ops->size);
+- }
++ if (WARN_ON_ONCE(!src->ops->clone))
++ return -EINVAL;
++
++ dst->ops = src->ops;
++ err = src->ops->clone(dst, src);
++ if (err < 0)
++ return err;
+
+ __module_get(src->ops->type->owner);
+
--- /dev/null
+From stable+bounces-66448-greg=kroah.com@vger.kernel.org Mon Aug 12 12:25:29 2024
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Mon, 12 Aug 2024 12:24:46 +0200
+Subject: netfilter: nf_tables: prefer nft_chain_validate
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, sashal@kernel.org, stable@vger.kernel.org
+Message-ID: <20240812102446.369777-6-pablo@netfilter.org>
+
+From: Florian Westphal <fw@strlen.de>
+
+commit cff3bd012a9512ac5ed858d38e6ed65f6391008c upstream.
+
+nft_chain_validate already performs loop detection because a cycle will
+result in a call stack overflow (ctx->level >= NFT_JUMP_STACK_SIZE).
+
+It also follows maps via ->validate callback in nft_lookup, so there
+appears no reason to iterate the maps again.
+
+nf_tables_check_loops() and all its helper functions can be removed.
+This improves ruleset load time significantly, from 23s down to 12s.
+
+This also fixes a crash bug. Old loop detection code can result in
+unbounded recursion:
+
+BUG: TASK stack guard page was hit at ....
+Oops: stack guard page: 0000 [#1] PREEMPT SMP KASAN
+CPU: 4 PID: 1539 Comm: nft Not tainted 6.10.0-rc5+ #1
+[..]
+
+with a suitable ruleset during validation of register stores.
+
+I can't see any actual reason to attempt to check for this from
+nft_validate_register_store(), at this point the transaction is still in
+progress, so we don't have a full picture of the rule graph.
+
+For nf-next it might make sense to either remove it or make this depend
+on table->validate_state in case we could catch an error earlier
+(for improved error reporting to userspace).
+
+Fixes: 20a69341f2d0 ("netfilter: nf_tables: add netlink set API")
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_tables_api.c | 151 +++---------------------------------------
+ 1 file changed, 13 insertions(+), 138 deletions(-)
+
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -3445,6 +3445,15 @@ static void nf_tables_rule_release(const
+ nf_tables_rule_destroy(ctx, rule);
+ }
+
++/** nft_chain_validate - loop detection and hook validation
++ *
++ * @ctx: context containing call depth and base chain
++ * @chain: chain to validate
++ *
++ * Walk through the rules of the given chain and chase all jumps/gotos
++ * and set lookups until either the jump limit is hit or all reachable
++ * chains have been validated.
++ */
+ int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain)
+ {
+ struct nft_expr *expr, *last;
+@@ -3463,6 +3472,9 @@ int nft_chain_validate(const struct nft_
+ if (!expr->ops->validate)
+ continue;
+
++ /* This may call nft_chain_validate() recursively,
++ * callers that do so must increment ctx->level.
++ */
+ err = expr->ops->validate(ctx, expr, &data);
+ if (err < 0)
+ return err;
+@@ -9999,143 +10011,6 @@ int nft_chain_validate_hooks(const struc
+ }
+ EXPORT_SYMBOL_GPL(nft_chain_validate_hooks);
+
+-/*
+- * Loop detection - walk through the ruleset beginning at the destination chain
+- * of a new jump until either the source chain is reached (loop) or all
+- * reachable chains have been traversed.
+- *
+- * The loop check is performed whenever a new jump verdict is added to an
+- * expression or verdict map or a verdict map is bound to a new chain.
+- */
+-
+-static int nf_tables_check_loops(const struct nft_ctx *ctx,
+- const struct nft_chain *chain);
+-
+-static int nft_check_loops(const struct nft_ctx *ctx,
+- const struct nft_set_ext *ext)
+-{
+- const struct nft_data *data;
+- int ret;
+-
+- data = nft_set_ext_data(ext);
+- switch (data->verdict.code) {
+- case NFT_JUMP:
+- case NFT_GOTO:
+- ret = nf_tables_check_loops(ctx, data->verdict.chain);
+- break;
+- default:
+- ret = 0;
+- break;
+- }
+-
+- return ret;
+-}
+-
+-static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
+- struct nft_set *set,
+- const struct nft_set_iter *iter,
+- struct nft_set_elem *elem)
+-{
+- const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
+-
+- if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
+- *nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END)
+- return 0;
+-
+- return nft_check_loops(ctx, ext);
+-}
+-
+-static int nft_set_catchall_loops(const struct nft_ctx *ctx,
+- struct nft_set *set)
+-{
+- u8 genmask = nft_genmask_next(ctx->net);
+- struct nft_set_elem_catchall *catchall;
+- struct nft_set_ext *ext;
+- int ret = 0;
+-
+- list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
+- ext = nft_set_elem_ext(set, catchall->elem);
+- if (!nft_set_elem_active(ext, genmask))
+- continue;
+-
+- ret = nft_check_loops(ctx, ext);
+- if (ret < 0)
+- return ret;
+- }
+-
+- return ret;
+-}
+-
+-static int nf_tables_check_loops(const struct nft_ctx *ctx,
+- const struct nft_chain *chain)
+-{
+- const struct nft_rule *rule;
+- const struct nft_expr *expr, *last;
+- struct nft_set *set;
+- struct nft_set_binding *binding;
+- struct nft_set_iter iter;
+-
+- if (ctx->chain == chain)
+- return -ELOOP;
+-
+- list_for_each_entry(rule, &chain->rules, list) {
+- nft_rule_for_each_expr(expr, last, rule) {
+- struct nft_immediate_expr *priv;
+- const struct nft_data *data;
+- int err;
+-
+- if (strcmp(expr->ops->type->name, "immediate"))
+- continue;
+-
+- priv = nft_expr_priv(expr);
+- if (priv->dreg != NFT_REG_VERDICT)
+- continue;
+-
+- data = &priv->data;
+- switch (data->verdict.code) {
+- case NFT_JUMP:
+- case NFT_GOTO:
+- err = nf_tables_check_loops(ctx,
+- data->verdict.chain);
+- if (err < 0)
+- return err;
+- break;
+- default:
+- break;
+- }
+- }
+- }
+-
+- list_for_each_entry(set, &ctx->table->sets, list) {
+- if (!nft_is_active_next(ctx->net, set))
+- continue;
+- if (!(set->flags & NFT_SET_MAP) ||
+- set->dtype != NFT_DATA_VERDICT)
+- continue;
+-
+- list_for_each_entry(binding, &set->bindings, list) {
+- if (!(binding->flags & NFT_SET_MAP) ||
+- binding->chain != chain)
+- continue;
+-
+- iter.genmask = nft_genmask_next(ctx->net);
+- iter.skip = 0;
+- iter.count = 0;
+- iter.err = 0;
+- iter.fn = nf_tables_loop_check_setelem;
+-
+- set->ops->walk(ctx, set, &iter);
+- if (!iter.err)
+- iter.err = nft_set_catchall_loops(ctx, set);
+-
+- if (iter.err < 0)
+- return iter.err;
+- }
+- }
+-
+- return 0;
+-}
+-
+ /**
+ * nft_parse_u32_check - fetch u32 attribute and check for maximum value
+ *
+@@ -10248,7 +10123,7 @@ static int nft_validate_register_store(c
+ if (data != NULL &&
+ (data->verdict.code == NFT_GOTO ||
+ data->verdict.code == NFT_JUMP)) {
+- err = nf_tables_check_loops(ctx, data->verdict.chain);
++ err = nft_chain_validate(ctx, data->verdict.chain);
+ if (err < 0)
+ return err;
+ }
--- /dev/null
+From stable+bounces-66444-greg=kroah.com@vger.kernel.org Mon Aug 12 12:25:15 2024
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Mon, 12 Aug 2024 12:24:42 +0200
+Subject: netfilter: nf_tables: set element extended ACK reporting support
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, sashal@kernel.org, stable@vger.kernel.org
+Message-ID: <20240812102446.369777-2-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit b53c116642502b0c85ecef78bff4f826a7dd4145 upstream.
+
+Report the element that causes problems via netlink extended ACK for set
+element commands.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_tables_api.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -5769,8 +5769,10 @@ static int nf_tables_getsetelem(struct s
+
+ nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
+ err = nft_get_set_elem(&ctx, set, attr);
+- if (err < 0)
++ if (err < 0) {
++ NL_SET_BAD_ATTR(extack, attr);
+ break;
++ }
+ }
+
+ return err;
+@@ -6589,8 +6591,10 @@ static int nf_tables_newsetelem(struct s
+
+ nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
+ err = nft_add_set_elem(&ctx, set, attr, info->nlh->nlmsg_flags);
+- if (err < 0)
++ if (err < 0) {
++ NL_SET_BAD_ATTR(extack, attr);
+ return err;
++ }
+ }
+
+ if (nft_net->validate_state == NFT_VALIDATE_DO)
+@@ -6866,8 +6870,10 @@ static int nf_tables_delsetelem(struct s
+
+ nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
+ err = nft_del_setelem(&ctx, set, attr);
+- if (err < 0)
++ if (err < 0) {
++ NL_SET_BAD_ATTR(extack, attr);
+ break;
++ }
+ }
+ return err;
+ }
--- /dev/null
+From stable+bounces-66445-greg=kroah.com@vger.kernel.org Mon Aug 12 12:25:20 2024
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Mon, 12 Aug 2024 12:24:43 +0200
+Subject: netfilter: nf_tables: use timestamp to check for set element timeout
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, sashal@kernel.org, stable@vger.kernel.org
+Message-ID: <20240812102446.369777-3-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit 7395dfacfff65e9938ac0889dafa1ab01e987d15 upstream
+
+Add a timestamp field at the beginning of the transaction, store it
+in the nftables per-netns area.
+
+Update set backend .insert, .deactivate and sync gc path to use the
+timestamp, this avoids that an element expires while control plane
+transaction is still unfinished.
+
+.lookup and .update, which are used from packet path, still use the
+current time to check if the element has expired. And .get path and dump
+also since this runs lockless under rcu read size lock. Then, there is
+async gc which also needs to check the current time since it runs
+asynchronously from a workqueue.
+
+Fixes: c3e1b005ed1c ("netfilter: nf_tables: add set element timeout support")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/netfilter/nf_tables.h | 16 ++++++++++++++--
+ net/netfilter/nf_tables_api.c | 4 +++-
+ net/netfilter/nft_set_hash.c | 8 +++++++-
+ net/netfilter/nft_set_pipapo.c | 18 +++++++++++-------
+ net/netfilter/nft_set_rbtree.c | 6 ++++--
+ 5 files changed, 39 insertions(+), 13 deletions(-)
+
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -772,10 +772,16 @@ static inline struct nft_set_elem_expr *
+ return nft_set_ext(ext, NFT_SET_EXT_EXPRESSIONS);
+ }
+
+-static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
++static inline bool __nft_set_elem_expired(const struct nft_set_ext *ext,
++ u64 tstamp)
+ {
+ return nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION) &&
+- time_is_before_eq_jiffies64(*nft_set_ext_expiration(ext));
++ time_after_eq64(tstamp, *nft_set_ext_expiration(ext));
++}
++
++static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
++{
++ return __nft_set_elem_expired(ext, get_jiffies_64());
+ }
+
+ static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
+@@ -1679,6 +1685,7 @@ struct nftables_pernet {
+ struct list_head notify_list;
+ struct mutex commit_mutex;
+ u64 table_handle;
++ u64 tstamp;
+ unsigned int base_seq;
+ u8 validate_state;
+ unsigned int gc_seq;
+@@ -1691,4 +1698,9 @@ static inline struct nftables_pernet *nf
+ return net_generic(net, nf_tables_net_id);
+ }
+
++static inline u64 nft_net_tstamp(const struct net *net)
++{
++ return nft_pernet(net)->tstamp;
++}
++
+ #endif /* _NET_NF_TABLES_H */
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -9185,6 +9185,7 @@ dead_elem:
+ struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc)
+ {
+ struct nft_set_elem_catchall *catchall, *next;
++ u64 tstamp = nft_net_tstamp(gc->net);
+ const struct nft_set *set = gc->set;
+ struct nft_set_elem elem;
+ struct nft_set_ext *ext;
+@@ -9194,7 +9195,7 @@ struct nft_trans_gc *nft_trans_gc_catcha
+ list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
+ ext = nft_set_elem_ext(set, catchall->elem);
+
+- if (!nft_set_elem_expired(ext))
++ if (!__nft_set_elem_expired(ext, tstamp))
+ continue;
+
+ gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL);
+@@ -9946,6 +9947,7 @@ static bool nf_tables_valid_genid(struct
+ bool genid_ok;
+
+ mutex_lock(&nft_net->commit_mutex);
++ nft_net->tstamp = get_jiffies_64();
+
+ genid_ok = genid == 0 || nft_net->base_seq == genid;
+ if (!genid_ok)
+--- a/net/netfilter/nft_set_hash.c
++++ b/net/netfilter/nft_set_hash.c
+@@ -35,6 +35,7 @@ struct nft_rhash_cmp_arg {
+ const struct nft_set *set;
+ const u32 *key;
+ u8 genmask;
++ u64 tstamp;
+ };
+
+ static inline u32 nft_rhash_key(const void *data, u32 len, u32 seed)
+@@ -61,7 +62,7 @@ static inline int nft_rhash_cmp(struct r
+ return 1;
+ if (nft_set_elem_is_dead(&he->ext))
+ return 1;
+- if (nft_set_elem_expired(&he->ext))
++ if (__nft_set_elem_expired(&he->ext, x->tstamp))
+ return 1;
+ if (!nft_set_elem_active(&he->ext, x->genmask))
+ return 1;
+@@ -86,6 +87,7 @@ bool nft_rhash_lookup(const struct net *
+ .genmask = nft_genmask_cur(net),
+ .set = set,
+ .key = key,
++ .tstamp = get_jiffies_64(),
+ };
+
+ he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
+@@ -104,6 +106,7 @@ static void *nft_rhash_get(const struct
+ .genmask = nft_genmask_cur(net),
+ .set = set,
+ .key = elem->key.val.data,
++ .tstamp = get_jiffies_64(),
+ };
+
+ he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
+@@ -127,6 +130,7 @@ static bool nft_rhash_update(struct nft_
+ .genmask = NFT_GENMASK_ANY,
+ .set = set,
+ .key = key,
++ .tstamp = get_jiffies_64(),
+ };
+
+ he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
+@@ -170,6 +174,7 @@ static int nft_rhash_insert(const struct
+ .genmask = nft_genmask_next(net),
+ .set = set,
+ .key = elem->key.val.data,
++ .tstamp = nft_net_tstamp(net),
+ };
+ struct nft_rhash_elem *prev;
+
+@@ -212,6 +217,7 @@ static void *nft_rhash_deactivate(const
+ .genmask = nft_genmask_next(net),
+ .set = set,
+ .key = elem->key.val.data,
++ .tstamp = nft_net_tstamp(net),
+ };
+
+ rcu_read_lock();
+--- a/net/netfilter/nft_set_pipapo.c
++++ b/net/netfilter/nft_set_pipapo.c
+@@ -504,6 +504,7 @@ out:
+ * @set: nftables API set representation
+ * @data: Key data to be matched against existing elements
+ * @genmask: If set, check that element is active in given genmask
++ * @tstamp: timestamp to check for expired elements
+ *
+ * This is essentially the same as the lookup function, except that it matches
+ * key data against the uncommitted copy and doesn't use preallocated maps for
+@@ -513,7 +514,8 @@ out:
+ */
+ static struct nft_pipapo_elem *pipapo_get(const struct net *net,
+ const struct nft_set *set,
+- const u8 *data, u8 genmask)
++ const u8 *data, u8 genmask,
++ u64 tstamp)
+ {
+ struct nft_pipapo_elem *ret = ERR_PTR(-ENOENT);
+ struct nft_pipapo *priv = nft_set_priv(set);
+@@ -568,7 +570,7 @@ next_match:
+ goto out;
+
+ if (last) {
+- if (nft_set_elem_expired(&f->mt[b].e->ext))
++ if (__nft_set_elem_expired(&f->mt[b].e->ext, tstamp))
+ goto next_match;
+ if ((genmask &&
+ !nft_set_elem_active(&f->mt[b].e->ext, genmask)))
+@@ -605,7 +607,7 @@ static void *nft_pipapo_get(const struct
+ const struct nft_set_elem *elem, unsigned int flags)
+ {
+ return pipapo_get(net, set, (const u8 *)elem->key.val.data,
+- nft_genmask_cur(net));
++ nft_genmask_cur(net), get_jiffies_64());
+ }
+
+ /**
+@@ -1199,6 +1201,7 @@ static int nft_pipapo_insert(const struc
+ struct nft_pipapo *priv = nft_set_priv(set);
+ struct nft_pipapo_match *m = priv->clone;
+ u8 genmask = nft_genmask_next(net);
++ u64 tstamp = nft_net_tstamp(net);
+ struct nft_pipapo_field *f;
+ const u8 *start_p, *end_p;
+ int i, bsize_max, err = 0;
+@@ -1208,7 +1211,7 @@ static int nft_pipapo_insert(const struc
+ else
+ end = start;
+
+- dup = pipapo_get(net, set, start, genmask);
++ dup = pipapo_get(net, set, start, genmask, tstamp);
+ if (!IS_ERR(dup)) {
+ /* Check if we already have the same exact entry */
+ const struct nft_data *dup_key, *dup_end;
+@@ -1230,7 +1233,7 @@ static int nft_pipapo_insert(const struc
+
+ if (PTR_ERR(dup) == -ENOENT) {
+ /* Look for partially overlapping entries */
+- dup = pipapo_get(net, set, end, nft_genmask_next(net));
++ dup = pipapo_get(net, set, end, nft_genmask_next(net), tstamp);
+ }
+
+ if (PTR_ERR(dup) != -ENOENT) {
+@@ -1583,6 +1586,7 @@ static void pipapo_gc(const struct nft_s
+ struct nft_set *set = (struct nft_set *) _set;
+ struct nft_pipapo *priv = nft_set_priv(set);
+ struct net *net = read_pnet(&set->net);
++ u64 tstamp = nft_net_tstamp(net);
+ int rules_f0, first_rule = 0;
+ struct nft_pipapo_elem *e;
+ struct nft_trans_gc *gc;
+@@ -1617,7 +1621,7 @@ static void pipapo_gc(const struct nft_s
+ /* synchronous gc never fails, there is no need to set on
+ * NFT_SET_ELEM_DEAD_BIT.
+ */
+- if (nft_set_elem_expired(&e->ext)) {
++ if (__nft_set_elem_expired(&e->ext, tstamp)) {
+ priv->dirty = true;
+
+ gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
+@@ -1788,7 +1792,7 @@ static void *pipapo_deactivate(const str
+ {
+ struct nft_pipapo_elem *e;
+
+- e = pipapo_get(net, set, data, nft_genmask_next(net));
++ e = pipapo_get(net, set, data, nft_genmask_next(net), nft_net_tstamp(net));
+ if (IS_ERR(e))
+ return NULL;
+
+--- a/net/netfilter/nft_set_rbtree.c
++++ b/net/netfilter/nft_set_rbtree.c
+@@ -314,6 +314,7 @@ static int __nft_rbtree_insert(const str
+ struct nft_rbtree *priv = nft_set_priv(set);
+ u8 cur_genmask = nft_genmask_cur(net);
+ u8 genmask = nft_genmask_next(net);
++ u64 tstamp = nft_net_tstamp(net);
+ int d;
+
+ /* Descend the tree to search for an existing element greater than the
+@@ -361,7 +362,7 @@ static int __nft_rbtree_insert(const str
+ /* perform garbage collection to avoid bogus overlap reports
+ * but skip new elements in this transaction.
+ */
+- if (nft_set_elem_expired(&rbe->ext) &&
++ if (__nft_set_elem_expired(&rbe->ext, tstamp) &&
+ nft_set_elem_active(&rbe->ext, cur_genmask)) {
+ const struct nft_rbtree_elem *removed_end;
+
+@@ -548,6 +549,7 @@ static void *nft_rbtree_deactivate(const
+ const struct rb_node *parent = priv->root.rb_node;
+ struct nft_rbtree_elem *rbe, *this = elem->priv;
+ u8 genmask = nft_genmask_next(net);
++ u64 tstamp = nft_net_tstamp(net);
+ int d;
+
+ while (parent != NULL) {
+@@ -568,7 +570,7 @@ static void *nft_rbtree_deactivate(const
+ nft_rbtree_interval_end(this)) {
+ parent = parent->rb_right;
+ continue;
+- } else if (nft_set_elem_expired(&rbe->ext)) {
++ } else if (__nft_set_elem_expired(&rbe->ext, tstamp)) {
+ break;
+ } else if (!nft_set_elem_active(&rbe->ext, genmask)) {
+ parent = parent->rb_left;
--- /dev/null
+From stable+bounces-62765-greg=kroah.com@vger.kernel.org Tue Jul 30 12:59:10 2024
+From: Lukas Wunner <lukas@wunner.de>
+Date: Tue, 30 Jul 2024 12:58:55 +0200
+Subject: PCI/DPC: Fix use-after-free on concurrent DPC and hot-removal
+To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Sasha Levin <sashal@kernel.org>
+Cc: stable@vger.kernel.org, linux-pci@vger.kernel.org, Keith Busch <kbusch@kernel.org>, Mika Westerberg <mika.westerberg@linux.intel.com>, Bjorn Helgaas <helgaas@kernel.org>, Krzysztof Wilczynski <kwilczynski@kernel.org>
+Message-ID: <ecc9e4e0552069fb3cffb46a45e5430d88d71e80.1722337010.git.lukas@wunner.de>
+
+From: Lukas Wunner <lukas@wunner.de>
+
+commit 11a1f4bc47362700fcbde717292158873fb847ed upstream.
+
+Keith reports a use-after-free when a DPC event occurs concurrently to
+hot-removal of the same portion of the hierarchy:
+
+The dpc_handler() awaits readiness of the secondary bus below the
+Downstream Port where the DPC event occurred. To do so, it polls the
+config space of the first child device on the secondary bus. If that
+child device is concurrently removed, accesses to its struct pci_dev
+cause the kernel to oops.
+
+That's because pci_bridge_wait_for_secondary_bus() neglects to hold a
+reference on the child device. Before v6.3, the function was only
+called on resume from system sleep or on runtime resume. Holding a
+reference wasn't necessary back then because the pciehp IRQ thread
+could never run concurrently. (On resume from system sleep, IRQs are
+not enabled until after the resume_noirq phase. And runtime resume is
+always awaited before a PCI device is removed.)
+
+However starting with v6.3, pci_bridge_wait_for_secondary_bus() is also
+called on a DPC event. Commit 53b54ad074de ("PCI/DPC: Await readiness
+of secondary bus after reset"), which introduced that, failed to
+appreciate that pci_bridge_wait_for_secondary_bus() now needs to hold a
+reference on the child device because dpc_handler() and pciehp may
+indeed run concurrently. The commit was backported to v5.10+ stable
+kernels, so that's the oldest one affected.
+
+Add the missing reference acquisition.
+
+Abridged stack trace:
+
+ BUG: unable to handle page fault for address: 00000000091400c0
+ CPU: 15 PID: 2464 Comm: irq/53-pcie-dpc 6.9.0
+ RIP: pci_bus_read_config_dword+0x17/0x50
+ pci_dev_wait()
+ pci_bridge_wait_for_secondary_bus()
+ dpc_reset_link()
+ pcie_do_recovery()
+ dpc_handler()
+
+Fixes: 53b54ad074de ("PCI/DPC: Await readiness of secondary bus after reset")
+Closes: https://lore.kernel.org/r/20240612181625.3604512-3-kbusch@meta.com/
+Link: https://lore.kernel.org/linux-pci/8e4bcd4116fd94f592f2bf2749f168099c480ddf.1718707743.git.lukas@wunner.de
+Reported-by: Keith Busch <kbusch@kernel.org>
+Tested-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Lukas Wunner <lukas@wunner.de>
+Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
+Reviewed-by: Keith Busch <kbusch@kernel.org>
+Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Cc: stable@vger.kernel.org # v5.10+
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/pci.c | 19 ++++++++++++-------
+ 1 file changed, 12 insertions(+), 7 deletions(-)
+
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -4916,7 +4916,7 @@ int pci_bridge_wait_for_secondary_bus(st
+ int timeout)
+ {
+ struct pci_dev *child;
+- int delay;
++ int delay, ret = 0;
+
+ if (pci_dev_is_disconnected(dev))
+ return 0;
+@@ -4944,8 +4944,8 @@ int pci_bridge_wait_for_secondary_bus(st
+ return 0;
+ }
+
+- child = list_first_entry(&dev->subordinate->devices, struct pci_dev,
+- bus_list);
++ child = pci_dev_get(list_first_entry(&dev->subordinate->devices,
++ struct pci_dev, bus_list));
+ up_read(&pci_bus_sem);
+
+ /*
+@@ -4955,7 +4955,7 @@ int pci_bridge_wait_for_secondary_bus(st
+ if (!pci_is_pcie(dev)) {
+ pci_dbg(dev, "waiting %d ms for secondary bus\n", 1000 + delay);
+ msleep(1000 + delay);
+- return 0;
++ goto put_child;
+ }
+
+ /*
+@@ -4976,7 +4976,7 @@ int pci_bridge_wait_for_secondary_bus(st
+ * until the timeout expires.
+ */
+ if (!pcie_downstream_port(dev))
+- return 0;
++ goto put_child;
+
+ if (pcie_get_speed_cap(dev) <= PCIE_SPEED_5_0GT) {
+ pci_dbg(dev, "waiting %d ms for downstream link\n", delay);
+@@ -4987,11 +4987,16 @@ int pci_bridge_wait_for_secondary_bus(st
+ if (!pcie_wait_for_link_delay(dev, true, delay)) {
+ /* Did not train, no need to wait any further */
+ pci_info(dev, "Data Link Layer Link Active not set in 1000 msec\n");
+- return -ENOTTY;
++ ret = -ENOTTY;
++ goto put_child;
+ }
+ }
+
+- return pci_dev_wait(child, reset_type, timeout - delay);
++ ret = pci_dev_wait(child, reset_type, timeout - delay);
++
++put_child:
++ pci_dev_put(child);
++ return ret;
+ }
+
+ void pci_reset_secondary_bus(struct pci_dev *dev)
--- /dev/null
+From jszhang@kernel.org Sat Aug 3 13:43:25 2024
+From: Jisheng Zhang <jszhang@kernel.org>
+Date: Sat, 3 Aug 2024 19:28:52 +0800
+Subject: PCI: dwc: Restore MSI Receiver mask during resume
+To: stable@kernel.org, "Jingoo Han" <jingoohan1@gmail.com>, "Manivannan Sadhasivam" <manivannan.sadhasivam@linaro.org>, "Lorenzo Pieralisi" <lpieralisi@kernel.org>, "Krzysztof Wilczyński" <kw@linux.com>, "Rob Herring" <robh@kernel.org>, "Bjorn Helgaas" <bhelgaas@google.com>, "Greg Kroah-Hartman" <gregkh@linuxfoundation.org>
+Cc: linux-pci@vger.kernel.org, Richard Zhu <hongxing.zhu@nxp.com>, Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Message-ID: <20240803112852.2263-1-jszhang@kernel.org>
+
+From: Jisheng Zhang <jszhang@kernel.org>
+
+commit 815953dc2011ad7a34de355dfa703dcef1085219 upstream
+
+If a host that uses the IP's integrated MSI Receiver lost power
+during suspend, we call dw_pcie_setup_rc() to reinit the RC. But
+dw_pcie_setup_rc() always sets pp->irq_mask[ctrl] to ~0, so the mask
+register is always set as 0xffffffff incorrectly, thus the MSI can't
+work after resume.
+
+Fix this issue by moving pp->irq_mask[ctrl] initialization to
+dw_pcie_host_init() so we can correctly set the mask reg during both
+boot and resume.
+
+Tested-by: Richard Zhu <hongxing.zhu@nxp.com>
+Link: https://lore.kernel.org/r/20211226074019.2556-1-jszhang@kernel.org
+Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/pci/controller/dwc/pcie-designware-host.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/drivers/pci/controller/dwc/pcie-designware-host.c
++++ b/drivers/pci/controller/dwc/pcie-designware-host.c
+@@ -352,6 +352,12 @@ int dw_pcie_host_init(struct pcie_port *
+ if (ret < 0)
+ return ret;
+ } else if (pp->has_msi_ctrl) {
++ u32 ctrl, num_ctrls;
++
++ num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
++ for (ctrl = 0; ctrl < num_ctrls; ctrl++)
++ pp->irq_mask[ctrl] = ~0;
++
+ if (!pp->msi_irq) {
+ pp->msi_irq = platform_get_irq_byname_optional(pdev, "msi");
+ if (pp->msi_irq < 0) {
+@@ -550,7 +556,6 @@ void dw_pcie_setup_rc(struct pcie_port *
+
+ /* Initialize IRQ Status array */
+ for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
+- pp->irq_mask[ctrl] = ~0;
+ dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK +
+ (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
+ pp->irq_mask[ctrl]);
ipv6-fix-source-address-selection-with-route-leak.patch
xfs-fix-log-recovery-buffer-allocation-for-the-legacy-h_size-fixup.patch
btrfs-fix-double-inode-unlock-for-direct-io-sync-writes.patch
+pci-dpc-fix-use-after-free-on-concurrent-dpc-and-hot-removal.patch
+tls-fix-race-between-tx-work-scheduling-and-socket-close.patch
+netfilter-nf_tables-set-element-extended-ack-reporting-support.patch
+netfilter-nf_tables-use-timestamp-to-check-for-set-element-timeout.patch
+netfilter-nf_tables-bail-out-if-stateful-expression-provides-no-.clone.patch
+netfilter-nf_tables-allow-clone-callbacks-to-sleep.patch
+netfilter-nf_tables-prefer-nft_chain_validate.patch
+net-stmmac-enable-mac_managed_pm-phylink-config.patch
+pci-dwc-restore-msi-receiver-mask-during-resume.patch
+wifi-mac80211-check-basic-rates-validity.patch
--- /dev/null
+From e01e3934a1b2d122919f73bc6ddbe1cdafc4bbdb Mon Sep 17 00:00:00 2001
+From: Jakub Kicinski <kuba@kernel.org>
+Date: Tue, 6 Feb 2024 17:18:20 -0800
+Subject: tls: fix race between tx work scheduling and socket close
+
+From: Jakub Kicinski <kuba@kernel.org>
+
+commit e01e3934a1b2d122919f73bc6ddbe1cdafc4bbdb upstream.
+
+Similarly to previous commit, the submitting thread (recvmsg/sendmsg)
+may exit as soon as the async crypto handler calls complete().
+Reorder scheduling the work before calling complete().
+This seems more logical in the first place, as it's
+the inverse order of what the submitting thread will do.
+
+Reported-by: valis <sec@valis.email>
+Fixes: a42055e8d2c3 ("net/tls: Add support for async encryption of records for performance")
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[ Lee: Fixed merge-conflict in Stable branches linux-6.1.y and older ]
+Signed-off-by: Lee Jones <lee@kernel.org>
+[ Harshit: bp to 5.15.y, minor conflict resolutin due to missing commit:
+ 8ae187386420 ("tls: Only use data field in crypto completion function")
+ in 5.15.y]
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/tls/tls_sw.c | 16 ++++++----------
+ 1 file changed, 6 insertions(+), 10 deletions(-)
+
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -468,7 +468,6 @@ static void tls_encrypt_done(struct cryp
+ struct scatterlist *sge;
+ struct sk_msg *msg_en;
+ struct tls_rec *rec;
+- bool ready = false;
+
+ if (err == -EINPROGRESS) /* see the comment in tls_decrypt_done() */
+ return;
+@@ -502,19 +501,16 @@ static void tls_encrypt_done(struct cryp
+ /* If received record is at head of tx_list, schedule tx */
+ first_rec = list_first_entry(&ctx->tx_list,
+ struct tls_rec, list);
+- if (rec == first_rec)
+- ready = true;
++ if (rec == first_rec) {
++ /* Schedule the transmission */
++ if (!test_and_set_bit(BIT_TX_SCHEDULED,
++ &ctx->tx_bitmask))
++ schedule_delayed_work(&ctx->tx_work.work, 1);
++ }
+ }
+
+ if (atomic_dec_and_test(&ctx->encrypt_pending))
+ complete(&ctx->async_wait.completion);
+-
+- if (!ready)
+- return;
+-
+- /* Schedule the transmission */
+- if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask))
+- schedule_delayed_work(&ctx->tx_work.work, 1);
+ }
+
+ static int tls_encrypt_async_wait(struct tls_sw_context_tx *ctx)
--- /dev/null
+From ce04abc3fcc62cd5640af981ebfd7c4dc3bded28 Mon Sep 17 00:00:00 2001
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Fri, 24 Feb 2023 10:52:19 +0100
+Subject: wifi: mac80211: check basic rates validity
+
+From: Johannes Berg <johannes.berg@intel.com>
+
+commit ce04abc3fcc62cd5640af981ebfd7c4dc3bded28 upstream.
+
+When userspace sets basic rates, it might send us some rates
+list that's empty or consists of invalid values only. We're
+currently ignoring invalid values and then may end up with a
+rates bitmap that's empty, which later results in a warning.
+
+Reject the call if there were no valid rates.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Reported-by: syzbot+19013115c9786bfd0c4e@syzkaller.appspotmail.com
+Tested-by: syzbot+19013115c9786bfd0c4e@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=19013115c9786bfd0c4e
+Signed-off-by: Vincenzo Mezzela <vincenzo.mezzela@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mac80211/cfg.c | 21 +++++++++++----------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -2339,6 +2339,17 @@ static int ieee80211_change_bss(struct w
+ if (!sband)
+ return -EINVAL;
+
++ if (params->basic_rates) {
++ if (!ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef,
++ wiphy->bands[sband->band],
++ params->basic_rates,
++ params->basic_rates_len,
++ &sdata->vif.bss_conf.basic_rates))
++ return -EINVAL;
++ changed |= BSS_CHANGED_BASIC_RATES;
++ ieee80211_check_rate_mask(sdata);
++ }
++
+ if (params->use_cts_prot >= 0) {
+ sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot;
+ changed |= BSS_CHANGED_ERP_CTS_PROT;
+@@ -2362,16 +2373,6 @@ static int ieee80211_change_bss(struct w
+ changed |= BSS_CHANGED_ERP_SLOT;
+ }
+
+- if (params->basic_rates) {
+- ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef,
+- wiphy->bands[sband->band],
+- params->basic_rates,
+- params->basic_rates_len,
+- &sdata->vif.bss_conf.basic_rates);
+- changed |= BSS_CHANGED_BASIC_RATES;
+- ieee80211_check_rate_mask(sdata);
+- }
+-
+ if (params->ap_isolate >= 0) {
+ if (params->ap_isolate)
+ sdata->flags |= IEEE80211_SDATA_DONT_BRIDGE_PACKETS;