From bbd4218310cc9fc8bba677e8c35abd03524ad474 Mon Sep 17 00:00:00 2001 From: Guangshuo Li Date: Tue, 14 Jul 2026 23:16:48 +0800 Subject: [PATCH] media: usbtv: Fix V4L2 refcount leak on probe failure usbtv_probe() allocates usbtv before usbtv_video_init() registers its embedded v4l2_device. v4l2_device_register() initializes the reference count to one, with usbtv_release() providing the final cleanup. If video_register_device() fails, usbtv_video_init() unregisters the V4L2 device and returns an error without dropping the initial v4l2_device reference. The probe error path then calls kfree() on usbtv directly, leaving the reference stranded and bypassing usbtv_release(). Leave the initialized V4L2 device intact on this failure path. After releasing the USB reference, call v4l2_device_put() so the final reference invokes usbtv_release(). Retain the direct kfree() path for failures that occur before v4l2_device_register(). This issue was found by a static analysis tool I am developing. Signed-off-by: Guangshuo Li Signed-off-by: Hans Verkuil --- drivers/media/usb/usbtv/usbtv-core.c | 5 ++++- drivers/media/usb/usbtv/usbtv-video.c | 4 +--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index 6c4facf4f41a..4f10f6613bc4 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -119,7 +119,10 @@ static int usbtv_probe(struct usb_interface *intf, usbtv_video_fail: usb_set_intfdata(intf, NULL); - kfree(usbtv); + if (usbtv->v4l2_dev.dev) + v4l2_device_put(&usbtv->v4l2_dev); + else + kfree(usbtv); return ret; } diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index de0328100a60..92bc7a2509c3 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -949,13 +949,11 @@ int usbtv_video_init(struct usbtv *usbtv) ret = video_register_device(&usbtv->vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) { dev_warn(usbtv->dev, "Could not register video device\n"); - goto vdev_fail; + return ret; } return 0; -vdev_fail: - v4l2_device_unregister(&usbtv->v4l2_dev); v4l2_fail: ctrl_fail: v4l2_ctrl_handler_free(&usbtv->ctrl);