]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
media: em28xx: fix use-after-free in em28xx_v4l2_open()
authorAbhishek Kumar <abhishek_sts8@yahoo.com>
Tue, 10 Mar 2026 16:44:37 +0000 (22:14 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 22 Apr 2026 11:32:22 +0000 (13:32 +0200)
commit a66485a934c7187ae8e36517d40615fa2e961cff upstream.

em28xx_v4l2_open() reads dev->v4l2 without holding dev->lock,
creating a race with em28xx_v4l2_init()'s error path and
em28xx_v4l2_fini(), both of which free the em28xx_v4l2 struct
and set dev->v4l2 to NULL under dev->lock.

This race leads to two issues:
 - use-after-free in v4l2_fh_init() when accessing vdev->ctrl_handler,
   since the video_device is embedded in the freed em28xx_v4l2 struct.
 - NULL pointer dereference in em28xx_resolution_set() when accessing
   v4l2->norm, since dev->v4l2 has been set to NULL.

Fix this by moving the mutex_lock() before the dev->v4l2 read and
adding a NULL check for dev->v4l2 under the lock.

Reported-by: syzbot+c025d34b8eaa54c571b8@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=c025d34b8eaa54c571b8
Fixes: 8139a4d583ab ("[media] em28xx: move v4l2 user counting fields from struct em28xx to struct v4l2")
Cc: stable@vger.kernel.org
Signed-off-by: Abhishek Kumar <abhishek_sts8@yahoo.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/media/usb/em28xx/em28xx-video.c

index b0c184f237a7214af95530f639beec2aac651c41..5f13f63fbdee2d2e217c94ff661bcb5efed83de9 100644 (file)
@@ -2126,7 +2126,7 @@ static int em28xx_v4l2_open(struct file *filp)
 {
        struct video_device *vdev = video_devdata(filp);
        struct em28xx *dev = video_drvdata(filp);
-       struct em28xx_v4l2 *v4l2 = dev->v4l2;
+       struct em28xx_v4l2 *v4l2;
        enum v4l2_buf_type fh_type = 0;
        int ret;
 
@@ -2143,13 +2143,19 @@ static int em28xx_v4l2_open(struct file *filp)
                return -EINVAL;
        }
 
+       if (mutex_lock_interruptible(&dev->lock))
+               return -ERESTARTSYS;
+
+       v4l2 = dev->v4l2;
+       if (!v4l2) {
+               mutex_unlock(&dev->lock);
+               return -ENODEV;
+       }
+
        em28xx_videodbg("open dev=%s type=%s users=%d\n",
                        video_device_node_name(vdev), v4l2_type_names[fh_type],
                        v4l2->users);
 
-       if (mutex_lock_interruptible(&dev->lock))
-               return -ERESTARTSYS;
-
        ret = v4l2_fh_open(filp);
        if (ret) {
                dev_err(&dev->intf->dev,