From: sashiko-bot@kernel.org
To: "Xu Yang" <xu.yang_2@oss.nxp.com>
Cc: Frank.Li@kernel.org, imx@lists.linux.dev
Subject: Re: [PATCH] usb: gadget: f_uac1_legacy: fix inverted NULL check after kstrndup()
Date: Thu, 25 Jun 2026 11:40:31 +0000 [thread overview]
Message-ID: <20260625114032.7585B1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260625113154.1954813-1-xu.yang_2@oss.nxp.com>
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing workqueue cancellation and queue cleanup before freeing `audio` context.
- [High] Unbounded memory leak of `usb_request` objects and buffers upon alternate setting changes.
- [High] Improper handling of `f_audio_buffer_alloc` failure leads to subsequent UAF or ERR_PTR dereference.
- [High] `audio->copy_buf` is not cleared when queued on `alt=0`, causing double list additions.
- [High] The playback workqueue only processes one buffer per run, stranding/leaking buffers.
- [High] A 1-byte out-of-bounds write of a NUL byte occurs in `f_uac1_opts_##name##_show` when reading a string attribute of maximum length.
--
commit 1d07b1a645b0a1199b66ed32d3217e953cef8087
Author: Xu Yang <xu.yang_2@nxp.com>
Date: Thu Jun 25 11:31:54 2026 +0000
usb: gadget: f_uac1_legacy: fix inverted NULL check after kstrndup()
This patch fixes an inverted NULL check on the result of kstrndup() in
f_uac1_opts_##name##_store(). The original code treated a successful
allocation as an error and would return -ENOMEM while proceeding with a
NULL pointer on failure.
> diff --git a/drivers/usb/gadget/function/f_uac1_legacy.c b/drivers/usb/gadget/function/f_uac1_legacy.c
> index 5d201a2e30e7f..e9f2632ce7852 100644
> --- a/drivers/usb/gadget/function/f_uac1_legacy.c
> +++ b/drivers/usb/gadget/function/f_uac1_legacy.c
> @@ -914,7 +914,7 @@ static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \
> goto end; \
> \
> tmp = kstrndup(page, len, GFP_KERNEL); \
> - if (tmp) { \
> + if (!tmp) { \
> ret = -ENOMEM; \
> goto end; \
> } \
[Severity: High]
This is a pre-existing issue, but does f_uac1_opts_##name##_show() have an
out-of-bounds write here?
drivers/usb/gadget/function/f_uac1_legacy.c:UAC1_STR_ATTRIBUTE() {
...
static ssize_t f_uac1_opts_##name##_show(struct config_item *item, \
char *page) \
{ \
...
result = sprintf(page, "%s\n", opts->name); \
...
}
If a user writes an attribute of exactly 4095 bytes, kstrndup stores it with
a length of 4095. During a subsequent read, sprintf() writes the 4095
characters, appends a newline (byte 4096), and then writes the NUL terminator
at index 4096, which overflows the 4096-byte page allocation by 1 byte.
Could this use sysfs_emit() or scnprintf() instead?
[Severity: High]
This is a pre-existing issue, but does f_audio_free() leak resources or cause
a use-after-free?
drivers/usb/gadget/function/f_uac1_legacy.c:f_audio_free() {
...
static void f_audio_free(struct usb_function *f)
{
struct f_audio *audio = func_to_audio(f);
struct f_uac1_legacy_opts *opts;
gaudio_cleanup(&audio->card);
opts = container_of(f->fi, struct f_uac1_legacy_opts, func_inst);
kfree(audio);
...
}
The audio structure is freed without cancelling the asynchronous
audio->playback_work or draining audio->play_queue. If the workqueue is
pending or executing, it will dereference the freed audio object. Any
elements left in the queue are also leaked.
[Severity: High]
This is a pre-existing issue, but does f_audio_set_alt() leak usb_request
objects and buffers?
drivers/usb/gadget/function/f_uac1_legacy.c:f_audio_set_alt() {
...
for (i = 0; i < req_count && err == 0; i++) {
req = usb_ep_alloc_request(out_ep, GFP_ATOMIC);
if (req) {
req->buf = kzalloc(req_buf_size,
GFP_ATOMIC);
...
}
When the interface is set to alt == 1, requests and buffers are dynamically
allocated. However, when the host stops the stream by switching to alt == 0,
these are never freed. Repeated toggling of the alternate setting could
quickly exhaust system memory.
[Severity: High]
This is a pre-existing issue, but does f_audio_out_ep_complete() improperly
handle f_audio_buffer_alloc() failures?
drivers/usb/gadget/function/f_uac1_legacy.c:f_audio_out_ep_complete() {
...
schedule_work(&audio->playback_work);
copy_buf = f_audio_buffer_alloc(audio_buf_size);
if (IS_ERR(copy_buf))
return -ENOMEM;
}
memcpy(copy_buf->buf + copy_buf->actual, req->buf, req->actual);
...
}
If f_audio_buffer_alloc() fails, it returns -ENOMEM immediately, but
audio->copy_buf is left pointing to the old buffer that was just queued for
playback. A subsequent completion would write to this old buffer, potentially
causing a use-after-free.
[Severity: High]
This is a pre-existing issue, but does f_audio_set_alt() incorrectly leave
audio->copy_buf populated when queued?
drivers/usb/gadget/function/f_uac1_legacy.c:f_audio_set_alt() {
...
} else {
struct f_audio_buf *copy_buf = audio->copy_buf;
if (copy_buf) {
list_add_tail(©_buf->list,
&audio->play_queue);
schedule_work(&audio->playback_work);
}
}
...
}
The copy_buf is added to the play_queue, but audio->copy_buf is not cleared.
If the host issues consecutive SET_INTERFACE 0 requests, the driver will
attempt to add the same buffer to the list again, which corrupts the
doubly-linked list.
[Severity: High]
This is a pre-existing issue, but does the playback workqueue strand buffers in
the play queue?
drivers/usb/gadget/function/f_uac1_legacy.c:f_audio_playback_work() {
...
spin_lock_irq(&audio->lock);
if (list_empty(&audio->play_queue)) {
spin_unlock_irq(&audio->lock);
return;
}
play_buf = list_first_entry(&audio->play_queue,
struct f_audio_buf, list);
list_del(&play_buf->list);
spin_unlock_irq(&audio->lock);
...
}
The work item pulls and processes exactly one buffer per execution. If
f_audio_out_ep_complete() adds multiple buffers quickly, schedule_work() may
coalesce the work items. Since there is no while(!list_empty()) loop, any
coalesced buffers are left stranded in the queue, leaking them when the stream
stops.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260625113154.1954813-1-xu.yang_2@oss.nxp.com?part=1
next prev parent reply other threads:[~2026-06-25 11:40 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-25 11:31 [PATCH] usb: gadget: f_uac1_legacy: fix inverted NULL check after kstrndup() Xu Yang
2026-06-25 11:40 ` sashiko-bot [this message]
2026-06-25 12:15 ` Frank Li
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=20260625114032.7585B1F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=Frank.Li@kernel.org \
--cc=imx@lists.linux.dev \
--cc=sashiko-reviews@lists.linux.dev \
--cc=xu.yang_2@oss.nxp.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.