From: Nicola Fiorillo <nicfio@gmail.com>
To: linux-media@vger.kernel.org
Cc: mchehab@kernel.org, sakari.ailus@linux.intel.com,
bingbu.cao@intel.com, tian.shu.qiu@intel.com,
linux-kernel@vger.kernel.org, Nicola Fiorillo <nicfio@gmail.com>
Subject: [PATCH 2/3] media: v4l2-subdev: Check v4l2_dev before dereferencing it in open()
Date: Wed, 12 Aug 2026 12:53:04 +0200 [thread overview]
Message-ID: <20260812105305.32447-3-nicfio@gmail.com> (raw)
In-Reply-To: <20260812105305.32447-1-nicfio@gmail.com>
Unbinding a sensor driver while something opens its /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, and only then unregisters the device node. Until the node is
gone userspace can still open it, and subdev_open() dereferences
sd->v4l2_dev unconditionally. The faulting address is the offset of the
mdev member in struct v4l2_device.
The window is not a narrow one: media_device_unregister_entity() sleeps,
and the first oops seen here was not provoked at all, it was hit by v4l_id,
run by udev on the very node that was appearing and disappearing.
The same window leaves sd->entity.graph_obj.mdev NULL while
sd->v4l2_dev->mdev is not, and the second dereference on that line goes
through it. That one was found by reading the teardown path, not by
crashing on it; it arrived later, with commit 218bf10e39ed ("media:
v4l2-subdev: handle module refcounting here").
Unregistering the device node before clearing the pointers would narrow the
window but not close it, because v4l2_open() drops videodev_lock before it
calls fops->open() and the whole of v4l2_device_unregister_subdev() can run
in between. Check the pointers in subdev_open() instead.
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*. The code is unchanged in 7.2-rc7.
Fixes: 61f5db549dde ("[media] v4l: Make v4l2_subdev inherit from media_entity")
Signed-off-by: Nicola Fiorillo <nicfio@gmail.com>
---
drivers/media/v4l2-core/v4l2-subdev.c | 31 +++++++++++++++++++++------
1 file changed, 25 insertions(+), 6 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index e9f81b9be..2a47b9730 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -97,8 +97,19 @@ static int subdev_open(struct file *file)
struct video_device *vdev = video_devdata(file);
struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
struct v4l2_subdev_fh *subdev_fh;
+ struct v4l2_device *v4l2_dev;
int ret;
+ /*
+ * v4l2_device_unregister_subdev() clears sd->v4l2_dev and unregisters
+ * the entity before it unregisters the device node, so an open() that
+ * races with the sub-device going away lands here with those pointers
+ * already gone.
+ */
+ v4l2_dev = READ_ONCE(sd->v4l2_dev);
+ if (!v4l2_dev)
+ return -ENODEV;
+
subdev_fh = kzalloc_obj(*subdev_fh);
if (subdev_fh == NULL)
return -ENOMEM;
@@ -112,15 +123,23 @@ 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) {
- struct module *owner;
+ if (v4l2_dev->mdev) {
+ struct media_device *mdev = READ_ONCE(sd->entity.graph_obj.mdev);
- owner = sd->entity.graph_obj.mdev->dev->driver->owner;
- if (!try_module_get(owner)) {
- ret = -EBUSY;
+ if (!mdev) {
+ ret = -ENODEV;
goto err;
}
- subdev_fh->owner = owner;
+
+ if (mdev->dev) {
+ struct module *owner = mdev->dev->driver->owner;
+
+ if (!try_module_get(owner)) {
+ ret = -EBUSY;
+ goto err;
+ }
+ subdev_fh->owner = owner;
+ }
}
if (sd->internal_ops && sd->internal_ops->open) {
--
2.47.3
next prev parent reply other threads:[~2026-08-12 10:53 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-12 10:53 [PATCH 0/3] media: Two oopses and a hang when unbinding a streaming sensor Nicola Fiorillo
2026-08-12 10:53 ` [PATCH 1/3] media: ipu6: Check the remote pad before dereferencing it Nicola Fiorillo
2026-08-12 10:53 ` Nicola Fiorillo [this message]
2026-08-12 10:53 ` [PATCH 3/3] media: ipu6: Signal the video queues when a sensor is unbound 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=20260812105305.32447-3-nicfio@gmail.com \
--to=nicfio@gmail.com \
--cc=bingbu.cao@intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@kernel.org \
--cc=sakari.ailus@linux.intel.com \
--cc=tian.shu.qiu@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.