All of lore.kernel.org
 help / color / mirror / Atom feed
From: gaggery.tsai@intel.com
To: linux-drivers-review-request@eclists.intel.com
Cc: pierre-louis.bossart@linux.dev, yung-chuan.liao@linux.intel.com,
	ranjani.sridharan@linux.intel.com, stable@vger.kernel.org,
	Gaggery Tsai <gaggery.tsai@intel.com>
Subject: [PATCH v2] ASoC: SOF: Intel: hda: Fix NULL pointer dereference on SoundWire IRQ during removal
Date: Thu, 12 Mar 2026 08:08:37 -0700	[thread overview]
Message-ID: <20260312150837.2076641-1-gaggery.tsai@intel.com> (raw)
In-Reply-To: <20260312150005.2069660-1-gaggery.tsai@intel.com>

From: Gaggery Tsai <gaggery.tsai@intel.com>

hda_sdw_exit() sets hdev->sdw to NULL after calling sdw_intel_exit(),
but the shared IPC IRQ handler is not freed until much later in
hda_dsp_remove(). If a SoundWire interrupt fires in this window, the
IRQ thread calls hda_dsp_sdw_thread() -> sdw_intel_thread() with a
NULL context pointer or with link->cdns already freed, causing a NULL
pointer dereference:

  BUG: kernel NULL pointer dereference, address: 00000000000003d0
  RIP: 0010:sdw_cdns_irq+0x9/0x2b0 [soundwire_cadence]
  Call Trace:
   sdw_intel_thread+0x2d/0x50 [soundwire_intel]
   hda_dsp_interrupt_thread+0x99/0x3a0 [snd_sof_intel_hda_generic]
   irq_thread_fn+0x25/0x60

The race window is between hda_sdw_exit() tearing down SoundWire
links and free_irq() in hda_dsp_remove(). During sdw_intel_exit() ->
sdw_intel_cleanup(), each link's auxiliary device is unregistered,
which clears link->cdns. Meanwhile the IRQ thread can still fire and
iterate the link list, calling sdw_cdns_irq() with a NULL cdns.

Fix this in three ways:

  1. In hda_sdw_exit(), disable SoundWire interrupts at the hardware
     level (hda_sdw_int_enable) and call synchronize_irq() BEFORE
     tearing down the SoundWire context, preventing new IRQ threads
     from entering the SoundWire path.

  2. Add a NULL guard for link->cdns in sdw_intel_thread() to handle
     the case where the IRQ thread races with individual link
     removal during sdw_intel_cleanup().

  3. Add a NULL guard in hda_dsp_sdw_thread() as defense-in-depth
     for the case where hdev->sdw is already NULL.

Tested on Intel Panther Lake with SoundWire codecs by manually
unbinding the SOF PCI device while audio was active.

Fixes: 722ba5f1f530 ("ASoC: SOF: Intel: hda: merge IPC, stream and SoundWire interrupt handlers")
Cc: stable@vger.kernel.org
Cc: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
Cc: Bard Liao <yung-chuan.liao@linux.intel.com>
Cc: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Gaggery Tsai <gaggery.tsai@intel.com>
---
 drivers/soundwire/intel_init.c |  6 ++++--
 sound/soc/sof/intel/hda.c      | 11 +++++++++--
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c
index ad48d67fa935..e093a29f1590 100644
--- a/drivers/soundwire/intel_init.c
+++ b/drivers/soundwire/intel_init.c
@@ -145,8 +145,10 @@ irqreturn_t sdw_intel_thread(int irq, void *dev_id)
 	struct sdw_intel_ctx *ctx = dev_id;
 	struct sdw_intel_link_res *link;
 
-	list_for_each_entry(link, &ctx->link_list, list)
-		sdw_cdns_irq(irq, link->cdns);
+	list_for_each_entry(link, &ctx->link_list, list) {
+		if (link->cdns)
+			sdw_cdns_irq(irq, link->cdns);
+	}
 
 	return IRQ_HANDLED;
 }
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index c0cc7d3ce526..02a0e354414e 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -256,12 +256,17 @@ static int hda_sdw_exit(struct snd_sof_dev *sdev)
 
 	hdev = sdev->pdata->hw_pdata;
 
+	/* Disable SoundWire IRQ at the hardware level first to prevent
+	 * the IRQ handler from accessing hdev->sdw after it is freed.
+	 * synchronize_irq() ensures any in-flight handler has completed.
+	 */
+	hda_sdw_int_enable(sdev, false);
+	synchronize_irq(sdev->ipc_irq);
+
 	if (hdev->sdw)
 		sdw_intel_exit(hdev->sdw);
 	hdev->sdw = NULL;
 
-	hda_sdw_int_enable(sdev, false);
-
 	return 0;
 }
 
@@ -309,6 +314,8 @@ static bool hda_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
 
 static irqreturn_t hda_dsp_sdw_thread(int irq, void *context)
 {
+	if (!context)
+		return IRQ_HANDLED;
 	return sdw_intel_thread(irq, context);
 }
 
-- 
2.43.0


  reply	other threads:[~2026-03-12 15:10 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-12 15:00 [PATCH] ASoC: SOF: Intel: hda: Fix NULL pointer dereference on SoundWire IRQ during removal gaggery.tsai
2026-03-12 15:08 ` gaggery.tsai [this message]
2026-03-20 20:34   ` [PATCH v2] " Pierre-Louis Bossart

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260312150837.2076641-1-gaggery.tsai@intel.com \
    --to=gaggery.tsai@intel.com \
    --cc=linux-drivers-review-request@eclists.intel.com \
    --cc=pierre-louis.bossart@linux.dev \
    --cc=ranjani.sridharan@linux.intel.com \
    --cc=stable@vger.kernel.org \
    --cc=yung-chuan.liao@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.