dw2102: limit messages to buffer size
authorAlyssa Milburn <amilburn@zall.org>
Sat, 1 Apr 2017 17:34:49 +0000 (14:34 -0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 25 May 2017 13:44:42 +0000 (15:44 +0200)
commit 950e252cb469f323740d78e4907843acef89eedb upstream.

Otherwise the i2c transfer functions can read or write beyond the end of
stack or heap buffers.

Signed-off-by: Alyssa Milburn <amilburn@zall.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/media/usb/dvb-usb/dw2102.c

index c3e6734..4a0cc54 100644 (file)
@@ -205,6 +205,20 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
 
        switch (num) {
        case 2:
+               if (msg[0].len != 1) {
+                       warn("i2c rd: len=%d is not 1!\n",
+                            msg[0].len);
+                       num = -EOPNOTSUPP;
+                       break;
+               }
+
+               if (2 + msg[1].len > sizeof(buf6)) {
+                       warn("i2c rd: len=%d is too big!\n",
+                            msg[1].len);
+                       num = -EOPNOTSUPP;
+                       break;
+               }
+
                /* read si2109 register by number */
                buf6[0] = msg[0].addr << 1;
                buf6[1] = msg[0].len;
@@ -220,6 +234,13 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
        case 1:
                switch (msg[0].addr) {
                case 0x68:
+                       if (2 + msg[0].len > sizeof(buf6)) {
+                               warn("i2c wr: len=%d is too big!\n",
+                                    msg[0].len);
+                               num = -EOPNOTSUPP;
+                               break;
+                       }
+
                        /* write to si2109 register */
                        buf6[0] = msg[0].addr << 1;
                        buf6[1] = msg[0].len;
@@ -263,6 +284,13 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
                /* first write first register number */
                u8 ibuf[MAX_XFER_SIZE], obuf[3];
 
+               if (2 + msg[0].len != sizeof(obuf)) {
+                       warn("i2c rd: len=%d is not 1!\n",
+                            msg[0].len);
+                       ret = -EOPNOTSUPP;
+                       goto unlock;
+               }
+
                if (2 + msg[1].len > sizeof(ibuf)) {
                        warn("i2c rd: len=%d is too big!\n",
                             msg[1].len);
@@ -463,6 +491,12 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                /* first write first register number */
                u8 ibuf[MAX_XFER_SIZE], obuf[3];
 
+               if (2 + msg[0].len != sizeof(obuf)) {
+                       warn("i2c rd: len=%d is not 1!\n",
+                            msg[0].len);
+                       ret = -EOPNOTSUPP;
+                       goto unlock;
+               }
                if (2 + msg[1].len > sizeof(ibuf)) {
                        warn("i2c rd: len=%d is too big!\n",
                             msg[1].len);
@@ -697,6 +731,13 @@ static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                        msg[0].buf[0] = state->data[1];
                        break;
                default:
+                       if (3 + msg[0].len > sizeof(state->data)) {
+                               warn("i2c wr: len=%d is too big!\n",
+                                    msg[0].len);
+                               num = -EOPNOTSUPP;
+                               break;
+                       }
+
                        /* always i2c write*/
                        state->data[0] = 0x08;
                        state->data[1] = msg[0].addr;
@@ -712,6 +753,19 @@ static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                break;
        case 2:
                /* always i2c read */
+               if (4 + msg[0].len > sizeof(state->data)) {
+                       warn("i2c rd: len=%d is too big!\n",
+                            msg[0].len);
+                       num = -EOPNOTSUPP;
+                       break;
+               }
+               if (1 + msg[1].len > sizeof(state->data)) {
+                       warn("i2c rd: len=%d is too big!\n",
+                            msg[1].len);
+                       num = -EOPNOTSUPP;
+                       break;
+               }
+
                state->data[0] = 0x09;
                state->data[1] = msg[0].len;
                state->data[2] = msg[1].len;