| From 3850543fee9c9de2e8472fd4aa734a0e09709496 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 12 Jul 2022 15:23:55 +0300 |
| Subject: ASoC: SOF: Intel: cnl: Do not process IPC reply before firmware boot |
| |
| From: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> |
| |
| [ Upstream commit acacd9eefd0def5a83244d88e5483b5f38ee7287 ] |
| |
| It is not yet clear, but it is possible to create a firmware so broken |
| that it will send a reply message before a FW_READY message (it is not |
| yet clear if FW_READY will arrive later). |
| Since the reply_data is allocated only after the FW_READY message, this |
| will lead to a NULL pointer dereference if not filtered out. |
| |
| The issue was reported with IPC4 firmware but the same condition is present |
| for IPC3. |
| |
| Reported-by: Kai Vehmanen <kai.vehmanen@linux.intel.com> |
| Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> |
| Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> |
| Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> |
| Link: https://lore.kernel.org/r/20220712122357.31282-2-peter.ujfalusi@linux.intel.com |
| Signed-off-by: Mark Brown <broonie@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| sound/soc/sof/intel/cnl.c | 37 ++++++++++++++++++++++++------------- |
| 1 file changed, 24 insertions(+), 13 deletions(-) |
| |
| diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c |
| index cd6e5f8a5eb4..6c98f65635fc 100644 |
| --- a/sound/soc/sof/intel/cnl.c |
| +++ b/sound/soc/sof/intel/cnl.c |
| @@ -60,17 +60,23 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context) |
| |
| if (primary & SOF_IPC4_MSG_DIR_MASK) { |
| /* Reply received */ |
| - struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data; |
| + if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) { |
| + struct sof_ipc4_msg *data = sdev->ipc->msg.reply_data; |
| |
| - data->primary = primary; |
| - data->extension = extension; |
| + data->primary = primary; |
| + data->extension = extension; |
| |
| - spin_lock_irq(&sdev->ipc_lock); |
| + spin_lock_irq(&sdev->ipc_lock); |
| |
| - snd_sof_ipc_get_reply(sdev); |
| - snd_sof_ipc_reply(sdev, data->primary); |
| + snd_sof_ipc_get_reply(sdev); |
| + snd_sof_ipc_reply(sdev, data->primary); |
| |
| - spin_unlock_irq(&sdev->ipc_lock); |
| + spin_unlock_irq(&sdev->ipc_lock); |
| + } else { |
| + dev_dbg_ratelimited(sdev->dev, |
| + "IPC reply before FW_READY: %#x|%#x\n", |
| + primary, extension); |
| + } |
| } else { |
| /* Notification received */ |
| notification_data.primary = primary; |
| @@ -124,15 +130,20 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context) |
| CNL_DSP_REG_HIPCCTL, |
| CNL_DSP_REG_HIPCCTL_DONE, 0); |
| |
| - spin_lock_irq(&sdev->ipc_lock); |
| + if (likely(sdev->fw_state == SOF_FW_BOOT_COMPLETE)) { |
| + spin_lock_irq(&sdev->ipc_lock); |
| |
| - /* handle immediate reply from DSP core */ |
| - hda_dsp_ipc_get_reply(sdev); |
| - snd_sof_ipc_reply(sdev, msg); |
| + /* handle immediate reply from DSP core */ |
| + hda_dsp_ipc_get_reply(sdev); |
| + snd_sof_ipc_reply(sdev, msg); |
| |
| - cnl_ipc_dsp_done(sdev); |
| + cnl_ipc_dsp_done(sdev); |
| |
| - spin_unlock_irq(&sdev->ipc_lock); |
| + spin_unlock_irq(&sdev->ipc_lock); |
| + } else { |
| + dev_dbg_ratelimited(sdev->dev, "IPC reply before FW_READY: %#x\n", |
| + msg); |
| + } |
| |
| ipc_irq = true; |
| } |
| -- |
| 2.35.1 |
| |