From: Greg Kroah-Hartman Date: Tue, 13 Aug 2024 10:49:13 +0000 (+0200) Subject: 5.15-stable patches X-Git-Tag: v6.1.105~19 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6db2f92303d18eb2f29a86222e55619f7ec9d940;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: net-stmmac-enable-mac_managed_pm-phylink-config.patch netfilter-nf_tables-allow-clone-callbacks-to-sleep.patch netfilter-nf_tables-bail-out-if-stateful-expression-provides-no-.clone.patch netfilter-nf_tables-prefer-nft_chain_validate.patch netfilter-nf_tables-set-element-extended-ack-reporting-support.patch netfilter-nf_tables-use-timestamp-to-check-for-set-element-timeout.patch pci-dpc-fix-use-after-free-on-concurrent-dpc-and-hot-removal.patch pci-dwc-restore-msi-receiver-mask-during-resume.patch tls-fix-race-between-tx-work-scheduling-and-socket-close.patch wifi-mac80211-check-basic-rates-validity.patch --- diff --git a/queue-5.15/net-stmmac-enable-mac_managed_pm-phylink-config.patch b/queue-5.15/net-stmmac-enable-mac_managed_pm-phylink-config.patch new file mode 100644 index 00000000000..be98e603397 --- /dev/null +++ b/queue-5.15/net-stmmac-enable-mac_managed_pm-phylink-config.patch @@ -0,0 +1,36 @@ +From jszhang@kernel.org Sat Aug 3 13:45:23 2024 +From: Jisheng Zhang +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 +Cc: netdev@vger.kernel.org, Shenwei Wang , Florian Fainelli , "David S . Miller" +Message-ID: <20240803113044.2285-1-jszhang@kernel.org> + +From: Shenwei Wang + +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 +Acked-by: Florian Fainelli +Signed-off-by: David S. Miller +Signed-off-by: Jisheng Zhang +Signed-off-by: Greg Kroah-Hartman +--- + 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)) diff --git a/queue-5.15/netfilter-nf_tables-allow-clone-callbacks-to-sleep.patch b/queue-5.15/netfilter-nf_tables-allow-clone-callbacks-to-sleep.patch new file mode 100644 index 00000000000..1cb9bae1fd4 --- /dev/null +++ b/queue-5.15/netfilter-nf_tables-allow-clone-callbacks-to-sleep.patch @@ -0,0 +1,244 @@ +From stable+bounces-66447-greg=kroah.com@vger.kernel.org Mon Aug 12 12:25:26 2024 +From: Pablo Neira Ayuso +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 + +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 +Signed-off-by: Florian Westphal +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 | 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; + diff --git a/queue-5.15/netfilter-nf_tables-bail-out-if-stateful-expression-provides-no-.clone.patch b/queue-5.15/netfilter-nf_tables-bail-out-if-stateful-expression-provides-no-.clone.patch new file mode 100644 index 00000000000..078e8c04b70 --- /dev/null +++ b/queue-5.15/netfilter-nf_tables-bail-out-if-stateful-expression-provides-no-.clone.patch @@ -0,0 +1,46 @@ +From stable+bounces-66446-greg=kroah.com@vger.kernel.org Mon Aug 12 12:25:23 2024 +From: Pablo Neira Ayuso +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 + +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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); + diff --git a/queue-5.15/netfilter-nf_tables-prefer-nft_chain_validate.patch b/queue-5.15/netfilter-nf_tables-prefer-nft_chain_validate.patch new file mode 100644 index 00000000000..118d15e2ae9 --- /dev/null +++ b/queue-5.15/netfilter-nf_tables-prefer-nft_chain_validate.patch @@ -0,0 +1,228 @@ +From stable+bounces-66448-greg=kroah.com@vger.kernel.org Mon Aug 12 12:25:29 2024 +From: Pablo Neira Ayuso +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 + +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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + 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; + } diff --git a/queue-5.15/netfilter-nf_tables-set-element-extended-ack-reporting-support.patch b/queue-5.15/netfilter-nf_tables-set-element-extended-ack-reporting-support.patch new file mode 100644 index 00000000000..acc91ac87d9 --- /dev/null +++ b/queue-5.15/netfilter-nf_tables-set-element-extended-ack-reporting-support.patch @@ -0,0 +1,59 @@ +From stable+bounces-66444-greg=kroah.com@vger.kernel.org Mon Aug 12 12:25:15 2024 +From: Pablo Neira Ayuso +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 + +commit b53c116642502b0c85ecef78bff4f826a7dd4145 upstream. + +Report the element that causes problems via netlink extended ACK for set +element commands. + +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman +--- + 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; + } diff --git a/queue-5.15/netfilter-nf_tables-use-timestamp-to-check-for-set-element-timeout.patch b/queue-5.15/netfilter-nf_tables-use-timestamp-to-check-for-set-element-timeout.patch new file mode 100644 index 00000000000..9e55a5403fc --- /dev/null +++ b/queue-5.15/netfilter-nf_tables-use-timestamp-to-check-for-set-element-timeout.patch @@ -0,0 +1,287 @@ +From stable+bounces-66445-greg=kroah.com@vger.kernel.org Mon Aug 12 12:25:20 2024 +From: Pablo Neira Ayuso +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 + +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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; diff --git a/queue-5.15/pci-dpc-fix-use-after-free-on-concurrent-dpc-and-hot-removal.patch b/queue-5.15/pci-dpc-fix-use-after-free-on-concurrent-dpc-and-hot-removal.patch new file mode 100644 index 00000000000..456d2b50e9a --- /dev/null +++ b/queue-5.15/pci-dpc-fix-use-after-free-on-concurrent-dpc-and-hot-removal.patch @@ -0,0 +1,124 @@ +From stable+bounces-62765-greg=kroah.com@vger.kernel.org Tue Jul 30 12:59:10 2024 +From: Lukas Wunner +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 , Sasha Levin +Cc: stable@vger.kernel.org, linux-pci@vger.kernel.org, Keith Busch , Mika Westerberg , Bjorn Helgaas , Krzysztof Wilczynski +Message-ID: + +From: Lukas Wunner + +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 +Tested-by: Keith Busch +Signed-off-by: Lukas Wunner +Signed-off-by: Krzysztof Wilczyński +Reviewed-by: Keith Busch +Reviewed-by: Mika Westerberg +Cc: stable@vger.kernel.org # v5.10+ +Signed-off-by: Greg Kroah-Hartman +--- + 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) diff --git a/queue-5.15/pci-dwc-restore-msi-receiver-mask-during-resume.patch b/queue-5.15/pci-dwc-restore-msi-receiver-mask-during-resume.patch new file mode 100644 index 00000000000..fe11ffa33eb --- /dev/null +++ b/queue-5.15/pci-dwc-restore-msi-receiver-mask-during-resume.patch @@ -0,0 +1,55 @@ +From jszhang@kernel.org Sat Aug 3 13:43:25 2024 +From: Jisheng Zhang +Date: Sat, 3 Aug 2024 19:28:52 +0800 +Subject: PCI: dwc: Restore MSI Receiver mask during resume +To: stable@kernel.org, "Jingoo Han" , "Manivannan Sadhasivam" , "Lorenzo Pieralisi" , "Krzysztof Wilczyński" , "Rob Herring" , "Bjorn Helgaas" , "Greg Kroah-Hartman" +Cc: linux-pci@vger.kernel.org, Richard Zhu , Lorenzo Pieralisi +Message-ID: <20240803112852.2263-1-jszhang@kernel.org> + +From: Jisheng Zhang + +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 +Link: https://lore.kernel.org/r/20211226074019.2556-1-jszhang@kernel.org +Signed-off-by: Jisheng Zhang +Signed-off-by: Lorenzo Pieralisi +Signed-off-by: Bjorn Helgaas +Signed-off-by: Greg Kroah-Hartman +--- + 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]); diff --git a/queue-5.15/series b/queue-5.15/series index 1d54a7a9b74..0d97d236ad7 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -485,3 +485,13 @@ btrfs-fix-corruption-after-buffer-fault-in-during-direct-io-append-write.patch 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 diff --git a/queue-5.15/tls-fix-race-between-tx-work-scheduling-and-socket-close.patch b/queue-5.15/tls-fix-race-between-tx-work-scheduling-and-socket-close.patch new file mode 100644 index 00000000000..42fafef1094 --- /dev/null +++ b/queue-5.15/tls-fix-race-between-tx-work-scheduling-and-socket-close.patch @@ -0,0 +1,68 @@ +From e01e3934a1b2d122919f73bc6ddbe1cdafc4bbdb Mon Sep 17 00:00:00 2001 +From: Jakub Kicinski +Date: Tue, 6 Feb 2024 17:18:20 -0800 +Subject: tls: fix race between tx work scheduling and socket close + +From: Jakub Kicinski + +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 +Fixes: a42055e8d2c3 ("net/tls: Add support for async encryption of records for performance") +Signed-off-by: Jakub Kicinski +Reviewed-by: Simon Horman +Reviewed-by: Sabrina Dubroca +Signed-off-by: David S. Miller +[ Lee: Fixed merge-conflict in Stable branches linux-6.1.y and older ] +Signed-off-by: Lee Jones +[ 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 +Signed-off-by: Greg Kroah-Hartman +--- + 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) diff --git a/queue-5.15/wifi-mac80211-check-basic-rates-validity.patch b/queue-5.15/wifi-mac80211-check-basic-rates-validity.patch new file mode 100644 index 00000000000..838a0d0ab07 --- /dev/null +++ b/queue-5.15/wifi-mac80211-check-basic-rates-validity.patch @@ -0,0 +1,63 @@ +From ce04abc3fcc62cd5640af981ebfd7c4dc3bded28 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Fri, 24 Feb 2023 10:52:19 +0100 +Subject: wifi: mac80211: check basic rates validity + +From: Johannes Berg + +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 +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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;