]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ALSA: caiaq: bound the length in the EP1 input parsers
authorMaoyi Xie <maoyixie.tju@gmail.com>
Thu, 18 Jun 2026 06:03:15 +0000 (14:03 +0800)
committerTakashi Iwai <tiwai@suse.de>
Thu, 18 Jun 2026 10:37:50 +0000 (12:37 +0200)
snd_caiaq_input_read_erp() and snd_caiaq_input_read_io() can be reached
from snd_usb_caiaq_input_dispatch(). They read fixed byte offsets from
the reply buffer without checking the reported length. On a short reply
they decode stale bytes left from a previous, longer report and feed them
to the input layer.

This is not an out-of-bounds access. Every offset is a compile-time
driver constant. The largest is buf[21] in the Maschine ERP case. The
EP1 transfer buffer ep1_in_buf is EP1_BUFSIZE (64) bytes, and the USB
core caps actual_length at 64, so a short reply only reads in-bounds
stale data. Acting on data the device did not send is still wrong, so
bail out per usb_id case when the reply is shorter than the bytes that
case consumes.

  read_erp: AK1 needs 2 bytes, Kore needs 16, Maschine needs 22.
  read_io:  the Kore case needs 5 bytes (buf[4]) and the Traktor Kontrol
            X1 case needs 7 (buf[5]/buf[6]). The preceding key bit loop
            is already bounded by "i < len * 8" and is left untouched.

snd_caiaq_input_read_analog() and snd_usb_caiaq_maschine_dispatch() are
not changed. Their callers already floor the reply length.

Suggested-by: Takashi Iwai <tiwai@suse.com>
Signed-off-by: Maoyi Xie <maoyixie.tju@gmail.com>
Link: https://patch.msgid.link/178176259547.3343534.6659489917322808916@maoyixie.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/usb/caiaq/input.c

index 2db4d1332df1cc73ac5b4e29d75085effb067503..eabbf41fdfb2b21874542a75a2c49ef312054fcf 100644 (file)
@@ -237,12 +237,16 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *cdev,
 
        switch (cdev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
+               if (len < 2)
+                       return;
                i = decode_erp(buf[0], buf[1]);
                input_report_abs(input_dev, ABS_X, i);
                input_sync(input_dev);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
+               if (len < 16)
+                       return;
                i = decode_erp(buf[7], buf[5]);
                input_report_abs(input_dev, ABS_HAT0X, i);
                i = decode_erp(buf[12], buf[14]);
@@ -263,6 +267,8 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *cdev,
                break;
 
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
+               if (len < 22)
+                       return;
                /* 4 under the left screen */
                input_report_abs(input_dev, ABS_HAT0X, decode_erp(buf[21], buf[20]));
                input_report_abs(input_dev, ABS_HAT0Y, decode_erp(buf[15], buf[14]));
@@ -308,9 +314,13 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *cdev,
        switch (cdev->chip.usb_id) {
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
+               if (len < 5)
+                       return;
                input_report_abs(cdev->input_dev, ABS_MISC, 255 - buf[4]);
                break;
        case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+               if (len < 7)
+                       return;
                /* rotary encoders */
                input_report_abs(cdev->input_dev, ABS_X, buf[5] & 0xf);
                input_report_abs(cdev->input_dev, ABS_Y, buf[5] >> 4);