Commit 6e0e34d8 authored by Taegu Ha's avatar Taegu Ha Committed by Greg Kroah-Hartman
Browse files

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: default avatarTaegu Ha <hataegu0826@gmail.com>
Cc: stable <stable@kernel.org>
Link: https://patch.msgid.link/20260401191311.3604898-1-hataegu0826@gmail.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 01af5423
Loading
Loading
Loading
Loading
+37 −10
Original line number Diff line number Diff line
@@ -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;