Commit 3027b255 authored by Ian Abbott's avatar Ian Abbott Committed by Greg Kroah-Hartman

staging: comedi: addi_apci_1500: check INSN_CONFIG_DIGITAL_TRIG shift

commit fc846e9d upstream.

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: a8c66b68 ("staging: comedi: addi_apci_1500: rewrite the subdevice support functions")
Cc: <stable@vger.kernel.org> #4.0+: ef75e14a: staging: comedi: verify array index is correct before using it
Cc: <stable@vger.kernel.org> #4.0+
Signed-off-by: default avatarIan Abbott <abbotti@mev.co.uk>
Link: https://lore.kernel.org/r/20200717145257.112660-5-abbotti@mev.co.ukSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 8f6e8ce1
...@@ -452,13 +452,14 @@ static int apci1500_di_cfg_trig(struct comedi_device *dev, ...@@ -452,13 +452,14 @@ static int apci1500_di_cfg_trig(struct comedi_device *dev,
struct apci1500_private *devpriv = dev->private; struct apci1500_private *devpriv = dev->private;
unsigned int trig = data[1]; unsigned int trig = data[1];
unsigned int shift = data[3]; unsigned int shift = data[3];
unsigned int hi_mask = data[4] << shift; unsigned int hi_mask;
unsigned int lo_mask = data[5] << shift; unsigned int lo_mask;
unsigned int chan_mask = hi_mask | lo_mask; unsigned int chan_mask;
unsigned int old_mask = (1 << shift) - 1; unsigned int old_mask;
unsigned int pm; unsigned int pm;
unsigned int pt; unsigned int pt;
unsigned int pp; unsigned int pp;
unsigned int invalid_chan;
if (trig > 1) { if (trig > 1) {
dev_dbg(dev->class_dev, dev_dbg(dev->class_dev,
...@@ -466,7 +467,20 @@ static int apci1500_di_cfg_trig(struct comedi_device *dev, ...@@ -466,7 +467,20 @@ static int apci1500_di_cfg_trig(struct comedi_device *dev,
return -EINVAL; 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"); dev_dbg(dev->class_dev, "invalid digital trigger channel\n");
return -EINVAL; return -EINVAL;
} }
......
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