Re: [PATCH] media: cedrus: validate H.264 reference list indices

From: Jernej Škrabec

Date: Tue Mar 24 2026 - 04:14:43 EST


CC: Nicolas

Dne torek, 24. marec 2026 ob 03:04:31 Srednjeevropski standardni čas je Pengpeng Hou napisal(a):
> Cedrus validates HEVC slice reference lists in cedrus_try_ctrl(), but
> the H.264 path still consumes ref_pic_list0/ref_pic_list1 indices
> straight from the stateless slice control. Those indices are later
> used to index the fixed-size decode_params->dpb[] array in
> _cedrus_write_ref_list().
>
> Reject H.264 slice controls whose active reference counts or
> reference indices exceed V4L2_H264_NUM_DPB_ENTRIES before the driver
> reaches the DPB lookup. This keeps the validation next to the existing
> Cedrus stateless control checks and avoids driver-specific
> out-of-bounds reads from malformed userspace control payloads.
>
> Signed-off-by: Pengpeng Hou <pengpeng@xxxxxxxxxxx>

This has same issue as doing it in common code, e.g. it would break
userspace.

One improvement would be to skip all indices which have value higher
or equal to V4L2_H264_NUM_DPB_ENTRIES here:

https://elixir.bootlin.com/linux/v6.19.9/source/drivers/staging/media/sunxi/cedrus/cedrus_h264.c#L212

Best regards,
Jernej

> ---
> drivers/staging/media/sunxi/cedrus/cedrus.c | 23 +++++++++++++++++++++
> 1 file changed, 23 insertions(+)
>
> diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
> index d68da1eaa7aa..905084c097a9 100644
> --- a/drivers/staging/media/sunxi/cedrus/cedrus.c
> +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
> @@ -42,6 +42,29 @@ static int cedrus_try_ctrl(struct v4l2_ctrl *ctrl)
> if (sps->bit_depth_luma_minus8 != 0)
> /* Only 8-bit is supported */
> return -EINVAL;
> + } else if (ctrl->id == V4L2_CID_STATELESS_H264_SLICE_PARAMS) {
> + const struct v4l2_ctrl_h264_slice_params *slice = ctrl->p_new.p_h264_slice_params;
> + unsigned int i;
> +
> + if (slice->num_ref_idx_l0_active_minus1 >=
> + V4L2_H264_NUM_DPB_ENTRIES)
> + return -EINVAL;
> +
> + for (i = 0; i <= slice->num_ref_idx_l0_active_minus1; i++)
> + if (slice->ref_pic_list0[i].index >=
> + V4L2_H264_NUM_DPB_ENTRIES)
> + return -EINVAL;
> +
> + if (slice->slice_type == V4L2_H264_SLICE_TYPE_B) {
> + if (slice->num_ref_idx_l1_active_minus1 >=
> + V4L2_H264_NUM_DPB_ENTRIES)
> + return -EINVAL;
> +
> + for (i = 0; i <= slice->num_ref_idx_l1_active_minus1; i++)
> + if (slice->ref_pic_list1[i].index >=
> + V4L2_H264_NUM_DPB_ENTRIES)
> + return -EINVAL;
> + }
> } else if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS) {
> const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
> struct cedrus_ctx *ctx = container_of(ctrl->handler, struct cedrus_ctx, hdl);
>