[PATCH] media: em28xx: fix NULL pointer dereference on disconnect of dual-TS devices
From: Greg Sikorski
Date: Wed Nov 04 2026 - 00:28:19 EST
Commit 826915b6b65e ("media: em28xx: fix use-after-free of
dev_next->devlist on disconnect") made em28xx_close_extension() unlink
dev->dev_next->devlist from em28xx_devlist. On a regular dual-TS board
(e.g. Hauppauge WinTV-dualHD, 2040:8265) the secondary device is never
added to that list: em28xx_duplicate_dev() kmemdup()s the primary device
during probe, before request_modules() -> em28xx_init_extension() links
the primary one, so dev_next->devlist is { NULL, NULL }. With
CONFIG_LIST_HARDENED the inlined list_del() validity check dereferences
the NULL prev pointer and every disconnect oopses in usb_hub_wq with
em28xx_devlist_mutex held; the device never re-enumerates and the USB hub
thread stays stuck until reboot:
BUG: kernel NULL pointer dereference, address: 0000000000000000
Workqueue: usb_hub_wq hub_event
RIP: 0010:em28xx_close_extension+0x80/0x130 [em28xx]
Call Trace:
em28xx_usb_disconnect.cold+0x87/0xed [em28xx]
usb_unbind_interface+0x9b/0x2c0
...
usb_disconnect+0xe7/0x300
hub_port_connect+0x7f/0x930
Initialise the list head in em28xx_init_dev(), which runs for both
devices (for the secondary one after the kmemdup()), and unlink both
entries with list_del_init(). That is correct whether or not dev_next was
ever linked, so the use-after-free fixed by 826915b6b65e stays fixed.
Fixes: 826915b6b65e ("media: em28xx: fix use-after-free of dev_next->devlist on disconnect")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Greg Sikorski <sikorski.grzegorz@xxxxxxxxx>
---
drivers/media/usb/em28xx/em28xx-cards.c | 1 +
drivers/media/usb/em28xx/em28xx-core.c | 4 ++--
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 8440eafad..4d2ea2e27 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -3845,6 +3845,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
const char *chip_name = NULL;
dev->intf = intf;
+ INIT_LIST_HEAD(&dev->devlist);
mutex_init(&dev->ctrl_urb_lock);
spin_lock_init(&dev->slock);
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 62a1c25a2..ab1e1e18b 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -1263,8 +1263,8 @@ void em28xx_close_extension(struct em28xx *dev)
}
}
if (dev->dev_next)
- list_del(&dev->dev_next->devlist);
- list_del(&dev->devlist);
+ list_del_init(&dev->dev_next->devlist);
+ list_del_init(&dev->devlist);
mutex_unlock(&em28xx_devlist_mutex);
}
--
2.53.0