drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
media_pad_remote_pad_first() may return NULL when the media link is absent
or disabled. The code dereferenced remote_pad->entity unconditionally in
ipu6_isys_csi2_enable_streams() and ipu6_isys_csi2_disable_streams(),
leading to a possible NULL dereference.
Guard the remote pad/subdev: in enable path return -ENOLINK/-ENODEV, in
disable path always shut down the local stream first and return 0 if the
remote side is missing. This keeps local shutdown semantics intact and
prevents a crash when the graph is partially torn down.
Also, ipu6_isys_csi2_calc_timing() passes link_freq into calc_timing()
where it is used as a divisor. v4l2_get_link_freq() may yield 0; add an
explicit check and return -EINVAL to avoid division by zero.
Found by Linux Verification Center (linuxtesting.org) with SVACE.
Fixes: 3a5c59ad926b ("media: ipu6: Rework CSI-2 sub-device streaming control")
Cc: stable@vger.kernel.org
Signed-off-by: Alexei Safin <a.safin@rosa.ru>
---
drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
index d1fece6210ab..58944918c344 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
@@ -171,6 +171,10 @@ ipu6_isys_csi2_calc_timing(struct ipu6_isys_csi2 *csi2,
if (link_freq < 0)
return link_freq;
+ /* Avoid division by zero in calc_timing() if link frequency is zero */
+ if (!link_freq)
+ return -EINVAL;
+
timing->ctermen = calc_timing(CSI2_CSI_RX_DLY_CNT_TERMEN_CLANE_A,
CSI2_CSI_RX_DLY_CNT_TERMEN_CLANE_B,
link_freq, accinv);
@@ -352,7 +356,12 @@ static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
int ret;
remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
+ if (!remote_pad)
+ return -ENOLINK;
+
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+ if (!remote_sd)
+ return -ENODEV;
sink_streams =
v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK,
@@ -389,7 +398,16 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
&streams_mask);
remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
+ if (!remote_pad) {
+ ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
+ return 0;
+ }
+
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+ if (!remote_sd) {
+ ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
+ return 0;
+ }
ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
--
2.50.1 (Apple Git-155)
© 2016 - 2025 Red Hat, Inc.