[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250612-linux-next-25-05-30-daily-reviews-v1-2-88ba033a9a03@linaro.org>
Date: Thu, 12 Jun 2025 09:07:16 +0100
From: Bryan O'Donoghue <bryan.odonoghue@...aro.org>
To: Robert Foss <rfoss@...nel.org>, Todor Tomov <todor.too@...il.com>,
Mauro Carvalho Chehab <mchehab@...nel.org>,
Hans Verkuil <hverkuil@...all.nl>, Depeng Shao <quic_depengs@...cinc.com>,
Vladimir Zapolskiy <vladimir.zapolskiy@...aro.org>,
Hans Verkuil <hans.verkuil@...co.com>
Cc: linux-media@...r.kernel.org, linux-arm-msm@...r.kernel.org,
linux-kernel@...r.kernel.org, Bryan O'Donoghue <bryan.odonoghue@...aro.org>,
stable@...r.kernel.org, Johan Hovold <johan+linaro@...nel.org>
Subject: [PATCH 2/2] media: qcom: camss: vfe: Fix registration sequencing
bug
msm_vfe_register_entities loops through each Raw Data Interface input line.
For each loop we add video device with its associated pads.
Once a single /dev/video0 node has been populated it is possible for
camss_find_sensor_pad to run. This routine scans through a list of media
entities taking a pointer pad = media_entity->pad[0] and assuming that
pointer is always valid.
It is possible for both the enumeration loop in msm_vfe_register_entities()
and a call from user-space to run concurrently.
Adding some deliberate sleep code into the loop in
msm_vfe_register_entities() and constructing a user-space program to open
every /dev/videoX node in a tight continuous loop, quickly shows the
following error.
[ 691.074558] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000030
[ 691.074933] Call trace:
[ 691.074935] camss_find_sensor_pad+0x74/0x114 [qcom_camss] (P)
[ 691.074946] camss_get_pixel_clock+0x18/0x64 [qcom_camss]
[ 691.074956] vfe_get+0xc0/0x54c [qcom_camss]
[ 691.074968] vfe_set_power+0x58/0xf4c [qcom_camss]
[ 691.074978] pipeline_pm_power_one+0x124/0x140 [videodev]
[ 691.074986] pipeline_pm_power+0x70/0x100 [videodev]
[ 691.074992] v4l2_pipeline_pm_use+0x54/0x90 [videodev]
[ 691.074998] v4l2_pipeline_pm_get+0x14/0x20 [videodev]
[ 691.075005] video_open+0x74/0xe0 [qcom_camss]
[ 691.075014] v4l2_open+0xa8/0x124 [videodev]
[ 691.075021] chrdev_open+0xb0/0x21c
[ 691.075031] do_dentry_open+0x138/0x4c4
[ 691.075040] vfs_open+0x2c/0xe8
[ 691.075044] path_openat+0x6f0/0x10a0
[ 691.075050] do_filp_open+0xa8/0x164
[ 691.075054] do_sys_openat2+0x94/0x104
[ 691.075058] __arm64_sys_openat+0x64/0xc0
[ 691.075061] invoke_syscall+0x48/0x104
[ 691.075069] el0_svc_common.constprop.0+0x40/0xe0
[ 691.075075] do_el0_svc+0x1c/0x28
[ 691.075080] el0_svc+0x30/0xcc
[ 691.075085] el0t_64_sync_handler+0x10c/0x138
[ 691.075088] el0t_64_sync+0x198/0x19c
Taking the vfe->power_lock is not possible since
v4l2_device_register_subdev takes the mdev->graph_lock. Later on fops->open
takes the mdev->graph_lock followed by vfe_get() -> taking vfe->power_lock.
Introduce a simple enumeration_complete bool which is false initially and
only set true once in our init routine after we complete enumeration.
If user-space tries to interact with the VFE before complete enumeration it
will receive -EAGAIN.
Cc: stable@...r.kernel.org
Fixes: 4c98a5f57f90 ("media: camss: Add VFE files")
Reported-by: Johan Hovold <johan+linaro@...nel.org>
Closes: https://lore.kernel.org/all/Zwjw6XfVWcufMlqM@hovoldconsulting.com
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@...aro.org>
---
drivers/media/platform/qcom/camss/camss-vfe.c | 8 ++++++++
drivers/media/platform/qcom/camss/camss-vfe.h | 1 +
2 files changed, 9 insertions(+)
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index ac3a9579e3e6910eee8c1ec11c4fff6e1bc94443..3fccc83ebbcc84c20e17da72c359de3dfd18fb40 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -1062,6 +1062,9 @@ int vfe_get(struct vfe_device *vfe)
{
int ret;
+ if (!vfe->enumeration_complete)
+ return -EAGAIN;
+
mutex_lock(&vfe->power_lock);
if (vfe->power_count == 0) {
@@ -1122,6 +1125,9 @@ int vfe_get(struct vfe_device *vfe)
*/
void vfe_put(struct vfe_device *vfe)
{
+ if (!vfe->enumeration_complete)
+ return;
+
mutex_lock(&vfe->power_lock);
if (vfe->power_count == 0) {
@@ -2091,6 +2097,8 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
}
}
+ vfe->enumeration_complete = true;
+
return 0;
error_link:
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 614e932c33da78e02e0800ce6534af7b14822f83..33b59dcfc8b2b81e896336b079a41eba603ec400 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -169,6 +169,7 @@ struct vfe_device {
struct camss_video_ops video_ops;
struct device *genpd;
struct device_link *genpd_link;
+ bool enumeration_complete;
};
struct camss_subdev_resources;
--
2.49.0
Powered by blists - more mailing lists