From: sashiko-bot@kernel.org
To: "Sinan Turunc" <enscrpt@pm.me>
Cc: linux-sound@vger.kernel.org
Subject: Re: [PATCH v3 2/2] ALSA: usx2y: Guard the playback copy
Date: Wed, 04 Nov 2026 11:02:48 +0000 [thread overview]
Message-ID: <sashiko-outbox-197138@kernel.org> (raw)
In-Reply-To: <20261104105228.1124-3-enscrpt@pm.me>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] ALSA: usx2y: incomplete packet length validation in usx2y_urb_play_prepare()
--
commit 8f4cd6a52f3d49a81dfc6755062eeb7276e1ee4b
Author: Sinan Turunc <enscrpt@pm.me>
ALSA: usx2y: Guard the playback copy
This commit adds bounds checks in usx2y_urb_play_prepare() to verify that each
packet fits within the playback endpoint's maxpacksize and that the total URB
frame count does not exceed the ring buffer size, returning -EPIPE on a
violation.
> diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
> index ee224b4dfb046..5f241d454012f 100644
> --- a/sound/usb/usx2y/usbusx2yaudio.c
> +++ b/sound/usb/usx2y/usbusx2yaudio.c
> @@ -112,7 +112,8 @@ static int usx2y_urb_play_prepare(struct snd_usx2y_substream *subs,
> /* calculate the size of a packet */
> counts = cap_urb->iso_frame_desc[pack].actual_length / usx2y->stride;
> count += counts;
> - if (counts < 43 || counts > 50) {
> + if (counts < 43 || counts > 50 ||
> + counts * usx2y->stride > subs->maxpacksize) {
> dev_err(&usx2y->dev->dev, "%s: should not be here with counts=%i\n",
> __func__, counts);
> return -EPIPE;
> @@ -125,6 +126,16 @@ static int usx2y_urb_play_prepare(struct snd_usx2y_substream *subs,
> urb->iso_frame_desc[pack].length = cap_urb->iso_frame_desc[pack].actual_length;
[Severity: High]
What happens in usx2y_urb_play_prepare() in sound/usb/usx2y/usbusx2yaudio.c
when i_usx2y_urb_complete() -> usx2y_usbframe_complete() ->
usx2y_urb_play_prepare() -> usx2y_urb_submit() processes a capture URB whose
cap_urb->iso_frame_desc[pack].actual_length is not a multiple of
usx2y->stride?
Because counts is computed via truncating integer division:
counts = cap_urb->iso_frame_desc[pack].actual_length / usx2y->stride;
any remainder actual_length % usx2y->stride is discarded from counts, and the
new guard only checks the truncated byte count counts * usx2y->stride against
subs->maxpacksize. However, the playback ISO descriptor offsets and lengths
are still populated from the untruncated actual_length:
urb->iso_frame_desc[pack].offset = pack ?
urb->iso_frame_desc[pack - 1].offset +
urb->iso_frame_desc[pack - 1].length :
0;
urb->iso_frame_desc[pack].length = cap_urb->iso_frame_desc[pack].actual_length;
Meanwhile, the ring-buffer wrap check, the memcpy() into subs->tmpbuf, the
non-wrapping pointer slice into runtime->dma_area, and
urb->transfer_buffer_length all account for only count * usx2y->stride bytes:
} else {
/* set the buffer pointer */
urb->transfer_buffer = runtime->dma_area + subs->hwptr * usx2y->stride;
subs->hwptr += count;
if (subs->hwptr >= runtime->buffer_size)
subs->hwptr -= runtime->buffer_size;
}
} else {
urb->transfer_buffer = subs->tmpbuf;
}
urb->transfer_buffer_length = count * usx2y->stride;
If actual_length has a non-zero remainder modulo usx2y->stride, can this still
read past the end of subs->tmpbuf or runtime->dma_area? For example:
1. When counts * usx2y->stride == subs->maxpacksize and actual_length has
trailing remainder bytes (such as stride = 4, subs->maxpacksize = 200, and
actual_length = 203, giving counts = 50), counts * usx2y->stride >
subs->maxpacksize does not trigger, so urb->iso_frame_desc[pack].length
(203) exceeds subs->maxpacksize (200) and the cumulative ISO descriptors
across nr_of_packs() packets exceed the subs->tmpbuf allocation of
nr_of_packs() * subs->maxpacksize.
2. Even when actual_length <= subs->maxpacksize (such as stride = 4,
subs->maxpacksize = 200, and actual_length = 195, giving counts = 48 and
counts * stride = 192), the ISO descriptors in urb->iso_frame_desc[] span
more bytes than urb->transfer_buffer_length. When subs->hwptr + count ==
runtime->buffer_size in the non-wrapping branch, only count * usx2y->stride
bytes remain before the end of runtime->dma_area, so the ISO descriptors
extend past the end of runtime->dma_area.
Should usx2y_urb_play_prepare() either size urb->iso_frame_desc[pack].length
as counts * usx2y->stride or reject packets where actual_length is not aligned
to usx2y->stride?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261104105228.1124-1-enscrpt@pm.me?part=2
next prev parent reply other threads:[~2026-11-04 11:02 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-04 10:52 [PATCH v3 0/2] ALSA: usx2y: Bound the PCM buffer by the URB size Sinan Turunc
2026-11-04 10:52 ` [PATCH v3 1/2] ALSA: usx2y: Require a buffer of two URBs Sinan Turunc
2026-11-04 10:52 ` [PATCH v3 2/2] ALSA: usx2y: Guard the playback copy Sinan Turunc
2026-11-04 11:02 ` sashiko-bot [this message]
2026-11-04 12:21 ` Sinan Turunc
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=sashiko-outbox-197138@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=enscrpt@pm.me \
--cc=linux-sound@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/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.