On Mon Aug 17 14:09:49 2026 +0000, Aleksandr Nogikh wrote:
> A null-pointer dereference can occur in usb_make_path() when called from
> usbtv_querycap() (and other ioctl handlers) during device disconnection.
>
> Oops: general protection fault, probably for non-canonical address
> 0xdffffc000000000a: 0000 [#1] SMP KASAN NOPTI
> KASAN: null-ptr-deref in range [0x0000000000000050-0x0000000000000057]
> RIP: 0010:usb_make_path include/linux/usb.h:985 [inline]
> RIP: 0010:usbtv_querycap+0x9c/0x100
> drivers/media/usb/usbtv/usbtv-video.c:612
> ...
> Call Trace:
> <TASK>
> v4l_querycap+0x236/0x470 drivers/media/v4l2-core/v4l2-ioctl.c:1106
> __video_do_ioctl+0x8af/0xc70 drivers/media/v4l2-core/v4l2-ioctl.c:3133
> video_usercopy+0x860/0x1430 drivers/media/v4l2-core/v4l2-ioctl.c:3475
> v4l2_ioctl+0x18d/0x1e0 drivers/media/v4l2-core/v4l2-dev.c:366
> vfs_ioctl fs/ioctl.c:51 [inline]
> __do_sys_ioctl fs/ioctl.c:597 [inline]
> __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583
> do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
> do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94
>
> This happens due to a race condition between the USB device disconnect
> routine (usbtv_disconnect()) and V4L2 ioctls. When the device is
> disconnected, usbtv_disconnect() sets usbtv->udev = NULL without holding
> the usbtv->v4l2_lock mutex. Concurrently, an ioctl handler like
> usbtv_querycap() can be executing under the v4l2_lock and attempt to use
> usbtv->udev, leading to a crash.
>
> To fix this, move the usbtv->udev = NULL assignment into usbtv_video_free()
> and protect it with mutex_lock(&usbtv->v4l2_lock). This ensures that no
> non-queue ioctl handler can run concurrently with the pointer being
> nullified. If an ioctl is already running, the mutex will block the
> disconnect path until the ioctl finishes. If an ioctl is blocked waiting
> for the lock, it will acquire it after the disconnect routine releases it,
> but will then check video_is_registered() (which was cleared by
> vb2_video_unregister_device()) and safely return -ENODEV.
>
> Acquiring v4l2_lock after vb2_video_unregister_device() avoids
> reintroducing a historical deadlock issue, and usbtv_audio_free() remains
> safe as it is called before usbtv_video_free().
>
> Fixes: 65e6a2773d65 ("media: usbtv: Remove useless locks in
> usbtv_video_free()")
> Cc: [email protected]
> Assisted-by: Gemini:gemini-3.6-flash Gemini:gemini-3.1-pro-preview syzbot
> Reported-by: [email protected]
> Closes: https://syzkaller.appspot.com/bug?extid=37a57a84893052ab6071
> Link:
> https://syzkaller.appspot.com/ai_job?id=5abbe65a-5853-4bc2-9135-5c75f88d51ed
> Signed-off-by: Aleksandr Nogikh <[email protected]>
> Signed-off-by: Hans Verkuil <[email protected]>
Patch committed.
Thanks,
Hans Verkuil
drivers/media/usb/usbtv/usbtv-core.c | 2 --
drivers/media/usb/usbtv/usbtv-video.c | 4 ++++
2 files changed, 4 insertions(+), 2 deletions(-)
---
diff --git a/drivers/media/usb/usbtv/usbtv-core.c
b/drivers/media/usb/usbtv/usbtv-core.c
index 4f10f6613bc4..89c3424e7685 100644
--- a/drivers/media/usb/usbtv/usbtv-core.c
+++ b/drivers/media/usb/usbtv/usbtv-core.c
@@ -139,8 +139,6 @@ static void usbtv_disconnect(struct usb_interface *intf)
usbtv_audio_free(usbtv);
usbtv_video_free(usbtv);
- usbtv->udev = NULL;
-
/* the usbtv structure will be deallocated when v4l2 will be
done using it */
v4l2_device_put(&usbtv->v4l2_dev);
diff --git a/drivers/media/usb/usbtv/usbtv-video.c
b/drivers/media/usb/usbtv/usbtv-video.c
index 92bc7a2509c3..2a91af8d1e30 100644
--- a/drivers/media/usb/usbtv/usbtv-video.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -966,5 +966,9 @@ void usbtv_video_free(struct usbtv *usbtv)
vb2_video_unregister_device(&usbtv->vdev);
v4l2_device_disconnect(&usbtv->v4l2_dev);
+ mutex_lock(&usbtv->v4l2_lock);
+ usbtv->udev = NULL;
+ mutex_unlock(&usbtv->v4l2_lock);
+
v4l2_device_put(&usbtv->v4l2_dev);
}
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]