USB: serial: io_edgeport: fix epic-descriptor handling
authorJohan Hovold <johan@kernel.org>
Thu, 12 Jan 2017 13:56:13 +0000 (14:56 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 14 May 2017 11:32:56 +0000 (13:32 +0200)
commit e4457d9798adb96272468e93da663de9bd0a4198 upstream.

Use a dedicated buffer for the DMA transfer and make sure to detect
short transfers to avoid parsing a corrupt descriptor.

Fixes: 6e8cf7751f9f ("USB: add EPIC support to the io_edgeport driver")
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Johan Hovold <johan@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/serial/io_edgeport.c

index b63a6c3899c59b47a7146bacab8c226474976107..d18ab56f0cc85bc3dd5ab9c22314c0ca7daf5123 100644 (file)
@@ -492,20 +492,24 @@ static int get_epic_descriptor(struct edgeport_serial *ep)
        int result;
        struct usb_serial *serial = ep->serial;
        struct edgeport_product_info *product_info = &ep->product_info;
-       struct edge_compatibility_descriptor *epic = &ep->epic_descriptor;
+       struct edge_compatibility_descriptor *epic;
        struct edge_compatibility_bits *bits;
        struct device *dev = &serial->dev->dev;
 
        ep->is_epic = 0;
+
+       epic = kmalloc(sizeof(*epic), GFP_KERNEL);
+       if (!epic)
+               return -ENOMEM;
+
        result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                                 USB_REQUEST_ION_GET_EPIC_DESC,
                                 0xC0, 0x00, 0x00,
-                                &ep->epic_descriptor,
-                                sizeof(struct edge_compatibility_descriptor),
+                                epic, sizeof(*epic),
                                 300);
-
-       if (result > 0) {
+       if (result == sizeof(*epic)) {
                ep->is_epic = 1;
+               memcpy(&ep->epic_descriptor, epic, sizeof(*epic));
                memset(product_info, 0, sizeof(struct edgeport_product_info));
 
                product_info->NumPorts = epic->NumPorts;
@@ -534,8 +538,16 @@ static int get_epic_descriptor(struct edgeport_serial *ep)
                dev_dbg(dev, "  IOSPWriteLCR     : %s\n", bits->IOSPWriteLCR    ? "TRUE": "FALSE");
                dev_dbg(dev, "  IOSPSetBaudRate  : %s\n", bits->IOSPSetBaudRate ? "TRUE": "FALSE");
                dev_dbg(dev, "  TrueEdgeport     : %s\n", bits->TrueEdgeport    ? "TRUE": "FALSE");
+
+               result = 0;
+       } else if (result >= 0) {
+               dev_warn(&serial->interface->dev, "short epic descriptor received: %d\n",
+                        result);
+               result = -EIO;
        }
 
+       kfree(epic);
+
        return result;
 }
 
@@ -2789,7 +2801,7 @@ static int edge_startup(struct usb_serial *serial)
        dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
 
        /* Read the epic descriptor */
-       if (get_epic_descriptor(edge_serial) <= 0) {
+       if (get_epic_descriptor(edge_serial) < 0) {
                /* memcpy descriptor to Supports structures */
                memcpy(&edge_serial->epic_descriptor.Supports, descriptor,
                       sizeof(struct edge_compatibility_bits));