]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
usb: gadget: f_uac1_legacy: validate control request size
authorTaegu Ha <hataegu0826@gmail.com>
Wed, 1 Apr 2026 19:13:11 +0000 (04:13 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 2 Apr 2026 07:37:17 +0000 (09:37 +0200)
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>
drivers/usb/gadget/function/f_uac1_legacy.c

index a0c953a99727c467f2d384343330e14b1e3e7f22..5d201a2e30e7f19c56c372c9112eb888781bb90d 100644 (file)
@@ -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;