diff mbox series

[2/2] media: dvb-usbv2: ensure safe USB transfers on disconnect in i2c_xfer

Message ID 20250421-ubsan-out-of-sub-v1-2-d9239a5af007@arnaud-lcm.com
State New
Headers show
Series media: dvb-usbv2: Prevent usb race condition, buffer overflow az6007 | expand

Commit Message

Arnaud Lecomte April 21, 2025, 4:33 p.m. UTC
Previously, there was a potential race condition where a USB transfer could
access inconsistent data if a disconnect occurred mid-transfer.
When this scenario happens (i.e when there is an USB disconnect during
the transfer), we would encounter an error related to the corruption of
st:
[   66.967387][T10787]  slab kmalloc-8k start ffff88804f5b4000 pointer offset 80 size 8192
[   66.968252][T10787] list_del corruption. prev->next should be ffffc9000d18f7e0, but was ffff88804f5b4050. (prev=ffff88804f5b4050)
[   66.969443][T10787] ------------[ cut here ]------------
[   66.969973][T10787] kernel BUG at lib/list_debug.c:64!
[   66.970491][T10787] Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
[   66.971104][T10787] CPU: 0 UID: 0 PID: 10787 Comm: repro Not tainted 6.15.0-rc3-00004-gcd75cc176092-dirty #28 PREEMPT(full)
[   66.972204][T10787] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[   66.973236][T10787] RIP: 0010:__list_del_entry_valid_or_report+0x15c/0x190
[   66.973896][T10787] Code: ca da fb fc 42 80 3c 2b 00 74 08 4c 89 e7 e8 fb 29 1f fd 49 8b 14 24 48 c7 c7 a0 09 a2 8c 4c 89 fe 4c 89 e1 e8 55 43 18 fc 90 <0f> 0b 4c 89 f7 e8 9a da fb fc 42 80 3c 2b 00 74 08 4c 89 e7 e8 cb

Signed-off-by: Arnaud Lecomte <contact@arnaud-lcm.com>
---
 drivers/media/usb/dvb-usb-v2/az6007.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c
index e8ee18010346..f6b8e29d19de 100644
--- a/drivers/media/usb/dvb-usb-v2/az6007.c
+++ b/drivers/media/usb/dvb-usb-v2/az6007.c
@@ -752,8 +752,13 @@  static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
 	int length;
 	u8 req, addr;
 
-	if (mutex_lock_interruptible(&st->mutex) < 0)
+	if (!usb_trylock_device(d->udev))
+		return -EBUSY;
+
+	if (mutex_lock_interruptible(&st->mutex) < 0) {
+		usb_unlock_device(d->udev);
 		return -EAGAIN;
+	}
 
 	for (i = 0; i < num; i++) {
 		addr = msgs[i].addr << 1;
@@ -821,6 +826,7 @@  static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
 	}
 err:
 	mutex_unlock(&st->mutex);
+	usb_unlock_device(d->udev);
 	if (ret < 0) {
 		pr_info("%s ERROR: %i\n", __func__, ret);
 		return ret;