* [PATCH 0/2] ALSA: usb-audio, ua101: oversized packet copies overrun PCM ring buffers
@ 2026-10-26 0:10 x8svc
2026-10-26 0:10 ` [PATCH 1/2] ALSA: usb-audio: Bound packet copies by the PCM buffer size x8svc
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: x8svc @ 2026-10-26 0:10 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai, Clemens Ladisch; +Cc: linux-sound, linux-kernel
Hello,
I found ring-buffer overruns in snd-usb-audio and snd-ua101 when the
amount of data copied from or to an isochronous transfer exceeds the
ALSA PCM buffer size. The copy paths use a two-part memcpy() and a
position update that handle only one wrap, which is not enough when a
single packet is larger than the whole buffer.
I reproduced the overruns under KASAN on 7.3-rc7 (2f2f7eeef8b0) in
snd-usb-audio and snd-ua101, for capture and playback. The two patches
that follow apply to and build on current mainline (c03c1a14507d). I
found similar code in snd-usb-line6, snd-usb-usx2y and cx231xx-audio,
and reproduced them on 7.3-rc7. em28xx-audio has the same shape. I
booted it, and KASAN reported nothing. By reading, the
same shape is in 5.15.y, 6.1.y, 6.6.y, 6.12.y, 6.18.y and 7.2.y. I did
not boot those branches. 5.10.y has older code, which I have not
checked.
The reproducer is available to maintainers on request.
snd-usb-audio (sound/usb/pcm.c)
-------------------------------
retire_capture_urb() and copy_to_urb(), called from
prepare_playback_urb(), copy data across the ALSA ring buffer with a
two-part memcpy() and update the position with a single wrap:
subs->hwptr_done += bytes;
if (subs->hwptr_done >= subs->buffer_bytes)
subs->hwptr_done -= subs->buffer_bytes;
if (oldptr + bytes > subs->buffer_bytes) {
unsigned int bytes1 = subs->buffer_bytes - oldptr;
memcpy(runtime->dma_area + oldptr, cp, bytes1);
memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
}
Nothing in the path guarantees bytes <= buffer_bytes. The device sets
the packet size and the PCM client sets the buffer size.
setup_hw_info() permits 8 kHz mono U8 with a 128-byte buffer (64-byte
periods, two periods), and a full-speed endpoint can send 1023-byte
packets.
The first oversized capture packet already overruns the logical PCM
buffer: with oldptr = 0, the two-part copy writes 128 bytes and then
another 895 bytes at the start of the 128-byte buffer. It also leaves
hwptr_done at 895 (1023 - 128), beyond buffer_bytes. On the next
packet, bytes1 = 128 - 895 wraps to 4294966529, and memcpy() runs past
the URB buffer and the vmalloc'd DMA buffer.
For playback, copy_to_urb() has the same single-wrap assumption, and
the reproducer reaches an out-of-bounds read there as well.
KASAN reports (7.3-rc7, x86_64):
Capture:
snd-usb-audio 2-1:1.0: invalid position: , pos = 895, buffer size = 128, period size = 64
BUG: KASAN: slab-out-of-bounds in retire_capture_urb+0x251/0x870
Read of size 4294966529 at addr ffff88800c1e2800 by task vhci_rx/82
...
retire_capture_urb+0x251/0x870
snd_complete_urb
__usb_hcd_giveback_urb
vhci_rx_loop
Playback:
BUG: KASAN: vmalloc-out-of-bounds in copy_to_urb.isra.0+0x188/0x430
Read of size 4294966529 at addr ffffc9000004537f by task vhci_rx/79
...
prepare_playback_urb+0x98a/0x1fc0
The buggy address belongs to a 1-page vmalloc region starting at
0xffffc90000045000 allocated at __snd_dma_alloc_pages
On 6.19-rc3 the same reproducer faults in memcpy() from
retire_capture_urb() without KASAN (RDX = 0xfffffd01, the wrapped
bytes1).
The USB/IP server never reports an actual_length larger than the
requested packet: actual_length equals the URB's iso_frame_desc length
and curpacksize. I reproduced this through USB/IP only. I have not
tested a physical device or a physical host controller.
The local PCM client only needs permission to open the PCM device. My
reproducer runs as an unprivileged user in the audio group. I also
tested Fedora 42's PipeWire 1.4.11 with WirePlumber 0.5.14 and
PulseAudio 17.0 against the same USB/IP device:
- In the tested PipeWire configuration, the driver selects its maximum
buffer, capped at two seconds (16000 bytes for this stream).
Full-speed 1023-byte and high-speed 3072-byte packets fit. With a
super-speed device advertising wBytesPerInterval 49152, pw-record
hits retire_capture_urb() with a 33152-byte write (49152 - 16000)
and then faults at the vmalloc guard page. pw-play hits copy_to_urb()
with a 33152-byte read on PipeWire's data-loop.0 thread, and the
machine soft-locks.
- PulseAudio 17.0 inside this VM turns timer-based scheduling off by
itself. The measured buffer is four 25 ms fragments, 799 bytes, and
a full-speed 1023-byte capture packet reproduces the
retire_capture_urb() report. I did not measure timer-based scheduling
left on. The PulseAudio source uses a 2 second buffer in that case.
A client with permission to open the PCM device directly can trigger
the full- and high-speed cases by selecting a sufficiently small
buffer. The super-speed case reproduced in the tested PipeWire
configuration with an ordinary recording or playback application when
the emulated device was selected as the default device.
Reproducer
----------
I used USB/IP because I could not exercise this isochronous transfer
path with dummy_hcd and raw-gadget. The reproducer is available to
maintainers on request:
- usbip-server.py emulates a UAC1 microphone or, with --mode playback,
a speaker. It advertises a one-channel, 8-bit, 8000 Hz Type I stream
and a full-speed isochronous endpoint with wMaxPacketSize 1023 and
bmAttributes 0x80 (MaxPacketsOnly). Each packet is 1023 bytes.
- attach.c imports the device and attaches the socket to vhci-hcd
(CONFIG_USBIP_VHCI_HCD).
- client.c opens the PCM device with U8, one channel, 8000 Hz,
period_size 64 and two periods (buffer_bytes 128), sets
stop_threshold to LONG_MAX, and starts the stream. For playback it
first writes 128 bytes.
The fault occurs within a second of starting the stream in my tests.
Patch 1
-------
The snd-usb-audio patch bounds the capture packet copy by the PCM
buffer size and stops prepare_playback_urb() from scheduling more data
than the buffer can hold.
I tested it on 7.3-rc7 with the same reproducer for 30 seconds per
mode. KASAN reported nothing. Capture kept streaming and logged the
ratelimited truncation warning. Playback entered XRUN at once because
the buffer cannot hold a single packet, which is the safe failure for
such a device. With PipeWire and a super-speed device, capture
truncates the packet with the same warning and the stream keeps
running. I did not repeat the patched playback run with PipeWire.
Patch 2
-------
In snd-ua101 (sound/usb/misc/ua101.c), copy_capture_data() takes the
frame count from actual_length, and copy_playback_data() takes it from
the capture packets through rate_feedback. Both split the copy at the
end of the ring buffer and wrap the position once.
set_stream_hw() permits an 18-frame buffer: periods_min is 2 and the
period can be 9 frames. A 672-byte packet of one-channel, 24-bit audio
holds 224 frames. After the first packet the position is 206, which is
188 frames past the 18-frame buffer (224 - 18). On the next packet the
single-wrap calculation underflows.
KASAN reports in my tests:
snd-ua101 2-1:1.0: invalid position: , pos = 206, buffer size = 18, period size = 9
BUG: KASAN: slab-out-of-bounds in capture_urb_complete+0x9eb/0xcb0
Read of size 4294966732 at addr ffff88800d73e7e0 by task vhci_rx/81
BUG: KASAN: vmalloc-out-of-bounds in playback_work+0x789/0xac0
Read of size 4294966732 at addr ffffc9000002626a by task kworker/0:1H/80
The reproducer uses the same USB/IP server with --device ua101 to
present a UA-101 interface layout, and a client using S24_3LE, 44100
Hz, period_size 9 and one channel.
The patch clamps the capture copy to the buffer size. On playback it
copies at most one buffer and fills the rest of the packet with
silence, so the URB length, the delay accounting and the data sent stay
consistent. I first tried shortening the playback packet instead, but
that makes the URB's declared length disagree with its buffer and
USB/IP drops the device, so I kept the length. With the patch, capture
and playback each ran for 30 seconds without a KASAN report and the
streams kept advancing.
The period accounting still subtracts one period at a time, so a
packet spanning several periods of a tiny buffer leaves period_pos
above one period until later calls drain it. I did not see this cause
a problem in the runs, but I have not analysed it further and would
welcome your view.
Other drivers
--------------
snd-usb-line6, capture, on 7.3-rc7. A GuitarPort device sent 1024-byte
packets into a 128-byte buffer (S16_LE, 44100 Hz, 16 frames, 2 periods,
2 channels). ALSA logged:
snd_usb_toneport 2-1:1.0: invalid position: , pos = 224, buffer size = 32, period size = 16
KASAN reported nothing. The ring is a whole page, so the extra bytes of
the first copy stay inside that page. The driver then stopped copying
and logged "driver bug: len".
snd-usb-usx2y, capture, on the same tree. After the hwdep firmware
load, a US-122 device sent 1024-byte packets into a 512-byte buffer
(S16_LE, 44100 Hz, 64 frames, 2 periods, 2 channels). KASAN reported:
BUG: KASAN: out-of-bounds in i_usx2y_urb_complete+0x1285/0x1ac0
Read of size 18446744073709551104 at addr ffff88800e448800 by task vhci_rx/83
That read size is the single-wrap length once the position has passed
the buffer. These two patches do not change line6, usx2y, cx231xx
or em28xx.
cx231xx-audio, capture, on the same tree. A Pixelview Xcapture device
sent 1024-byte packets into a 128-byte buffer (S16_LE, 48000 Hz, 16
frames, 2 periods, 2 channels). KASAN reported:
BUG: KASAN: use-after-free in cx231xx_audio_isocirq+0x2c7/0x780
Read of size 4294966528 at addr ffff88800e8e0400 by task vhci_rx/82
ALSA logged pos = 224, buffer size = 32, period size = 16. That
position is one 256-frame packet minus the 32-frame buffer. The read
size is the single-wrap length once the position has passed the buffer.
em28xx-audio, capture, on the same tree. An em2860 device sent
3072-byte packets into a 24576-byte buffer (S16_LE, 48000 Hz, 3072
frames, 2 periods, 2 channels). The endpoint was 0x83, with 64 packets
per URB. Capture ran for 30 seconds. KASAN reported nothing.
period_bytes_min is 11059 and periods_min is 2, so the smallest buffer
is 22118 bytes. em28xx_audio_ep_packet_size() caps a high-speed
endpoint at 8188 bytes, so one packet cannot pass that buffer.
Process
-------
I understand this to fall under the regular-bug handling in
Documentation/process/threat-model.rst, because reproduction uses an
emulated USB device, so I am sending it to the subsystem list with the
proposed fixes. An AI tool helped with the analysis and the patches.
I reviewed and tested them myself.
Thanks,
x8svc
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/2] ALSA: usb-audio: Bound packet copies by the PCM buffer size
2026-10-26 0:10 [PATCH 0/2] ALSA: usb-audio, ua101: oversized packet copies overrun PCM ring buffers x8svc
@ 2026-10-26 0:10 ` x8svc
2026-10-26 0:10 ` [PATCH 2/2] ALSA: ua101: " x8svc
2026-10-26 8:08 ` [PATCH 0/2] ALSA: usb-audio, ua101: oversized packet copies overrun PCM ring buffers Takashi Iwai
2 siblings, 0 replies; 6+ messages in thread
From: x8svc @ 2026-10-26 0:10 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai, Clemens Ladisch
Cc: linux-sound, linux-kernel, stable
retire_capture_urb() and prepare_playback_urb() assume that one USB
packet never carries more data than the whole ALSA ring buffer. Nothing
enforces that: the packet size comes from the device (wMaxPacketSize,
and curpacksize == maxpacksize when the class-specific endpoint
descriptor sets MaxPacketsOnly), while the PCM hardware constraints only
require 64-byte periods, two periods and a period time of one data
interval. An 8 kHz mono U8 stream on a 128-byte buffer is legal, and a
full-speed device can send 1023-byte packets into it.
On the first oversized packet hwptr_done is wrapped once and stays
beyond buffer_bytes (895 for 1023 bytes into 128). On the next packet
the wrap arithmetic in the copy path computes
bytes1 = subs->buffer_bytes - oldptr
with oldptr > buffer_bytes, so bytes1 wraps to about 4 GB and memcpy()
runs off the end of the URB buffer and of the vmalloc'd DMA buffer:
BUG: KASAN: slab-out-of-bounds in retire_capture_urb+0x251/0x870
Read of size 4294966529 at addr ffff88800c1e2800 by task vhci_rx/82
and for playback, where copy_to_urb() has the same shape:
BUG: KASAN: vmalloc-out-of-bounds in copy_to_urb.isra.0+0x188/0x430
Read of size 4294966529 at addr ffffc9000004537f by task vhci_rx/79
prepare_playback_urb+0x98a/0x1fc0
Truncate an oversized capture packet to the buffer size, and stop
filling a playback URB once it holds a whole buffer. With bytes <=
buffer_bytes the single wrap of hwptr_done and the two-part memcpy()
in both copy paths stay inside the buffer. A device whose packets do
not fit the buffer at all was never going to play correctly anyway.
Reproduced on 7.3-rc7 with a USB/IP device (dummy_hcd cannot carry
isochronous data) advertising a UAC1 endpoint with MaxPacketsOnly and
wMaxPacketSize 1023, and a PCM client using period_size 64, periods 2.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: x8svc <enscrpt@pm.me>
---
sound/usb/pcm.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 682b6c1fe76..c2f7b08607a 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -1343,6 +1343,18 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
bytes -= adj;
subs->stream_offset_adj -= adj;
}
+ /*
+ * A packet can be as large as the endpoint's maxpacksize, which
+ * the device chooses, while the ring buffer can be as small as
+ * two 64-byte periods. The hwptr_done wrap below handles one
+ * wrap only, so never take more than one buffer from a packet.
+ */
+ if (unlikely(bytes > subs->buffer_bytes)) {
+ dev_warn_ratelimited(&subs->dev->dev,
+ "%u-byte packet exceeds %u-byte buffer, truncating\n",
+ bytes, subs->buffer_bytes);
+ bytes = subs->buffer_bytes;
+ }
frames = bytes / stride;
if (!subs->txfr_quirk)
bytes = frames * stride;
@@ -1553,8 +1565,14 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
for (i = 0; i < ctx->packets; i++) {
counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, avail);
+ /*
+ * Bound by the ring buffer as well as by the URB:
+ * copy_to_urb() wraps hwptr_done once, so one URB must
+ * never carry more than the whole buffer.
+ */
if (counts < 0 ||
- (frames + counts) * stride > ctx->buffer_size)
+ (frames + counts) * stride > ctx->buffer_size ||
+ (frames + counts) * stride > subs->buffer_bytes)
break;
/* set up descriptor */
urb->iso_frame_desc[i].offset = frames * stride;
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/2] ALSA: ua101: Bound packet copies by the PCM buffer size
2026-10-26 0:10 [PATCH 0/2] ALSA: usb-audio, ua101: oversized packet copies overrun PCM ring buffers x8svc
2026-10-26 0:10 ` [PATCH 1/2] ALSA: usb-audio: Bound packet copies by the PCM buffer size x8svc
@ 2026-10-26 0:10 ` x8svc
2026-10-26 8:08 ` [PATCH 0/2] ALSA: usb-audio, ua101: oversized packet copies overrun PCM ring buffers Takashi Iwai
2 siblings, 0 replies; 6+ messages in thread
From: x8svc @ 2026-10-26 0:10 UTC (permalink / raw)
To: Jaroslav Kysela, Takashi Iwai, Clemens Ladisch
Cc: linux-sound, linux-kernel, stable
copy_capture_data() and copy_playback_data() wrap the ring buffer
position once and split the memcpy() in two at the buffer end, which is
only correct when one packet holds at most buffer_size frames. The
capture packet size is the device's (actual_length up to wMaxPacketSize,
divided by 3 * bNrChannels from its own descriptor), the playback packet
size is taken from the capture packets, and set_stream_hw() lets the
PCM client pick period_bytes_min 1, periods_min 2 and a period time of
1.5 packet intervals: 9 frames at 44.1 kHz high speed, an 18-frame
buffer. A device sending 672-byte mono 24-bit packets delivers 224
frames per packet.
After the first packet buffer_pos is 206 and stays beyond buffer_size.
On the next packet frames1 = buffer_size - buffer_pos wraps and memcpy()
runs away:
snd-ua101 2-1:1.0: invalid position: , pos = 206, buffer size = 18,
period size = 9
BUG: KASAN: slab-out-of-bounds in capture_urb_complete+0x9eb/0xcb0
Read of size 4294966732 at addr ffff88800d73e7e0 by task vhci_rx/81
and for playback:
BUG: KASAN: vmalloc-out-of-bounds in playback_work+0x789/0xac0
Read of size 4294966732 at addr ffffc9000002626a by task kworker/0:1H/80
Clamp the capture copy to buffer_size. On playback, copy at most one
buffer and fill the rest of the packet with silence, so the URB length,
the delay accounting and the data sent stay consistent. With that bound
the single wrap and both memcpy() halves stay inside the buffer. A
device whose packets do not fit the buffer never played correctly
anyway.
Reproduced on 7.3-rc7 with a USB/IP device presenting the UA-101
interface layout and a 672-byte isochronous endpoint.
Fixes: 63978ab3e3e9 ("sound: add Edirol UA-101 support")
Cc: stable@vger.kernel.org
Signed-off-by: x8svc <enscrpt@pm.me>
---
sound/usb/misc/ua101.c | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)
diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index 58d8a3cdc8b9..bd8e0ed0ba5d 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -285,13 +285,29 @@ static void playback_work(struct work_struct *work)
/* fill packet with data or silence */
urb->iso_frame_desc[0].length =
frames * ua->playback.frame_bytes;
- if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states))
+ if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) {
+ /*
+ * The packet size comes from the capture stream,
+ * i.e. from the device, while the ring buffer can
+ * be as small as two tiny periods. The single wrap
+ * in copy_playback_data() is only valid for
+ * frames <= buffer_size, so copy at most one
+ * buffer and send silence for the rest.
+ */
+ unsigned int copy_frames = min(frames,
+ ua->playback.substream->runtime->buffer_size);
+
do_period_elapsed |= copy_playback_data(&ua->playback,
urb,
- frames);
- else
+ copy_frames);
+ memset(urb->transfer_buffer +
+ copy_frames * ua->playback.frame_bytes, 0,
+ (frames - copy_frames) *
+ ua->playback.frame_bytes);
+ } else {
memset(urb->transfer_buffer, 0,
urb->iso_frame_desc[0].length);
+ }
/* and off you go ... */
err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -320,6 +336,13 @@ static bool copy_capture_data(struct ua101_stream *stream, struct urb *urb,
runtime = stream->substream->runtime;
frame_bytes = stream->frame_bytes;
+ /*
+ * A packet can carry up to max_packet_bytes, the device's
+ * wMaxPacketSize, which may exceed the whole ring buffer; keep what
+ * fits so the single wrap below stays valid.
+ */
+ if (unlikely(frames > runtime->buffer_size))
+ frames = runtime->buffer_size;
dest = runtime->dma_area + stream->buffer_pos * frame_bytes;
if (stream->buffer_pos + frames <= runtime->buffer_size) {
memcpy(dest, urb->transfer_buffer, frames * frame_bytes);
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 0/2] ALSA: usb-audio, ua101: oversized packet copies overrun PCM ring buffers
2026-10-26 0:10 [PATCH 0/2] ALSA: usb-audio, ua101: oversized packet copies overrun PCM ring buffers x8svc
2026-10-26 0:10 ` [PATCH 1/2] ALSA: usb-audio: Bound packet copies by the PCM buffer size x8svc
2026-10-26 0:10 ` [PATCH 2/2] ALSA: ua101: " x8svc
@ 2026-10-26 8:08 ` Takashi Iwai
2026-10-26 12:30 ` x8svc
2 siblings, 1 reply; 6+ messages in thread
From: Takashi Iwai @ 2026-10-26 8:08 UTC (permalink / raw)
To: x8svc
Cc: Jaroslav Kysela, Takashi Iwai, Clemens Ladisch, linux-sound,
linux-kernel
On Mon, 26 Oct 2026 01:10:37 +0100,
x8svc wrote:
>
> Hello,
>
> I found ring-buffer overruns in snd-usb-audio and snd-ua101 when the
> amount of data copied from or to an isochronous transfer exceeds the
> ALSA PCM buffer size. The copy paths use a two-part memcpy() and a
> position update that handle only one wrap, which is not enough when a
> single packet is larger than the whole buffer.
>
> I reproduced the overruns under KASAN on 7.3-rc7 (2f2f7eeef8b0) in
> snd-usb-audio and snd-ua101, for capture and playback. The two patches
> that follow apply to and build on current mainline (c03c1a14507d). I
> found similar code in snd-usb-line6, snd-usb-usx2y and cx231xx-audio,
> and reproduced them on 7.3-rc7. em28xx-audio has the same shape. I
> booted it, and KASAN reported nothing. By reading, the
> same shape is in 5.15.y, 6.1.y, 6.6.y, 6.12.y, 6.18.y and 7.2.y. I did
> not boot those branches. 5.10.y has older code, which I have not
> checked.
>
> The reproducer is available to maintainers on request.
>
> snd-usb-audio (sound/usb/pcm.c)
> -------------------------------
>
> retire_capture_urb() and copy_to_urb(), called from
> prepare_playback_urb(), copy data across the ALSA ring buffer with a
> two-part memcpy() and update the position with a single wrap:
>
> subs->hwptr_done += bytes;
> if (subs->hwptr_done >= subs->buffer_bytes)
> subs->hwptr_done -= subs->buffer_bytes;
>
> if (oldptr + bytes > subs->buffer_bytes) {
> unsigned int bytes1 = subs->buffer_bytes - oldptr;
> memcpy(runtime->dma_area + oldptr, cp, bytes1);
> memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
> }
>
> Nothing in the path guarantees bytes <= buffer_bytes. The device sets
> the packet size and the PCM client sets the buffer size.
> setup_hw_info() permits 8 kHz mono U8 with a 128-byte buffer (64-byte
> periods, two periods), and a full-speed endpoint can send 1023-byte
> packets.
>
> The first oversized capture packet already overruns the logical PCM
> buffer: with oldptr = 0, the two-part copy writes 128 bytes and then
> another 895 bytes at the start of the 128-byte buffer. It also leaves
> hwptr_done at 895 (1023 - 128), beyond buffer_bytes. On the next
> packet, bytes1 = 128 - 895 wraps to 4294966529, and memcpy() runs past
> the URB buffer and the vmalloc'd DMA buffer.
>
> For playback, copy_to_urb() has the same single-wrap assumption, and
> the reproducer reaches an out-of-bounds read there as well.
>
> KASAN reports (7.3-rc7, x86_64):
>
> Capture:
>
> snd-usb-audio 2-1:1.0: invalid position: , pos = 895, buffer size = 128, period size = 64
> BUG: KASAN: slab-out-of-bounds in retire_capture_urb+0x251/0x870
> Read of size 4294966529 at addr ffff88800c1e2800 by task vhci_rx/82
> ...
> retire_capture_urb+0x251/0x870
> snd_complete_urb
> __usb_hcd_giveback_urb
> vhci_rx_loop
>
> Playback:
>
> BUG: KASAN: vmalloc-out-of-bounds in copy_to_urb.isra.0+0x188/0x430
> Read of size 4294966529 at addr ffffc9000004537f by task vhci_rx/79
> ...
> prepare_playback_urb+0x98a/0x1fc0
> The buggy address belongs to a 1-page vmalloc region starting at
> 0xffffc90000045000 allocated at __snd_dma_alloc_pages
>
> On 6.19-rc3 the same reproducer faults in memcpy() from
> retire_capture_urb() without KASAN (RDX = 0xfffffd01, the wrapped
> bytes1).
>
> The USB/IP server never reports an actual_length larger than the
> requested packet: actual_length equals the URB's iso_frame_desc length
> and curpacksize. I reproduced this through USB/IP only. I have not
> tested a physical device or a physical host controller.
>
> The local PCM client only needs permission to open the PCM device. My
> reproducer runs as an unprivileged user in the audio group. I also
> tested Fedora 42's PipeWire 1.4.11 with WirePlumber 0.5.14 and
> PulseAudio 17.0 against the same USB/IP device:
>
> - In the tested PipeWire configuration, the driver selects its maximum
> buffer, capped at two seconds (16000 bytes for this stream).
> Full-speed 1023-byte and high-speed 3072-byte packets fit. With a
> super-speed device advertising wBytesPerInterval 49152, pw-record
> hits retire_capture_urb() with a 33152-byte write (49152 - 16000)
> and then faults at the vmalloc guard page. pw-play hits copy_to_urb()
> with a 33152-byte read on PipeWire's data-loop.0 thread, and the
> machine soft-locks.
> - PulseAudio 17.0 inside this VM turns timer-based scheduling off by
> itself. The measured buffer is four 25 ms fragments, 799 bytes, and
> a full-speed 1023-byte capture packet reproduces the
> retire_capture_urb() report. I did not measure timer-based scheduling
> left on. The PulseAudio source uses a 2 second buffer in that case.
>
> A client with permission to open the PCM device directly can trigger
> the full- and high-speed cases by selecting a sufficiently small
> buffer. The super-speed case reproduced in the tested PipeWire
> configuration with an ordinary recording or playback application when
> the emulated device was selected as the default device.
>
> Reproducer
> ----------
>
> I used USB/IP because I could not exercise this isochronous transfer
> path with dummy_hcd and raw-gadget. The reproducer is available to
> maintainers on request:
>
> - usbip-server.py emulates a UAC1 microphone or, with --mode playback,
> a speaker. It advertises a one-channel, 8-bit, 8000 Hz Type I stream
> and a full-speed isochronous endpoint with wMaxPacketSize 1023 and
> bmAttributes 0x80 (MaxPacketsOnly). Each packet is 1023 bytes.
> - attach.c imports the device and attaches the socket to vhci-hcd
> (CONFIG_USBIP_VHCI_HCD).
> - client.c opens the PCM device with U8, one channel, 8000 Hz,
> period_size 64 and two periods (buffer_bytes 128), sets
> stop_threshold to LONG_MAX, and starts the stream. For playback it
> first writes 128 bytes.
>
> The fault occurs within a second of starting the stream in my tests.
>
> Patch 1
> -------
>
> The snd-usb-audio patch bounds the capture packet copy by the PCM
> buffer size and stops prepare_playback_urb() from scheduling more data
> than the buffer can hold.
>
> I tested it on 7.3-rc7 with the same reproducer for 30 seconds per
> mode. KASAN reported nothing. Capture kept streaming and logged the
> ratelimited truncation warning. Playback entered XRUN at once because
> the buffer cannot hold a single packet, which is the safe failure for
> such a device. With PipeWire and a super-speed device, capture
> truncates the packet with the same warning and the stream keeps
> running. I did not repeat the patched playback run with PipeWire.
>
> Patch 2
> -------
>
> In snd-ua101 (sound/usb/misc/ua101.c), copy_capture_data() takes the
> frame count from actual_length, and copy_playback_data() takes it from
> the capture packets through rate_feedback. Both split the copy at the
> end of the ring buffer and wrap the position once.
>
> set_stream_hw() permits an 18-frame buffer: periods_min is 2 and the
> period can be 9 frames. A 672-byte packet of one-channel, 24-bit audio
> holds 224 frames. After the first packet the position is 206, which is
> 188 frames past the 18-frame buffer (224 - 18). On the next packet the
> single-wrap calculation underflows.
>
> KASAN reports in my tests:
>
> snd-ua101 2-1:1.0: invalid position: , pos = 206, buffer size = 18, period size = 9
> BUG: KASAN: slab-out-of-bounds in capture_urb_complete+0x9eb/0xcb0
> Read of size 4294966732 at addr ffff88800d73e7e0 by task vhci_rx/81
>
> BUG: KASAN: vmalloc-out-of-bounds in playback_work+0x789/0xac0
> Read of size 4294966732 at addr ffffc9000002626a by task kworker/0:1H/80
>
> The reproducer uses the same USB/IP server with --device ua101 to
> present a UA-101 interface layout, and a client using S24_3LE, 44100
> Hz, period_size 9 and one channel.
>
> The patch clamps the capture copy to the buffer size. On playback it
> copies at most one buffer and fills the rest of the packet with
> silence, so the URB length, the delay accounting and the data sent stay
> consistent. I first tried shortening the playback packet instead, but
> that makes the URB's declared length disagree with its buffer and
> USB/IP drops the device, so I kept the length. With the patch, capture
> and playback each ran for 30 seconds without a KASAN report and the
> streams kept advancing.
>
> The period accounting still subtracts one period at a time, so a
> packet spanning several periods of a tiny buffer leaves period_pos
> above one period until later calls drain it. I did not see this cause
> a problem in the runs, but I have not analysed it further and would
> welcome your view.
>
> Other drivers
> --------------
>
> snd-usb-line6, capture, on 7.3-rc7. A GuitarPort device sent 1024-byte
> packets into a 128-byte buffer (S16_LE, 44100 Hz, 16 frames, 2 periods,
> 2 channels). ALSA logged:
>
> snd_usb_toneport 2-1:1.0: invalid position: , pos = 224, buffer size = 32, period size = 16
>
> KASAN reported nothing. The ring is a whole page, so the extra bytes of
> the first copy stay inside that page. The driver then stopped copying
> and logged "driver bug: len".
>
> snd-usb-usx2y, capture, on the same tree. After the hwdep firmware
> load, a US-122 device sent 1024-byte packets into a 512-byte buffer
> (S16_LE, 44100 Hz, 64 frames, 2 periods, 2 channels). KASAN reported:
>
> BUG: KASAN: out-of-bounds in i_usx2y_urb_complete+0x1285/0x1ac0
> Read of size 18446744073709551104 at addr ffff88800e448800 by task vhci_rx/83
>
> That read size is the single-wrap length once the position has passed
> the buffer. These two patches do not change line6, usx2y, cx231xx
> or em28xx.
>
> cx231xx-audio, capture, on the same tree. A Pixelview Xcapture device
> sent 1024-byte packets into a 128-byte buffer (S16_LE, 48000 Hz, 16
> frames, 2 periods, 2 channels). KASAN reported:
>
> BUG: KASAN: use-after-free in cx231xx_audio_isocirq+0x2c7/0x780
> Read of size 4294966528 at addr ffff88800e8e0400 by task vhci_rx/82
>
> ALSA logged pos = 224, buffer size = 32, period size = 16. That
> position is one 256-frame packet minus the 32-frame buffer. The read
> size is the single-wrap length once the position has passed the buffer.
>
> em28xx-audio, capture, on the same tree. An em2860 device sent
> 3072-byte packets into a 24576-byte buffer (S16_LE, 48000 Hz, 3072
> frames, 2 periods, 2 channels). The endpoint was 0x83, with 64 packets
> per URB. Capture ran for 30 seconds. KASAN reported nothing.
> period_bytes_min is 11059 and periods_min is 2, so the smallest buffer
> is 22118 bytes. em28xx_audio_ep_packet_size() caps a high-speed
> endpoint at 8188 bytes, so one packet cannot pass that buffer.
>
> Process
> -------
>
> I understand this to fall under the regular-bug handling in
> Documentation/process/threat-model.rst, because reproduction uses an
> emulated USB device, so I am sending it to the subsystem list with the
> proposed fixes. An AI tool helped with the analysis and the patches.
> I reviewed and tested them myself.
Through a quick glance, the code changes look OK. But, could you give
a proper Signed-off-by tag (and the corresponding From tag) with a
real name (or a known identity) and resubmit? Signed-off-by is a
legal requirement for upstreaming.
thanks,
Takashi
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 0/2] ALSA: usb-audio, ua101: oversized packet copies overrun PCM ring buffers
2026-10-26 8:08 ` [PATCH 0/2] ALSA: usb-audio, ua101: oversized packet copies overrun PCM ring buffers Takashi Iwai
@ 2026-10-26 12:30 ` x8svc
2026-10-26 13:38 ` Takashi Iwai
0 siblings, 1 reply; 6+ messages in thread
From: x8svc @ 2026-10-26 12:30 UTC (permalink / raw)
To: Takashi Iwai; +Cc: Jaroslav Kysela, Clemens Ladisch, linux-sound, linux-kernel
Takashi,
Thanks for the review.
x8svc is my standing identity, not a name picked for this one patch. The same
name signs every commit I push and is the account behind my public GitHub
work; I expect to keep using it for any future kernel submissions too.
Both patches already carry matching From and Signed-off-by lines
(x8svc <enscrpt@pm.me>), so unless there's something more specific you need
to treat it as a known identity, I'd rather not resubmit for no reason. Let
me know if that's enough, or what else you need.
Thanks,
x8svc
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 0/2] ALSA: usb-audio, ua101: oversized packet copies overrun PCM ring buffers
2026-10-26 12:30 ` x8svc
@ 2026-10-26 13:38 ` Takashi Iwai
0 siblings, 0 replies; 6+ messages in thread
From: Takashi Iwai @ 2026-10-26 13:38 UTC (permalink / raw)
To: x8svc
Cc: Takashi Iwai, Jaroslav Kysela, Clemens Ladisch, linux-sound,
linux-kernel
On Mon, 26 Oct 2026 13:30:07 +0100,
x8svc wrote:
>
> Takashi,
>
> Thanks for the review.
>
> x8svc is my standing identity, not a name picked for this one patch. The same
> name signs every commit I push and is the account behind my public GitHub
> work; I expect to keep using it for any future kernel submissions too.
Honestly speaking, I don't care about github activity at all. The
only question is the activity in the kernel community, and I don't see
any of such until now?
> Both patches already carry matching From and Signed-off-by lines
> (x8svc <enscrpt@pm.me>), so unless there's something more specific you need
> to treat it as a known identity, I'd rather not resubmit for no reason. Let
> me know if that's enough, or what else you need.
The Signed-off-by is the only concern.
thanks,
Takashi
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-26 13:38 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-26 0:10 [PATCH 0/2] ALSA: usb-audio, ua101: oversized packet copies overrun PCM ring buffers x8svc
2026-10-26 0:10 ` [PATCH 1/2] ALSA: usb-audio: Bound packet copies by the PCM buffer size x8svc
2026-10-26 0:10 ` [PATCH 2/2] ALSA: ua101: " x8svc
2026-10-26 8:08 ` [PATCH 0/2] ALSA: usb-audio, ua101: oversized packet copies overrun PCM ring buffers Takashi Iwai
2026-10-26 12:30 ` x8svc
2026-10-26 13:38 ` Takashi Iwai
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®