Skip to content

Commit fba2105

Browse files
committed
ALSA: usb-audio: Add sanity check for OOB writes at silencing
At silencing the playback URB packets in the implicit fb mode before the actual playback, we blindly assume that the received packets fit with the buffer size. But when the setup in the capture stream differs from the playback stream (e.g. due to the USB core limitation of max packet size), such an inconsistency may lead to OOB writes to the buffer, resulting in a crash. For addressing it, add a sanity check of the transfer buffer size at prepare_silent_urb(), and stop the data copy if the received data overflows. Also, report back the transfer error properly from there, too. Note that this doesn't fix the root cause of the playback error itself, but this merely covers the kernel Oops. Link: https://bugzilla.kernel.org/show_bug.cgi?id=221076 Link: https://patch.msgid.link/20260216141209.1849200-4-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent 36adb51 commit fba2105

1 file changed

Lines changed: 22 additions & 17 deletions

File tree

sound/usb/endpoint.c

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,8 @@ static inline bool has_tx_length_quirk(struct snd_usb_audio *chip)
275275
return chip->quirk_flags & QUIRK_FLAG_TX_LENGTH;
276276
}
277277

278-
static void prepare_silent_urb(struct snd_usb_endpoint *ep,
279-
struct snd_urb_ctx *ctx)
278+
static int prepare_silent_urb(struct snd_usb_endpoint *ep,
279+
struct snd_urb_ctx *ctx)
280280
{
281281
struct urb *urb = ctx->urb;
282282
unsigned int offs = 0;
@@ -289,28 +289,34 @@ static void prepare_silent_urb(struct snd_usb_endpoint *ep,
289289
extra = sizeof(packet_length);
290290

291291
for (i = 0; i < ctx->packets; ++i) {
292-
unsigned int offset;
293-
unsigned int length;
294-
int counts;
295-
296-
counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, 0);
297-
length = counts * ep->stride; /* number of silent bytes */
298-
offset = offs * ep->stride + extra * i;
299-
urb->iso_frame_desc[i].offset = offset;
292+
int length;
293+
294+
length = snd_usb_endpoint_next_packet_size(ep, ctx, i, 0);
295+
if (length < 0)
296+
return length;
297+
length *= ep->stride; /* number of silent bytes */
298+
if (offs + length + extra > ctx->buffer_size)
299+
break;
300+
urb->iso_frame_desc[i].offset = offs;
300301
urb->iso_frame_desc[i].length = length + extra;
301302
if (extra) {
302303
packet_length = cpu_to_le32(length);
303-
memcpy(urb->transfer_buffer + offset,
304+
memcpy(urb->transfer_buffer + offs,
304305
&packet_length, sizeof(packet_length));
306+
offs += extra;
305307
}
306-
memset(urb->transfer_buffer + offset + extra,
308+
memset(urb->transfer_buffer + offs,
307309
ep->silence_value, length);
308-
offs += counts;
310+
offs += length;
309311
}
310312

311-
urb->number_of_packets = ctx->packets;
312-
urb->transfer_buffer_length = offs * ep->stride + ctx->packets * extra;
313+
if (!offs)
314+
return -EPIPE;
315+
316+
urb->number_of_packets = i;
317+
urb->transfer_buffer_length = offs;
313318
ctx->queued = 0;
319+
return 0;
314320
}
315321

316322
/*
@@ -332,8 +338,7 @@ static int prepare_outbound_urb(struct snd_usb_endpoint *ep,
332338
if (data_subs && ep->prepare_data_urb)
333339
return ep->prepare_data_urb(data_subs, urb, in_stream_lock);
334340
/* no data provider, so send silence */
335-
prepare_silent_urb(ep, ctx);
336-
break;
341+
return prepare_silent_urb(ep, ctx);
337342

338343
case SND_USB_ENDPOINT_TYPE_SYNC:
339344
if (snd_usb_get_speed(ep->chip->dev) >= USB_SPEED_HIGH) {

0 commit comments

Comments
 (0)