From: Nicola Fiorillo <nicfio@gmail.com>
To: Sakari Ailus <sakari.ailus@linux.intel.com>
Cc: Mauro Carvalho Chehab <mchehab@kernel.org>,
Hans Verkuil <hverkuil@kernel.org>,
Laurent Pinchart <laurent.pinchart@ideasonboard.com>,
Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com>,
linux-media@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH v3 1/2] media: v4l2-subdev: Fix NULL pointer dereference in subdev_open()
Date: Thu, 8 Oct 2026 06:25:59 +0200 [thread overview]
Message-ID: <20261008042600.275884-2-nicfio@gmail.com> (raw)
In-Reply-To: <20261008042600.275884-1-nicfio@gmail.com>
Unbinding a driver while something opens a /dev/v4l-subdevN node oopses
the kernel:
BUG: kernel NULL pointer dereference, address: 0000000000000008
RIP: 0010:subdev_open+0x8a/0x190 [videodev]
Call Trace:
v4l2_open+0xa9/0x100 [videodev]
chrdev_open+0xb2/0x230
do_dentry_open+0x14c/0x440
vfs_open+0x2e/0xe0
path_openat+0x82e/0x12d0
do_filp_open+0xc4/0x170
do_sys_openat2+0xae/0xe0
__x64_sys_openat+0x55/0xa0
v4l2_device_unregister_subdev() clears sd->v4l2_dev, then unregisters
the media entity, which clears sd->entity.graph_obj.mdev, and only then
unregisters the device node. Drivers that call media_device_unregister()
before v4l2_device_unregister(), as vimc does, clear
sd->entity.graph_obj.mdev even earlier, while the sub-device nodes are
still registered. subdev_open() dereferences both pointers. v4l2_open()
has checked that the node is registered, but it drops videodev_lock
before calling fops->open(), so the whole unregistration can run in
between. Reordering v4l2_device_unregister_subdev() would not help in
the second case, and checking the two pointers in subdev_open() would
only narrow the window.
Neither pointer is needed in subdev_open(). Both record that the
sub-device is registered, and are cleared on purpose when it goes away,
while open() runs on behalf of the device node. The node has its own
pointer to the same v4l2_device, vdev->v4l2_dev, which is set when the
node is registered and never cleared, and the V4L2 core already relies
on it for as long as the node exists: v4l2_release() dereferences it on
every close. The sub-device's entity is registered with
vdev->v4l2_dev->mdev, so that is also the media device to take the
module reference through.
That reference goes through mdev->dev->driver, which the driver core
clears once the media device's own driver has been unbound, as when
syzbot unbinds vimc. Read it once with READ_ONCE(), as
dev_driver_string() does, and fail the open with -ENODEV if it is gone:
unbinding does not unload the module, so the pointer read is either
still valid or NULL.
With this, subdev_open() no longer reads a pointer that the V4L2 core or
the driver core clears when a driver is unbound. It can still run on a
sub-device that has just been unregistered, exactly like a file handle
opened an instant earlier. The lifetime of the sub-device and of the
media device when a driver goes away with file handles open, and module
unloading, are a separate, known limitation that this does not address.
Reproduced on a CHUWI Hi10 X1 (Alder Lake-N, IPU6) running 6.12.86, at
cycle 7 of a loop unbinding and rebinding a sensor while four processes
opened every /dev/v4l-subdev*. syzbot hit the second dereference on the
same line by unbinding vimc, and so does a test in QEMU with KASAN that
opens vimc's sub-device nodes while vimc is unbound and rebound; with
this patch the same test shows no oops, KASAN report or warning.
Reported-by: syzbot+74de6401dbdd377b5746@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=74de6401dbdd377b5746
Fixes: 61f5db549dde ("[media] v4l: Make v4l2_subdev inherit from media_entity")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Nicola Fiorillo <nicfio@gmail.com>
---
drivers/media/v4l2-core/v4l2-subdev.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index a07d77e58..c56ca328f 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -96,6 +96,7 @@ static int subdev_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
+ struct media_device *mdev = vdev->v4l2_dev->mdev;
struct v4l2_subdev_fh *subdev_fh;
int ret;
@@ -112,10 +113,17 @@ static int subdev_open(struct file *file)
v4l2_fh_init(&subdev_fh->vfh, vdev);
v4l2_fh_add(&subdev_fh->vfh, file);
- if (sd->v4l2_dev->mdev && sd->entity.graph_obj.mdev->dev) {
+ if (mdev && mdev->dev) {
+ struct device_driver *drv = READ_ONCE(mdev->dev->driver);
struct module *owner;
- owner = sd->entity.graph_obj.mdev->dev->driver->owner;
+ /* The media device's driver has been unbound meanwhile. */
+ if (!drv) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ owner = drv->owner;
if (!try_module_get(owner)) {
ret = -EBUSY;
goto err;
--
2.47.3
next prev parent reply other threads:[~2026-10-08 4:26 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-08 4:25 [PATCH v3 0/2] media: v4l2-subdev: Fix NULL dereferences racing with unbind Nicola Fiorillo
2026-10-08 4:25 ` Nicola Fiorillo [this message]
2026-10-08 5:48 ` [PATCH v3 1/2] media: v4l2-subdev: Fix NULL pointer dereference in subdev_open() Laurent Pinchart
2026-10-08 7:06 ` Nicola Fiorillo
2026-10-09 9:48 ` Laurent Pinchart
2026-10-09 10:37 ` Nicola Fiorillo
2026-10-08 4:26 ` [PATCH v3 2/2] media: v4l2-subdev: Fix NULL pointer dereference in the EXT_CTRLS ioctls Nicola Fiorillo
2026-10-08 10:44 ` Sakari Ailus
2026-10-08 13:55 ` Nicola Fiorillo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261008042600.275884-2-nicfio@gmail.com \
--to=nicfio@gmail.com \
--cc=hverkuil@kernel.org \
--cc=laurent.pinchart@ideasonboard.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@kernel.org \
--cc=ngocthang2710.1999@gmail.com \
--cc=sakari.ailus@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox