From f07804ec77d77f8a9dcf570a24154e17747bc82f Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 17 Jul 2020 15:52:54 +0100 Subject: staging: comedi: ni_6527: fix INSN_CONFIG_DIGITAL_TRIG support `ni6527_intr_insn_config()` processes `INSN_CONFIG` comedi instructions for the "interrupt" subdevice. When `data[0]` is `INSN_CONFIG_DIGITAL_TRIG` it is configuring the digital trigger. When `data[2]` is `COMEDI_DIGITAL_TRIG_ENABLE_EDGES` it is configuring rising and falling edge detection for the digital trigger, using a base channel number (or shift amount) in `data[3]`, a rising edge bitmask in `data[4]` and falling edge bitmask in `data[5]`. If the base channel number (shift amount) is greater than or equal to the number of channels (24) of the digital input subdevice, there are no changes to the rising and falling edges, so the mask of channels to be changed can be set to 0, otherwise the mask of channels to be changed, and the rising and falling edge bitmasks are shifted by the base channel number before calling `ni6527_set_edge_detection()` to change the appropriate registers. Unfortunately, the code is comparing the base channel (shift amount) to the interrupt subdevice's number of channels (1) instead of the digital input subdevice's number of channels (24). Fix it by comparing to 32 because all shift amounts for an `unsigned int` must be less than that and everything from bit 24 upwards is ignored by `ni6527_set_edge_detection()` anyway. Fixes: 110f9e687c1a8 ("staging: comedi: ni_6527: support INSN_CONFIG_DIGITAL_TRIG") Cc: # 3.17+ Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20200717145257.112660-2-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/ni_6527.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index 4d1eccb5041d..4518c2680b7c 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -332,7 +332,7 @@ static int ni6527_intr_insn_config(struct comedi_device *dev, case COMEDI_DIGITAL_TRIG_ENABLE_EDGES: /* check shift amount */ shift = data[3]; - if (shift >= s->n_chan) { + if (shift >= 32) { mask = 0; rising = 0; falling = 0; -- cgit v1.2.3 From 0bd0db42a030b75c20028c7ba6e327b9cb554116 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 17 Jul 2020 15:52:55 +0100 Subject: staging: comedi: addi_apci_1032: check INSN_CONFIG_DIGITAL_TRIG shift The `INSN_CONFIG` comedi instruction with sub-instruction code `INSN_CONFIG_DIGITAL_TRIG` includes a base channel in `data[3]`. This is used as a right shift amount for other bitmask values without being checked. Shift amounts greater than or equal to 32 will result in undefined behavior. Add code to deal with this. Fixes: 33cdce6293dcc ("staging: comedi: addi_apci_1032: conform to new INSN_CONFIG_DIGITAL_TRIG") Cc: #3.8+ Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20200717145257.112660-3-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/addi_apci_1032.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c index 560649be9d13..e035c9f757a1 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1032.c +++ b/drivers/staging/comedi/drivers/addi_apci_1032.c @@ -106,14 +106,22 @@ static int apci1032_cos_insn_config(struct comedi_device *dev, unsigned int *data) { struct apci1032_private *devpriv = dev->private; - unsigned int shift, oldmask; + unsigned int shift, oldmask, himask, lomask; switch (data[0]) { case INSN_CONFIG_DIGITAL_TRIG: if (data[1] != 0) return -EINVAL; shift = data[3]; - oldmask = (1U << shift) - 1; + if (shift < 32) { + oldmask = (1U << shift) - 1; + himask = data[4] << shift; + lomask = data[5] << shift; + } else { + oldmask = 0xffffffffu; + himask = 0; + lomask = 0; + } switch (data[2]) { case COMEDI_DIGITAL_TRIG_DISABLE: devpriv->ctrl = 0; @@ -136,8 +144,8 @@ static int apci1032_cos_insn_config(struct comedi_device *dev, devpriv->mode2 &= oldmask; } /* configure specified channels */ - devpriv->mode1 |= data[4] << shift; - devpriv->mode2 |= data[5] << shift; + devpriv->mode1 |= himask; + devpriv->mode2 |= lomask; break; case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS: if (devpriv->ctrl != (APCI1032_CTRL_INT_ENA | @@ -154,8 +162,8 @@ static int apci1032_cos_insn_config(struct comedi_device *dev, devpriv->mode2 &= oldmask; } /* configure specified channels */ - devpriv->mode1 |= data[4] << shift; - devpriv->mode2 |= data[5] << shift; + devpriv->mode1 |= himask; + devpriv->mode2 |= lomask; break; default: return -EINVAL; -- cgit v1.2.3 From fc846e9db67c7e808d77bf9e2ef3d49e3820ce5d Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 17 Jul 2020 15:52:57 +0100 Subject: staging: comedi: addi_apci_1500: check INSN_CONFIG_DIGITAL_TRIG shift The `INSN_CONFIG` comedi instruction with sub-instruction code `INSN_CONFIG_DIGITAL_TRIG` includes a base channel in `data[3]`. This is used as a right shift amount for other bitmask values without being checked. Shift amounts greater than or equal to 32 will result in undefined behavior. Add code to deal with this, adjusting the checks for invalid channels so that enabled channel bits that would have been lost by shifting are also checked for validity. Only channels 0 to 15 are valid. Fixes: a8c66b684efaf ("staging: comedi: addi_apci_1500: rewrite the subdevice support functions") Cc: #4.0+: ef75e14a6c93: staging: comedi: verify array index is correct before using it Cc: #4.0+ Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20200717145257.112660-5-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/addi_apci_1500.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c index 689acd69a1b9..816dd25b9d0e 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1500.c +++ b/drivers/staging/comedi/drivers/addi_apci_1500.c @@ -452,13 +452,14 @@ static int apci1500_di_cfg_trig(struct comedi_device *dev, struct apci1500_private *devpriv = dev->private; unsigned int trig = data[1]; unsigned int shift = data[3]; - unsigned int hi_mask = data[4] << shift; - unsigned int lo_mask = data[5] << shift; - unsigned int chan_mask = hi_mask | lo_mask; - unsigned int old_mask = (1 << shift) - 1; + unsigned int hi_mask; + unsigned int lo_mask; + unsigned int chan_mask; + unsigned int old_mask; unsigned int pm; unsigned int pt; unsigned int pp; + unsigned int invalid_chan; if (trig > 1) { dev_dbg(dev->class_dev, @@ -466,7 +467,20 @@ static int apci1500_di_cfg_trig(struct comedi_device *dev, return -EINVAL; } - if (chan_mask > 0xffff) { + if (shift <= 16) { + hi_mask = data[4] << shift; + lo_mask = data[5] << shift; + old_mask = (1U << shift) - 1; + invalid_chan = (data[4] | data[5]) >> (16 - shift); + } else { + hi_mask = 0; + lo_mask = 0; + old_mask = 0xffff; + invalid_chan = data[4] | data[5]; + } + chan_mask = hi_mask | lo_mask; + + if (invalid_chan) { dev_dbg(dev->class_dev, "invalid digital trigger channel\n"); return -EINVAL; } -- cgit v1.2.3 From 926234f1b8434c4409aa4c53637aa3362ca07cea Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Fri, 17 Jul 2020 15:52:56 +0100 Subject: staging: comedi: addi_apci_1564: check INSN_CONFIG_DIGITAL_TRIG shift The `INSN_CONFIG` comedi instruction with sub-instruction code `INSN_CONFIG_DIGITAL_TRIG` includes a base channel in `data[3]`. This is used as a right shift amount for other bitmask values without being checked. Shift amounts greater than or equal to 32 will result in undefined behavior. Add code to deal with this. Fixes: 1e15687ea472 ("staging: comedi: addi_apci_1564: add Change-of-State interrupt subdevice and required functions") Cc: #3.17+ Signed-off-by: Ian Abbott Link: https://lore.kernel.org/r/20200717145257.112660-4-abbotti@mev.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/addi_apci_1564.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 10501fe6bb25..1268ba34be5f 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -331,14 +331,22 @@ static int apci1564_cos_insn_config(struct comedi_device *dev, unsigned int *data) { struct apci1564_private *devpriv = dev->private; - unsigned int shift, oldmask; + unsigned int shift, oldmask, himask, lomask; switch (data[0]) { case INSN_CONFIG_DIGITAL_TRIG: if (data[1] != 0) return -EINVAL; shift = data[3]; - oldmask = (1U << shift) - 1; + if (shift < 32) { + oldmask = (1U << shift) - 1; + himask = data[4] << shift; + lomask = data[5] << shift; + } else { + oldmask = 0xffffffffu; + himask = 0; + lomask = 0; + } switch (data[2]) { case COMEDI_DIGITAL_TRIG_DISABLE: devpriv->ctrl = 0; @@ -362,8 +370,8 @@ static int apci1564_cos_insn_config(struct comedi_device *dev, devpriv->mode2 &= oldmask; } /* configure specified channels */ - devpriv->mode1 |= data[4] << shift; - devpriv->mode2 |= data[5] << shift; + devpriv->mode1 |= himask; + devpriv->mode2 |= lomask; break; case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS: if (devpriv->ctrl != (APCI1564_DI_IRQ_ENA | @@ -380,8 +388,8 @@ static int apci1564_cos_insn_config(struct comedi_device *dev, devpriv->mode2 &= oldmask; } /* configure specified channels */ - devpriv->mode1 |= data[4] << shift; - devpriv->mode2 |= data[5] << shift; + devpriv->mode1 |= himask; + devpriv->mode2 |= lomask; break; default: return -EINVAL; -- cgit v1.2.3 From faaff9765664009c1c7c65551d32e9ed3b1dda8f Mon Sep 17 00:00:00 2001 From: Rustam Kovhaev Date: Wed, 22 Jul 2020 09:10:52 -0700 Subject: staging: wlan-ng: properly check endpoint types As syzkaller detected, wlan-ng driver does not do sanity check of endpoints in prism2sta_probe_usb(), add check for xfer direction and type Reported-and-tested-by: syzbot+c2a1fa67c02faa0de723@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?extid=c2a1fa67c02faa0de723 Signed-off-by: Rustam Kovhaev Cc: stable Link: https://lore.kernel.org/r/20200722161052.999754-1-rkovhaev@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/prism2usb.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/staging/wlan-ng/prism2usb.c b/drivers/staging/wlan-ng/prism2usb.c index 4689b2170e4f..456603fd26c0 100644 --- a/drivers/staging/wlan-ng/prism2usb.c +++ b/drivers/staging/wlan-ng/prism2usb.c @@ -61,11 +61,25 @@ static int prism2sta_probe_usb(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *dev; - + const struct usb_endpoint_descriptor *epd; + const struct usb_host_interface *iface_desc = interface->cur_altsetting; struct wlandevice *wlandev = NULL; struct hfa384x *hw = NULL; int result = 0; + if (iface_desc->desc.bNumEndpoints != 2) { + result = -ENODEV; + goto failed; + } + + result = -EINVAL; + epd = &iface_desc->endpoint[1].desc; + if (!usb_endpoint_is_bulk_in(epd)) + goto failed; + epd = &iface_desc->endpoint[2].desc; + if (!usb_endpoint_is_bulk_out(epd)) + goto failed; + dev = interface_to_usbdev(interface); wlandev = create_wlan(); if (!wlandev) { -- cgit v1.2.3