lkml.org 
[lkml]   [2020]   [Jul]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.9 36/61] staging: comedi: addi_apci_1564: check INSN_CONFIG_DIGITAL_TRIG shift
    Date
    From: Ian Abbott <abbotti@mev.co.uk>

    commit 926234f1b8434c4409aa4c53637aa3362ca07cea 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.

    Fixes: 1e15687ea472 ("staging: comedi: addi_apci_1564: add Change-of-State interrupt subdevice and required functions")
    Cc: <stable@vger.kernel.org> #3.17+
    Signed-off-by: Ian Abbott <abbotti@mev.co.uk>
    Link: https://lore.kernel.org/r/20200717145257.112660-4-abbotti@mev.co.uk
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/staging/comedi/drivers/addi_apci_1564.c | 20 ++++++++++++++------
    1 file changed, 14 insertions(+), 6 deletions(-)

    --- a/drivers/staging/comedi/drivers/addi_apci_1564.c
    +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c
    @@ -340,14 +340,22 @@ static int apci1564_cos_insn_config(stru
    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;
    @@ -371,8 +379,8 @@ static int apci1564_cos_insn_config(stru
    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 |
    @@ -389,8 +397,8 @@ static int apci1564_cos_insn_config(stru
    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;

    \
     
     \ /
      Last update: 2020-07-30 10:09    [W:3.648 / U:0.112 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site