Commit 6527f833 authored by Bjørn Mork's avatar Bjørn Mork Committed by David S. Miller

net: cdc_ncm: fix NULL pointer deref in cdc_ncm_bind_common

Commit 77b0a099 ("cdc-ncm: use common parser") added a dangerous
new trust in the CDC functional descriptors presented by the device,
unconditionally assuming that any device handled by the driver has
a CDC Union descriptor.

This descriptor is required by the NCM and MBIM specs, but crashing
on non-compliant devices is still unacceptable. Not only will that
allow malicious devices to crash the kernel, but in this case it is
also well known that there are non-compliant real devices on the
market - as shown by the comment accompanying the IAD workaround
in the same function.

The Sierra Wireless EM7305 is an example of such device, having
a CDC header and a CDC MBIM descriptor but no CDC Union:

    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber       12
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         2 Communications
      bInterfaceSubClass     14
      bInterfaceProtocol      0
      iInterface              0
      CDC Header:
        bcdCDC               1.10
      CDC MBIM:
        bcdMBIMVersion       1.00
        wMaxControlMessage   4096
        bNumberFilters       16
        bMaxFilterSize       128
        wMaxSegmentSize      4064
        bmNetworkCapabilities 0x20
          8-byte ntb input size
      Endpoint Descriptor:
	..

The conversion to a common parser also left the local cdc_union
variable untouched.  This caused the IAD workaround code to be applied
to all devices with an IAD descriptor, which was never intended.  Finish
the conversion by testing for hdr.usb_cdc_union_desc instead.

Cc: Oliver Neukum <oneukum@suse.com>
Fixes: 77b0a099 ("cdc-ncm: use common parser")
Signed-off-by: default avatarBjørn Mork <bjorn@mork.no>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 90bb81f3
...@@ -691,7 +691,6 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx) ...@@ -691,7 +691,6 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags) int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags)
{ {
const struct usb_cdc_union_desc *union_desc = NULL;
struct cdc_ncm_ctx *ctx; struct cdc_ncm_ctx *ctx;
struct usb_driver *driver; struct usb_driver *driver;
u8 *buf; u8 *buf;
...@@ -725,6 +724,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ ...@@ -725,6 +724,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
/* parse through descriptors associated with control interface */ /* parse through descriptors associated with control interface */
cdc_parse_cdc_header(&hdr, intf, buf, len); cdc_parse_cdc_header(&hdr, intf, buf, len);
if (hdr.usb_cdc_union_desc)
ctx->data = usb_ifnum_to_if(dev->udev, ctx->data = usb_ifnum_to_if(dev->udev,
hdr.usb_cdc_union_desc->bSlaveInterface0); hdr.usb_cdc_union_desc->bSlaveInterface0);
ctx->ether_desc = hdr.usb_cdc_ether_desc; ctx->ether_desc = hdr.usb_cdc_ether_desc;
...@@ -733,7 +733,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_ ...@@ -733,7 +733,7 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
ctx->mbim_extended_desc = hdr.usb_cdc_mbim_extended_desc; ctx->mbim_extended_desc = hdr.usb_cdc_mbim_extended_desc;
/* some buggy devices have an IAD but no CDC Union */ /* some buggy devices have an IAD but no CDC Union */
if (!union_desc && intf->intf_assoc && intf->intf_assoc->bInterfaceCount == 2) { if (!hdr.usb_cdc_union_desc && intf->intf_assoc && intf->intf_assoc->bInterfaceCount == 2) {
ctx->data = usb_ifnum_to_if(dev->udev, intf->cur_altsetting->desc.bInterfaceNumber + 1); ctx->data = usb_ifnum_to_if(dev->udev, intf->cur_altsetting->desc.bInterfaceNumber + 1);
dev_dbg(&intf->dev, "CDC Union missing - got slave from IAD\n"); dev_dbg(&intf->dev, "CDC Union missing - got slave from IAD\n");
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment