From: Yaohan Li <shunsheng1218@gmail.com>
To: nkapron@google.com, gregkh@linuxfoundation.org
Cc: felipe.balbi@linux.intel.com, vladimir_zapolskiy@mentor.com,
linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH v2] usb: gadget: u_audio: call period elapsed under the stream lock
Date: Thu, 5 Nov 2026 19:43:09 +0800 [thread overview]
Message-ID: <20261105114309.970899-1-shunsheng1218@gmail.com> (raw)
u_audio_iso_complete() drops the substream stream lock before
calling snd_pcm_period_elapsed(), which re-acquires it internally.
Between the unlock and the re-acquire, a concurrent close can run
through snd_pcm_drop(), finish the PCM release and free the runtime,
leaving the period notification to dereference a freed runtime
(runtime->fasync in snd_pcm_period_elapsed()).
Keep the stream lock across the period notification and use
snd_pcm_period_elapsed_under_stream_lock(), the API for exactly this
caller-held-lock case, so the callback's runtime access happens
inside a single locked section.
On final PCM release, snd_pcm_drop() takes the stream lock before
runtime detachment: an in-flight completion holding that lock
finishes before STOP can proceed. The STOP trigger clears prm->ss,
so subsequent callbacks do not enter the running PCM path. Runtime
detachment happens later and is not itself protected by the stream
lock. On the gadget side, u_audio_stop_*() dequeues the requests
before the endpoint is freed.
KASAN reported the use-after-free in u_audio_iso_complete() on the
unmodified kernel. With the callback stalled inside the locked
section while a concurrent close ran, no use-after-free was reported
after this change.
This issue was investigated and the fix was developed with AI
assistance (ZCode/GLM-4).
Fixes: 773e53d50e227 ("usb: gadget: u_audio: remove cached period bytes value")
Signed-off-by: Yaohan Li <shunsheng1218@gmail.com>
---
Changes since v1:
- v1 saved the period size while the lock was held but still called
snd_pcm_period_elapsed() after dropping it, leaving the same
unlock/re-lock window open for the period notification itself.
This version keeps the stream lock across the notification using
snd_pcm_period_elapsed_under_stream_lock().
- Documented the synchronization this relies on: snd_pcm_drop()
takes the stream lock before runtime detachment, so an in-flight
completion holding the lock finishes first, and its STOP trigger
clears u_audio's prm->ss so later callbacks take the early exit.
Runtime detachment itself is not protected by the stream lock.
v1: https://lore.kernel.org/r/179378417544.69464.16164899430939223277@gmail.com/
drivers/usb/gadget/function/u_audio.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c
index f0ee83abcebc7..7da4032e3a203 100644
--- a/drivers/usb/gadget/function/u_audio.c
+++ b/drivers/usb/gadget/function/u_audio.c
@@ -156,6 +156,7 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
struct uac_rtd_params *prm = req->context;
struct snd_uac_chip *uac = prm->uac;
unsigned int frames, p_pktsize;
+ unsigned int period_bytes;
unsigned long long pitched_rate_mil, p_pktsize_residue_mil,
residue_frames_mil, div_result;
@@ -267,10 +268,12 @@ static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
/* update hw_ptr after data is copied to memory */
prm->hw_ptr = (hw_ptr + req->actual) % runtime->dma_bytes;
hw_ptr = prm->hw_ptr;
- snd_pcm_stream_unlock(substream);
+ period_bytes = snd_pcm_lib_period_bytes(substream);
+
+ if ((hw_ptr % period_bytes) < req->actual)
+ snd_pcm_period_elapsed_under_stream_lock(substream);
- if ((hw_ptr % snd_pcm_lib_period_bytes(substream)) < req->actual)
- snd_pcm_period_elapsed(substream);
+ snd_pcm_stream_unlock(substream);
exit:
if (usb_ep_queue(ep, req, GFP_ATOMIC))
base-commit: 6628e7d4c6b25c8d18f1345e3a20d21829aae7e4
--
2.34.1
reply other threads:[~2026-11-05 11:43 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20261105114309.970899-1-shunsheng1218@gmail.com \
--to=shunsheng1218@gmail.com \
--cc=felipe.balbi@linux.intel.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=nkapron@google.com \
--cc=vladimir_zapolskiy@mentor.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®