diff options
author | Peter Ujfalusi <peter.ujfalusi@linux.intel.com> | 2022-07-12 15:23:55 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2022-08-25 12:45:49 +0300 |
commit | 230f646085d17a008b609eb8fe8befb8811868f0 (patch) | |
tree | f6a6600c7171a80df0eb4094769eab2f8fdf6151 | |
parent | 62c8639072ae6cd7bbc0a27ea4d1faf7091f0a07 (diff) | |
download | linux-230f646085d17a008b609eb8fe8befb8811868f0.tar.xz |
ASoC: SOF: Intel: cnl: Do not process IPC reply before firmware boot
[ 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>
-rw-r--r-- | sound/soc/sof/intel/cnl.c | 37 |
1 files 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; } |