media: dw2102: Fix null-ptr-deref in dw2102_i2c_transfer()
authorZhang Shurong <zhang_shurong@foxmail.com>
Sat, 8 Jul 2023 10:22:52 +0000 (18:22 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 23 Sep 2023 09:11:06 +0000 (11:11 +0200)
[ Upstream commit 5ae544d94abc8ff77b1b9bf8774def3fa5689b5b ]

In dw2102_i2c_transfer, msg is controlled by user. When msg[i].buf
is null and msg[i].len is zero, former checks on msg[i].buf would be
passed. Malicious data finally reach dw2102_i2c_transfer. If accessing
msg[i].buf[0] without sanity check, null ptr deref would happen.
We add check on msg[i].len to prevent crash.

Similar commit:
commit 950e252cb469
("[media] dw2102: limit messages to buffer size")

Signed-off-by: Zhang Shurong <zhang_shurong@foxmail.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/media/usb/dvb-usb/dw2102.c

index 8747960..356fc72 100644 (file)
@@ -128,6 +128,10 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 
        switch (num) {
        case 2:
+               if (msg[0].len < 1) {
+                       num = -EOPNOTSUPP;
+                       break;
+               }
                /* read stv0299 register */
                value = msg[0].buf[0];/* register */
                for (i = 0; i < msg[1].len; i++) {
@@ -139,6 +143,10 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
        case 1:
                switch (msg[0].addr) {
                case 0x68:
+                       if (msg[0].len < 2) {
+                               num = -EOPNOTSUPP;
+                               break;
+                       }
                        /* write to stv0299 register */
                        buf6[0] = 0x2a;
                        buf6[1] = msg[0].buf[0];
@@ -148,6 +156,10 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                        break;
                case 0x60:
                        if (msg[0].flags == 0) {
+                               if (msg[0].len < 4) {
+                                       num = -EOPNOTSUPP;
+                                       break;
+                               }
                        /* write to tuner pll */
                                buf6[0] = 0x2c;
                                buf6[1] = 5;
@@ -159,6 +171,10 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                dw210x_op_rw(d->udev, 0xb2, 0, 0,
                                                buf6, 7, DW210X_WRITE_MSG);
                        } else {
+                               if (msg[0].len < 1) {
+                                       num = -EOPNOTSUPP;
+                                       break;
+                               }
                        /* read from tuner */
                                dw210x_op_rw(d->udev, 0xb5, 0, 0,
                                                buf6, 1, DW210X_READ_MSG);
@@ -166,12 +182,20 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                        }
                        break;
                case (DW2102_RC_QUERY):
+                       if (msg[0].len < 2) {
+                               num = -EOPNOTSUPP;
+                               break;
+                       }
                        dw210x_op_rw(d->udev, 0xb8, 0, 0,
                                        buf6, 2, DW210X_READ_MSG);
                        msg[0].buf[0] = buf6[0];
                        msg[0].buf[1] = buf6[1];
                        break;
                case (DW2102_VOLTAGE_CTRL):
+                       if (msg[0].len < 1) {
+                               num = -EOPNOTSUPP;
+                               break;
+                       }
                        buf6[0] = 0x30;
                        buf6[1] = msg[0].buf[0];
                        dw210x_op_rw(d->udev, 0xb2, 0, 0,