ALSA: usb-audio: Sanity checks for each pipe and EP types
authorTakashi Iwai <tiwai@suse.de>
Mon, 24 Jun 2019 13:08:28 +0000 (15:08 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 24 Jun 2019 13:11:06 +0000 (15:11 +0200)
The recent USB core code performs sanity checks for the given pipe and
EP types, and it can be hit by manipulated USB descriptors by syzbot.
For making syzbot happier, this patch introduces a local helper for a
sanity check in the driver side and calls it at each place before the
message handling, so that we can avoid the WARNING splats.

Reported-by: syzbot+d952e5e28f5fb7718d23@syzkaller.appspotmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/usb/helper.c
sound/usb/helper.h
sound/usb/quirks.c

index 7712e2b84183891336469d65b861cba0beb145e3..b1cc9499c57e1c59b88212a81c99f1a1e6905200 100644 (file)
@@ -76,6 +76,20 @@ void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype
        return NULL;
 }
 
+/* check the validity of pipe and EP types */
+int snd_usb_pipe_sanity_check(struct usb_device *dev, unsigned int pipe)
+{
+       static const int pipetypes[4] = {
+               PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+       };
+       struct usb_host_endpoint *ep;
+
+       ep = usb_pipe_endpoint(dev, pipe);
+       if (usb_pipetype(pipe) != pipetypes[usb_endpoint_type(&ep->desc)])
+               return -EINVAL;
+       return 0;
+}
+
 /*
  * Wrapper for usb_control_msg().
  * Allocates a temp buffer to prevent dmaing from/to the stack.
@@ -88,6 +102,9 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
        void *buf = NULL;
        int timeout;
 
+       if (snd_usb_pipe_sanity_check(dev, pipe))
+               return -EINVAL;
+
        if (size > 0) {
                buf = kmemdup(data, size, GFP_KERNEL);
                if (!buf)
index d338bd0e0ca609b29cb8b5bccb344bf099e8b0c6..6afb70156ec4fcae1549f83100c50271edf50ca7 100644 (file)
@@ -7,6 +7,7 @@ unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size);
 void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype);
 void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsubtype);
 
+int snd_usb_pipe_sanity_check(struct usb_device *dev, unsigned int pipe);
 int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe,
                    __u8 request, __u8 requesttype, __u16 value, __u16 index,
                    void *data, __u16 size);
index e6ce1bbe6ca6ef1af81a1c135a10a1a0ce95fd93..057143330a281002bf9a2fc8bbb62e39b07daf21 100644 (file)
@@ -840,11 +840,13 @@ static int snd_usb_novation_boot_quirk(struct usb_device *dev)
 static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev)
 {
        int err, actual_length;
-
        /* "midi send" enable */
        static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 };
+       void *buf;
 
-       void *buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL);
+       if (snd_usb_pipe_sanity_check(dev, usb_sndintpipe(dev, 0x05)))
+               return -EINVAL;
+       buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL);
        if (!buf)
                return -ENOMEM;
        err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x05), buf,
@@ -869,7 +871,11 @@ static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev)
 
 static int snd_usb_nativeinstruments_boot_quirk(struct usb_device *dev)
 {
-       int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+       int ret;
+
+       if (snd_usb_pipe_sanity_check(dev, usb_sndctrlpipe(dev, 0)))
+               return -EINVAL;
+       ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                                  0xaf, USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                                  1, 0, NULL, 0, 1000);
 
@@ -976,6 +982,8 @@ static int snd_usb_axefx3_boot_quirk(struct usb_device *dev)
 
        dev_dbg(&dev->dev, "Waiting for Axe-Fx III to boot up...\n");
 
+       if (snd_usb_pipe_sanity_check(dev, usb_sndctrlpipe(dev, 0)))
+               return -EINVAL;
        /* If the Axe-Fx III has not fully booted, it will timeout when trying
         * to enable the audio streaming interface. A more generous timeout is
         * used here to detect when the Axe-Fx III has finished booting as the
@@ -1008,6 +1016,8 @@ static int snd_usb_motu_microbookii_communicate(struct usb_device *dev, u8 *buf,
 {
        int err, actual_length;
 
+       if (snd_usb_pipe_sanity_check(dev, usb_sndintpipe(dev, 0x01)))
+               return -EINVAL;
        err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x01), buf, *length,
                                &actual_length, 1000);
        if (err < 0)
@@ -1018,6 +1028,8 @@ static int snd_usb_motu_microbookii_communicate(struct usb_device *dev, u8 *buf,
 
        memset(buf, 0, buf_size);
 
+       if (snd_usb_pipe_sanity_check(dev, usb_rcvintpipe(dev, 0x82)))
+               return -EINVAL;
        err = usb_interrupt_msg(dev, usb_rcvintpipe(dev, 0x82), buf, buf_size,
                                &actual_length, 1000);
        if (err < 0)