--- /dev/null
+From 171eb6f71e9e3ba6a7410a1d93f3ac213f39dae2 Mon Sep 17 00:00:00 2001
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Date: Sat, 19 Apr 2025 23:34:48 +0200
+Subject: ASoC: meson: meson-card-utils: use of_property_present() for DT parsing
+
+From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+
+commit 171eb6f71e9e3ba6a7410a1d93f3ac213f39dae2 upstream.
+
+Commit c141ecc3cecd ("of: Warn when of_property_read_bool() is used on
+non-boolean properties") added a warning when trying to parse a property
+with a value (boolean properties are defined as: absent = false, present
+without any value = true). This causes a warning from meson-card-utils.
+
+meson-card-utils needs to know about the existence of the
+"audio-routing" and/or "audio-widgets" properties in order to properly
+parse them. Switch to of_property_present() in order to silence the
+following warning messages during boot:
+ OF: /sound: Read of boolean property 'audio-routing' with a value.
+ OF: /sound: Read of boolean property 'audio-widgets' with a value.
+
+Fixes: 7864a79f37b5 ("ASoC: meson: add axg sound card support")
+Tested-by: Christian Hewitt <christianshewitt@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Link: https://patch.msgid.link/20250419213448.59647-1-martin.blumenstingl@googlemail.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/soc/meson/meson-card-utils.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/meson/meson-card-utils.c
++++ b/sound/soc/meson/meson-card-utils.c
+@@ -245,7 +245,7 @@ static int meson_card_parse_of_optional(
+ const char *p))
+ {
+ /* If property is not provided, don't fail ... */
+- if (!of_property_read_bool(card->dev->of_node, propname))
++ if (!of_property_present(card->dev->of_node, propname))
+ return 0;
+
+ /* ... but do fail if it is provided and the parsing fails */
--- /dev/null
+From 688abe2860fd9c644705b9e11cb9649eb891b879 Mon Sep 17 00:00:00 2001
+From: Wentao Liang <vulab@iscas.ac.cn>
+Date: Mon, 19 May 2025 15:57:39 +0800
+Subject: ASoC: qcom: sdm845: Add error handling in sdm845_slim_snd_hw_params()
+
+From: Wentao Liang <vulab@iscas.ac.cn>
+
+commit 688abe2860fd9c644705b9e11cb9649eb891b879 upstream.
+
+The function sdm845_slim_snd_hw_params() calls the functuion
+snd_soc_dai_set_channel_map() but does not check its return
+value. A proper implementation can be found in msm_snd_hw_params().
+
+Add error handling for snd_soc_dai_set_channel_map(). If the
+function fails and it is not a unsupported error, return the
+error code immediately.
+
+Fixes: 5caf64c633a3 ("ASoC: qcom: sdm845: add support to DB845c and Lenovo Yoga")
+Cc: stable@vger.kernel.org # v5.6
+Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Link: https://patch.msgid.link/20250519075739.1458-1-vulab@iscas.ac.cn
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ sound/soc/qcom/sdm845.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/sound/soc/qcom/sdm845.c
++++ b/sound/soc/qcom/sdm845.c
+@@ -78,6 +78,10 @@ static int sdm845_slim_snd_hw_params(str
+ else
+ ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt,
+ tx_ch, 0, NULL);
++ if (ret != 0 && ret != -ENOTSUPP) {
++ dev_err(rtd->dev, "failed to set cpu chan map, err:%d\n", ret);
++ return ret;
++ }
+ }
+
+ return 0;
--- /dev/null
+From f830edbae247b89228c3e09294151b21e0dc849c Mon Sep 17 00:00:00 2001
+From: Zijun Hu <quic_zijuhu@quicinc.com>
+Date: Wed, 7 May 2025 19:50:26 +0800
+Subject: configfs: Do not override creating attribute file failure in populate_attrs()
+
+From: Zijun Hu <quic_zijuhu@quicinc.com>
+
+commit f830edbae247b89228c3e09294151b21e0dc849c upstream.
+
+populate_attrs() may override failure for creating attribute files
+by success for creating subsequent bin attribute files, and have
+wrong return value.
+
+Fix by creating bin attribute files under successfully creating
+attribute files.
+
+Fixes: 03607ace807b ("configfs: implement binary attributes")
+Cc: stable@vger.kernel.org
+Reviewed-by: Joel Becker <jlbec@evilplan.org>
+Reviewed-by: Breno Leitao <leitao@debian.org>
+Signed-off-by: Zijun Hu <quic_zijuhu@quicinc.com>
+Link: https://lore.kernel.org/r/20250507-fix_configfs-v3-2-fe2d96de8dc4@quicinc.com
+Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/configfs/dir.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/configfs/dir.c
++++ b/fs/configfs/dir.c
+@@ -593,7 +593,7 @@ static int populate_attrs(struct config_
+ break;
+ }
+ }
+- if (t->ct_bin_attrs) {
++ if (!error && t->ct_bin_attrs) {
+ for (i = 0; (bin_attr = t->ct_bin_attrs[i]) != NULL; i++) {
+ error = configfs_create_bin_file(item, bin_attr);
+ if (error)
--- /dev/null
+From 0413bcf0fc460a68a2a7a8354aee833293d7d693 Mon Sep 17 00:00:00 2001
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Thu, 8 May 2025 13:22:16 +0800
+Subject: crypto: marvell/cesa - Do not chain submitted requests
+
+From: Herbert Xu <herbert@gondor.apana.org.au>
+
+commit 0413bcf0fc460a68a2a7a8354aee833293d7d693 upstream.
+
+This driver tries to chain requests together before submitting them
+to hardware in order to reduce completion interrupts.
+
+However, it even extends chains that have already been submitted
+to hardware. This is dangerous because there is no way of knowing
+whether the hardware has already read the DMA memory in question
+or not.
+
+Fix this by splitting the chain list into two. One for submitted
+requests and one for requests that have not yet been submitted.
+Only extend the latter.
+
+Reported-by: Klaus Kudielka <klaus.kudielka@gmail.com>
+Fixes: 85030c5168f1 ("crypto: marvell - Add support for chaining crypto requests in TDMA mode")
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/crypto/marvell/cesa/cesa.c | 2 -
+ drivers/crypto/marvell/cesa/cesa.h | 9 ++++--
+ drivers/crypto/marvell/cesa/tdma.c | 53 ++++++++++++++++++++++---------------
+ 3 files changed, 39 insertions(+), 25 deletions(-)
+
+--- a/drivers/crypto/marvell/cesa/cesa.c
++++ b/drivers/crypto/marvell/cesa/cesa.c
+@@ -94,7 +94,7 @@ static int mv_cesa_std_process(struct mv
+
+ static int mv_cesa_int_process(struct mv_cesa_engine *engine, u32 status)
+ {
+- if (engine->chain.first && engine->chain.last)
++ if (engine->chain_hw.first && engine->chain_hw.last)
+ return mv_cesa_tdma_process(engine, status);
+
+ return mv_cesa_std_process(engine, status);
+--- a/drivers/crypto/marvell/cesa/cesa.h
++++ b/drivers/crypto/marvell/cesa/cesa.h
+@@ -440,8 +440,10 @@ struct mv_cesa_dev {
+ * SRAM
+ * @queue: fifo of the pending crypto requests
+ * @load: engine load counter, useful for load balancing
+- * @chain: list of the current tdma descriptors being processed
+- * by this engine.
++ * @chain_hw: list of the current tdma descriptors being processed
++ * by the hardware.
++ * @chain_sw: list of the current tdma descriptors that will be
++ * submitted to the hardware.
+ * @complete_queue: fifo of the processed requests by the engine
+ *
+ * Structure storing CESA engine information.
+@@ -463,7 +465,8 @@ struct mv_cesa_engine {
+ struct gen_pool *pool;
+ struct crypto_queue queue;
+ atomic_t load;
+- struct mv_cesa_tdma_chain chain;
++ struct mv_cesa_tdma_chain chain_hw;
++ struct mv_cesa_tdma_chain chain_sw;
+ struct list_head complete_queue;
+ int irq;
+ };
+--- a/drivers/crypto/marvell/cesa/tdma.c
++++ b/drivers/crypto/marvell/cesa/tdma.c
+@@ -38,6 +38,15 @@ void mv_cesa_dma_step(struct mv_cesa_req
+ {
+ struct mv_cesa_engine *engine = dreq->engine;
+
++ spin_lock_bh(&engine->lock);
++ if (engine->chain_sw.first == dreq->chain.first) {
++ engine->chain_sw.first = NULL;
++ engine->chain_sw.last = NULL;
++ }
++ engine->chain_hw.first = dreq->chain.first;
++ engine->chain_hw.last = dreq->chain.last;
++ spin_unlock_bh(&engine->lock);
++
+ writel_relaxed(0, engine->regs + CESA_SA_CFG);
+
+ mv_cesa_set_int_mask(engine, CESA_SA_INT_ACC0_IDMA_DONE);
+@@ -96,25 +105,27 @@ void mv_cesa_dma_prepare(struct mv_cesa_
+ void mv_cesa_tdma_chain(struct mv_cesa_engine *engine,
+ struct mv_cesa_req *dreq)
+ {
+- if (engine->chain.first == NULL && engine->chain.last == NULL) {
+- engine->chain.first = dreq->chain.first;
+- engine->chain.last = dreq->chain.last;
+- } else {
+- struct mv_cesa_tdma_desc *last;
++ struct mv_cesa_tdma_desc *last = engine->chain_sw.last;
+
+- last = engine->chain.last;
++ /*
++ * Break the DMA chain if the request being queued needs the IV
++ * regs to be set before lauching the request.
++ */
++ if (!last || dreq->chain.first->flags & CESA_TDMA_SET_STATE)
++ engine->chain_sw.first = dreq->chain.first;
++ else {
+ last->next = dreq->chain.first;
+- engine->chain.last = dreq->chain.last;
+-
+- /*
+- * Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on
+- * the last element of the current chain, or if the request
+- * being queued needs the IV regs to be set before lauching
+- * the request.
+- */
+- if (!(last->flags & CESA_TDMA_BREAK_CHAIN) &&
+- !(dreq->chain.first->flags & CESA_TDMA_SET_STATE))
+- last->next_dma = cpu_to_le32(dreq->chain.first->cur_dma);
++ last->next_dma = cpu_to_le32(dreq->chain.first->cur_dma);
++ }
++ last = dreq->chain.last;
++ engine->chain_sw.last = last;
++ /*
++ * Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on
++ * the last element of the current chain.
++ */
++ if (last->flags & CESA_TDMA_BREAK_CHAIN) {
++ engine->chain_sw.first = NULL;
++ engine->chain_sw.last = NULL;
+ }
+ }
+
+@@ -127,7 +138,7 @@ int mv_cesa_tdma_process(struct mv_cesa_
+
+ tdma_cur = readl(engine->regs + CESA_TDMA_CUR);
+
+- for (tdma = engine->chain.first; tdma; tdma = next) {
++ for (tdma = engine->chain_hw.first; tdma; tdma = next) {
+ spin_lock_bh(&engine->lock);
+ next = tdma->next;
+ spin_unlock_bh(&engine->lock);
+@@ -149,12 +160,12 @@ int mv_cesa_tdma_process(struct mv_cesa_
+ &backlog);
+
+ /* Re-chaining to the next request */
+- engine->chain.first = tdma->next;
++ engine->chain_hw.first = tdma->next;
+ tdma->next = NULL;
+
+ /* If this is the last request, clear the chain */
+- if (engine->chain.first == NULL)
+- engine->chain.last = NULL;
++ if (engine->chain_hw.first == NULL)
++ engine->chain_hw.last = NULL;
+ spin_unlock_bh(&engine->lock);
+
+ ctx = crypto_tfm_ctx(req->tfm);
--- /dev/null
+From ac5ee087d31ed93b6e45d2968a66828c6f621d8c Mon Sep 17 00:00:00 2001
+From: Alexander Aring <aahringo@redhat.com>
+Date: Mon, 31 Mar 2025 19:03:24 -0400
+Subject: gfs2: move msleep to sleepable context
+
+From: Alexander Aring <aahringo@redhat.com>
+
+commit ac5ee087d31ed93b6e45d2968a66828c6f621d8c upstream.
+
+This patch moves the msleep_interruptible() out of the non-sleepable
+context by moving the ls->ls_recover_spin spinlock around so
+msleep_interruptible() will be called in a sleepable context.
+
+Cc: stable@vger.kernel.org
+Fixes: 4a7727725dc7 ("GFS2: Fix recovery issues for spectators")
+Suggested-by: Andreas Gruenbacher <agruenba@redhat.com>
+Signed-off-by: Alexander Aring <aahringo@redhat.com>
+Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/gfs2/lock_dlm.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/fs/gfs2/lock_dlm.c
++++ b/fs/gfs2/lock_dlm.c
+@@ -942,14 +942,15 @@ locks_done:
+ if (sdp->sd_args.ar_spectator) {
+ fs_info(sdp, "Recovery is required. Waiting for a "
+ "non-spectator to mount.\n");
++ spin_unlock(&ls->ls_recover_spin);
+ msleep_interruptible(1000);
+ } else {
+ fs_info(sdp, "control_mount wait1 block %u start %u "
+ "mount %u lvb %u flags %lx\n", block_gen,
+ start_gen, mount_gen, lvb_gen,
+ ls->ls_recover_flags);
++ spin_unlock(&ls->ls_recover_spin);
+ }
+- spin_unlock(&ls->ls_recover_spin);
+ goto restart;
+ }
+
--- /dev/null
+From c6bb8a21cdad8c975a3a646b9e5c8df01ad29783 Mon Sep 17 00:00:00 2001
+From: Wentao Liang <vulab@iscas.ac.cn>
+Date: Sun, 25 May 2025 00:34:25 +0800
+Subject: net/mlx5: Add error handling in mlx5_query_nic_vport_node_guid()
+
+From: Wentao Liang <vulab@iscas.ac.cn>
+
+commit c6bb8a21cdad8c975a3a646b9e5c8df01ad29783 upstream.
+
+The function mlx5_query_nic_vport_node_guid() calls the function
+mlx5_query_nic_vport_context() but does not check its return value.
+A proper implementation can be found in mlx5_nic_vport_query_local_lb().
+
+Add error handling for mlx5_query_nic_vport_context(). If it fails, free
+the out buffer via kvfree() and return error code.
+
+Fixes: 9efa75254593 ("net/mlx5_core: Introduce access functions to query vport RoCE fields")
+Cc: stable@vger.kernel.org # v4.5
+Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
+Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20250524163425.1695-1-vulab@iscas.ac.cn
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/vport.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
+@@ -441,19 +441,22 @@ int mlx5_query_nic_vport_node_guid(struc
+ {
+ u32 *out;
+ int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out);
++ int err;
+
+ out = kvzalloc(outlen, GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+- mlx5_query_nic_vport_context(mdev, 0, out);
++ err = mlx5_query_nic_vport_context(mdev, 0, out);
++ if (err)
++ goto out;
+
+ *node_guid = MLX5_GET64(query_nic_vport_context_out, out,
+ nic_vport_context.node_guid);
+-
++out:
+ kvfree(out);
+
+- return 0;
++ return err;
+ }
+ EXPORT_SYMBOL_GPL(mlx5_query_nic_vport_node_guid);
+
--- /dev/null
+From f0b50730bdd8f2734e548de541e845c0d40dceb6 Mon Sep 17 00:00:00 2001
+From: Wentao Liang <vulab@iscas.ac.cn>
+Date: Wed, 21 May 2025 21:36:20 +0800
+Subject: net/mlx5_core: Add error handling inmlx5_query_nic_vport_qkey_viol_cntr()
+
+From: Wentao Liang <vulab@iscas.ac.cn>
+
+commit f0b50730bdd8f2734e548de541e845c0d40dceb6 upstream.
+
+The function mlx5_query_nic_vport_qkey_viol_cntr() calls the function
+mlx5_query_nic_vport_context() but does not check its return value. This
+could lead to undefined behavior if the query fails. A proper
+implementation can be found in mlx5_nic_vport_query_local_lb().
+
+Add error handling for mlx5_query_nic_vport_context(). If it fails, free
+the out buffer via kvfree() and return error code.
+
+Fixes: 9efa75254593 ("net/mlx5_core: Introduce access functions to query vport RoCE fields")
+Cc: stable@vger.kernel.org # v4.5
+Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
+Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
+Link: https://patch.msgid.link/20250521133620.912-1-vulab@iscas.ac.cn
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/vport.c | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c
+@@ -495,19 +495,22 @@ int mlx5_query_nic_vport_qkey_viol_cntr(
+ {
+ u32 *out;
+ int outlen = MLX5_ST_SZ_BYTES(query_nic_vport_context_out);
++ int err;
+
+ out = kvzalloc(outlen, GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+- mlx5_query_nic_vport_context(mdev, 0, out);
++ err = mlx5_query_nic_vport_context(mdev, 0, out);
++ if (err)
++ goto out;
+
+ *qkey_viol_cntr = MLX5_GET(query_nic_vport_context_out, out,
+ nic_vport_context.qkey_violation_counter);
+-
++out:
+ kvfree(out);
+
+- return 0;
++ return err;
+ }
+ EXPORT_SYMBOL_GPL(mlx5_query_nic_vport_qkey_viol_cntr);
+
--- /dev/null
+From 9cc0eafd28c7faef300822992bb08d79cab2a36c Mon Sep 17 00:00:00 2001
+From: Gautam Menghani <gautam@linux.ibm.com>
+Date: Wed, 5 Mar 2025 14:32:36 +0530
+Subject: powerpc/pseries/msi: Avoid reading PCI device registers in reduced power states
+
+From: Gautam Menghani <gautam@linux.ibm.com>
+
+commit 9cc0eafd28c7faef300822992bb08d79cab2a36c upstream.
+
+When a system is being suspended to RAM, the PCI devices are also
+suspended and the PPC code ends up calling pseries_msi_compose_msg() and
+this triggers the BUG_ON() in __pci_read_msi_msg() because the device at
+this point is in reduced power state. In reduced power state, the memory
+mapped registers of the PCI device are not accessible.
+
+To replicate the bug:
+1. Make sure deep sleep is selected
+ # cat /sys/power/mem_sleep
+ s2idle [deep]
+
+2. Make sure console is not suspended (so that dmesg logs are visible)
+ echo N > /sys/module/printk/parameters/console_suspend
+
+3. Suspend the system
+ echo mem > /sys/power/state
+
+To fix this behaviour, read the cached msi message of the device when the
+device is not in PCI_D0 power state instead of touching the hardware.
+
+Fixes: a5f3d2c17b07 ("powerpc/pseries/pci: Add MSI domains")
+Cc: stable@vger.kernel.org # v5.15+
+Signed-off-by: Gautam Menghani <gautam@linux.ibm.com>
+Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
+Reviewed-by: Vaibhav Jain <vaibhav@linux.ibm.com>
+Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
+Link: https://patch.msgid.link/20250305090237.294633-1-gautam@linux.ibm.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/powerpc/platforms/pseries/msi.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/arch/powerpc/platforms/pseries/msi.c
++++ b/arch/powerpc/platforms/pseries/msi.c
+@@ -539,7 +539,12 @@ static struct msi_domain_info pseries_ms
+
+ static void pseries_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
+ {
+- __pci_read_msi_msg(irq_data_get_msi_desc(data), msg);
++ struct pci_dev *dev = msi_desc_to_pci_dev(irq_data_get_msi_desc(data));
++
++ if (dev->current_state == PCI_D0)
++ __pci_read_msi_msg(irq_data_get_msi_desc(data), msg);
++ else
++ get_cached_msi_msg(data->irq, msg);
+ }
+
+ static struct irq_chip pseries_msi_irq_chip = {
kbuild-userprogs-fix-bitsize-and-target-detection-on-clang.patch
kbuild-hdrcheck-fix-cross-build-with-clang.patch
xfs-allow-inode-inactivation-during-a-ro-mount-log-r.patch
+configfs-do-not-override-creating-attribute-file-failure-in-populate_attrs.patch
+crypto-marvell-cesa-do-not-chain-submitted-requests.patch
+gfs2-move-msleep-to-sleepable-context.patch
+asoc-qcom-sdm845-add-error-handling-in-sdm845_slim_snd_hw_params.patch
+asoc-meson-meson-card-utils-use-of_property_present-for-dt-parsing.patch
+powerpc-pseries-msi-avoid-reading-pci-device-registers-in-reduced-power-states.patch
+net-mlx5_core-add-error-handling-inmlx5_query_nic_vport_qkey_viol_cntr.patch
+net-mlx5-add-error-handling-in-mlx5_query_nic_vport_node_guid.patch
+wifi-p54-prevent-buffer-overflow-in-p54_rx_eeprom_readback.patch
--- /dev/null
+From da1b9a55ff116cb040528ef664c70a4eec03ae99 Mon Sep 17 00:00:00 2001
+From: Christian Lamparter <chunkeey@gmail.com>
+Date: Fri, 16 May 2025 20:41:06 +0200
+Subject: wifi: p54: prevent buffer-overflow in p54_rx_eeprom_readback()
+
+From: Christian Lamparter <chunkeey@gmail.com>
+
+commit da1b9a55ff116cb040528ef664c70a4eec03ae99 upstream.
+
+Robert Morris reported:
+
+|If a malicious USB device pretends to be an Intersil p54 wifi
+|interface and generates an eeprom_readback message with a large
+|eeprom->v1.len, p54_rx_eeprom_readback() will copy data from the
+|message beyond the end of priv->eeprom.
+|
+|static void p54_rx_eeprom_readback(struct p54_common *priv,
+| struct sk_buff *skb)
+|{
+| struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+| struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
+|
+| if (priv->fw_var >= 0x509) {
+| memcpy(priv->eeprom, eeprom->v2.data,
+| le16_to_cpu(eeprom->v2.len));
+| } else {
+| memcpy(priv->eeprom, eeprom->v1.data,
+| le16_to_cpu(eeprom->v1.len));
+| }
+| [...]
+
+The eeprom->v{1,2}.len is set by the driver in p54_download_eeprom().
+The device is supposed to provide the same length back to the driver.
+But yes, it's possible (like shown in the report) to alter the value
+to something that causes a crash/panic due to overrun.
+
+This patch addresses the issue by adding the size to the common device
+context, so p54_rx_eeprom_readback no longer relies on possibly tampered
+values... That said, it also checks if the "firmware" altered the value
+and no longer copies them.
+
+The one, small saving grace is: Before the driver tries to read the eeprom,
+it needs to upload >a< firmware. the vendor firmware has a proprietary
+license and as a reason, it is not present on most distributions by
+default.
+
+Cc: <stable@kernel.org>
+Reported-by: Robert Morris <rtm@mit.edu>
+Closes: https://lore.kernel.org/linux-wireless/28782.1747258414@localhost/
+Fixes: 7cb770729ba8 ("p54: move eeprom code into common library")
+Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
+Link: https://patch.msgid.link/20250516184107.47794-1-chunkeey@gmail.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/intersil/p54/fwio.c | 2 ++
+ drivers/net/wireless/intersil/p54/p54.h | 1 +
+ drivers/net/wireless/intersil/p54/txrx.c | 13 +++++++++----
+ 3 files changed, 12 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/wireless/intersil/p54/fwio.c
++++ b/drivers/net/wireless/intersil/p54/fwio.c
+@@ -233,6 +233,7 @@ int p54_download_eeprom(struct p54_commo
+
+ mutex_lock(&priv->eeprom_mutex);
+ priv->eeprom = buf;
++ priv->eeprom_slice_size = len;
+ eeprom_hdr = skb_put(skb, eeprom_hdr_size + len);
+
+ if (priv->fw_var < 0x509) {
+@@ -255,6 +256,7 @@ int p54_download_eeprom(struct p54_commo
+ ret = -EBUSY;
+ }
+ priv->eeprom = NULL;
++ priv->eeprom_slice_size = 0;
+ mutex_unlock(&priv->eeprom_mutex);
+ return ret;
+ }
+--- a/drivers/net/wireless/intersil/p54/p54.h
++++ b/drivers/net/wireless/intersil/p54/p54.h
+@@ -258,6 +258,7 @@ struct p54_common {
+
+ /* eeprom handling */
+ void *eeprom;
++ size_t eeprom_slice_size;
+ struct completion eeprom_comp;
+ struct mutex eeprom_mutex;
+ };
+--- a/drivers/net/wireless/intersil/p54/txrx.c
++++ b/drivers/net/wireless/intersil/p54/txrx.c
+@@ -500,14 +500,19 @@ static void p54_rx_eeprom_readback(struc
+ return ;
+
+ if (priv->fw_var >= 0x509) {
+- memcpy(priv->eeprom, eeprom->v2.data,
+- le16_to_cpu(eeprom->v2.len));
++ if (le16_to_cpu(eeprom->v2.len) != priv->eeprom_slice_size)
++ return;
++
++ memcpy(priv->eeprom, eeprom->v2.data, priv->eeprom_slice_size);
+ } else {
+- memcpy(priv->eeprom, eeprom->v1.data,
+- le16_to_cpu(eeprom->v1.len));
++ if (le16_to_cpu(eeprom->v1.len) != priv->eeprom_slice_size)
++ return;
++
++ memcpy(priv->eeprom, eeprom->v1.data, priv->eeprom_slice_size);
+ }
+
+ priv->eeprom = NULL;
++ priv->eeprom_slice_size = 0;
+ tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
+ dev_kfree_skb_any(tmp);
+ complete(&priv->eeprom_comp);