summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTaegu Ha <hataegu0826@gmail.com>2026-04-02 04:13:11 +0900
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-04-02 09:37:17 +0200
commit6e0e34d85cd46ceb37d16054e97a373a32770f6c (patch)
treefb4ad322c9e8172147256da111cb9bb1c9029e14
parent01af542392b5d41fd659d487015a71f627accce3 (diff)
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>
-rw-r--r--drivers/usb/gadget/function/f_uac1_legacy.c47
1 files changed, 37 insertions, 10 deletions
diff --git a/drivers/usb/gadget/function/f_uac1_legacy.c b/drivers/usb/gadget/function/f_uac1_legacy.c
index a0c953a99727..5d201a2e30e7 100644
--- a/drivers/usb/gadget/function/f_uac1_legacy.c
+++ b/drivers/usb/gadget/function/f_uac1_legacy.c
@@ -360,19 +360,46 @@ static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req)
static void f_audio_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_audio *audio = req->context;
- int status = req->status;
- u32 data = 0;
struct usb_ep *out_ep = audio->out_ep;
- switch (status) {
-
- case 0: /* normal completion? */
- if (ep == out_ep)
+ switch (req->status) {
+ case 0:
+ if (ep == out_ep) {
f_audio_out_ep_complete(ep, req);
- else if (audio->set_con) {
- memcpy(&data, req->buf, req->length);
- audio->set_con->set(audio->set_con, audio->set_cmd,
- le16_to_cpu(data));
+ } else if (audio->set_con) {
+ struct usb_audio_control *con = audio->set_con;
+ u8 type = con->type;
+ u32 data;
+ bool valid_request = false;
+
+ switch (type) {
+ case UAC_FU_MUTE: {
+ u8 value;
+
+ if (req->actual == sizeof(value)) {
+ memcpy(&value, req->buf, sizeof(value));
+ data = value;
+ valid_request = true;
+ }
+ break;
+ }
+ case UAC_FU_VOLUME: {
+ __le16 value;
+
+ if (req->actual == sizeof(value)) {
+ memcpy(&value, req->buf, sizeof(value));
+ data = le16_to_cpu(value);
+ valid_request = true;
+ }
+ break;
+ }
+ }
+
+ if (valid_request)
+ con->set(con, audio->set_cmd, data);
+ else
+ usb_ep_set_halt(ep);
+
audio->set_con = NULL;
}
break;