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);