Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: gadget: f_uac1_legacy: validate control request size

f_audio_complete() copies req->length bytes into a 4-byte stack
variable:

u32 data = 0;
memcpy(&data, req->buf, req->length);

req->length is derived from the host-controlled USB request path,
which can lead to a stack out-of-bounds write.

Validate req->actual against the expected payload size for the
supported control selectors and decode only the expected amount
of data.

This avoids copying a host-influenced length into a fixed-size
stack object.

Signed-off-by: Taegu Ha <hataegu0826@gmail.com>
Cc: stable <stable@kernel.org>
Link: https://patch.msgid.link/20260401191311.3604898-1-hataegu0826@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Taegu Ha and committed by
Greg Kroah-Hartman
6e0e34d8 01af5423

+37 -10
+37 -10
drivers/usb/gadget/function/f_uac1_legacy.c
··· 360 360 static void f_audio_complete(struct usb_ep *ep, struct usb_request *req) 361 361 { 362 362 struct f_audio *audio = req->context; 363 - int status = req->status; 364 - u32 data = 0; 365 363 struct usb_ep *out_ep = audio->out_ep; 366 364 367 - switch (status) { 368 - 369 - case 0: /* normal completion? */ 370 - if (ep == out_ep) 365 + switch (req->status) { 366 + case 0: 367 + if (ep == out_ep) { 371 368 f_audio_out_ep_complete(ep, req); 372 - else if (audio->set_con) { 373 - memcpy(&data, req->buf, req->length); 374 - audio->set_con->set(audio->set_con, audio->set_cmd, 375 - le16_to_cpu(data)); 369 + } else if (audio->set_con) { 370 + struct usb_audio_control *con = audio->set_con; 371 + u8 type = con->type; 372 + u32 data; 373 + bool valid_request = false; 374 + 375 + switch (type) { 376 + case UAC_FU_MUTE: { 377 + u8 value; 378 + 379 + if (req->actual == sizeof(value)) { 380 + memcpy(&value, req->buf, sizeof(value)); 381 + data = value; 382 + valid_request = true; 383 + } 384 + break; 385 + } 386 + case UAC_FU_VOLUME: { 387 + __le16 value; 388 + 389 + if (req->actual == sizeof(value)) { 390 + memcpy(&value, req->buf, sizeof(value)); 391 + data = le16_to_cpu(value); 392 + valid_request = true; 393 + } 394 + break; 395 + } 396 + } 397 + 398 + if (valid_request) 399 + con->set(con, audio->set_cmd, data); 400 + else 401 + usb_ep_set_halt(ep); 402 + 376 403 audio->set_con = NULL; 377 404 } 378 405 break;