Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] media: rkvdec: hevc: cap EXT SPS RPS control counts before descriptor assembly
@ 2026-05-13 18:19 Michael Bommarito
  0 siblings, 0 replies; only message in thread
From: Michael Bommarito @ 2026-05-13 18:19 UTC (permalink / raw)
  To: Detlev Casanova, Ezequiel Garcia, Mauro Carvalho Chehab,
	Heiko Stuebner, linux-media
  Cc: linux-rockchip, linux-arm-kernel, linux-kernel

V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS and
V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS are registered as dynamic-size
controls with a per-control element cap of 65. The V4L2 control core
enforces only the payload-element cap. It does not bound the spec-derived
count fields that the rkvdec HEVC helper later uses to walk fixed hardware
descriptor tables and temporary helper arrays:

  - struct rkvdec_rps::refs[32]
  - struct rkvdec_rps::short_term_ref_sets[64]
  - struct calculated_rps_st_set::delta_poc_s0[16] / delta_poc_s1[16]

A userspace V4L2 client that can open the Rockchip RKVDEC m2m decoder node
may submit SPS/RPS controls whose counts exceed those capacities or whose
prediction reference index underflows. rkvdec_hevc_assemble_hw_rps() then
walks past the descriptor table or temporary-array bounds.

KASAN under a small KUnit harness wrapping the real helper reports
slab-out-of-bounds in all of:

  - num_short_term_ref_pic_sets = 65 (write past short_term_ref_sets[64])
  - num_long_term_ref_pics_sps = 33  (write past refs[32], intra-struct)
  - ext_sps_st_rps[i].num_negative_pics or num_positive_pics > 16
    (write past delta_poc_s0[16] inside calculated_rps_st_set)
  - INTER_REF_PIC_SET_PRED with delta_idx_minus1 + 1 > i
    (u8 ref_rps_idx underflow then OOB read on calculated_rps_st_sets)

Validate the SPS/RPS counts before calling the assembly helpers. The cap
values match both the HEVC spec ranges (num_short_term_ref_pic_sets <= 64,
num_long_term_ref_pics_sps <= 32) and the fixed driver descriptor and
helper-array capacities. Reject controls whose counts exceed those, and
reject prediction entries whose reference index would underflow.

Fixes: c9a59dc2acc7 ("media: rkvdec: Add HEVC support for the VDPU381 variant")
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
---

I don't have a RK3588 / RK3576 board to confirm this through a real
/dev/videoN request path yet, but was convinced enough by:

  1. Static reach: registration of EXT_SPS_ST_RPS / EXT_SPS_LT_RPS with
     .dims = { 65 } at drivers/media/platform/rockchip/rkvdec/rkvdec.c
     :239-287, the SPS-count-driven loops in rkvdec-hevc-common.c
     :213-225 and :228-251, and v4l2-ctrls-core.c :1213-1277, which
     validates only EXT RPS flags and not the spec-derived count fields.

  2. A KUnit harness (separate, not in this patch) that allocates one
     struct rkvdec_rps + a single calculated_rps_st_sets element via
     kunit_kzalloc / kzalloc and calls the real
     rkvdec_hevc_assemble_hw_rps() helper. Under UML + KASAN_GENERIC with
     the kasan_multi_shot boot param, on a stock tree it produces these
     reports:

       BUG: KASAN: slab-out-of-bounds in
         rkvdec_hevc_assemble_hw_rps+0xb0c/0x1080
         (num_short_term_ref_pic_sets = 65, write of size 36 0 bytes past
         the rps allocation)

       BUG: KASAN: slab-out-of-bounds in
         rkvdec_hevc_assemble_hw_rps (num_negative_pics = 64, write past
         the single-element kzalloc'd calculated_rps_st_sets buffer)

       BUG: KASAN: slab-use-after-free / slab-out-of-bounds reads via
         u8 ref_rps_idx underflow at calculated_rps_st_sets[255]
         (INTER_REF_PIC_SET_PRED with delta_idx_minus1 = 0, idx = 0)

     The num_long_term_ref_pics_sps = 33 case is invisible to KASAN
     (the OOB write lands inside struct rkvdec_rps) but corrupts
     short_term_ref_sets[0]; the harness asserts that case explicitly.

  3. Same harness on the patched tree: all five cases (four adversarial
     plus a legitimate-limit regression with ST=64, LT=32, num_neg=1)
     pass clean, no KASAN reports.

If hardware-side validation actually does reject these counts before
rkvdec_hevc_assemble_hw_rps() runs and this patch is unnecessary, please
say so and I will withdraw it. If it is reachable, I will follow up with
a runtime hardware splat once the Orange Pi board I bought arrives.

Let me know if you want a patch set with the KUnit harnesses too.

checkpatch.pl: 0 errors / 0 warnings.

 .../rockchip/rkvdec/rkvdec-hevc-common.c      | 49 +++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
index 3119f3bc9f98..895fb16bc572 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
@@ -408,9 +408,58 @@ static void rkvdec_hevc_prepare_hw_st_rps(struct rkvdec_hevc_run *run, struct rk
 	memcpy(cache, run->ext_sps_st_rps, sizeof(struct v4l2_ctrl_hevc_ext_sps_st_rps));
 }
 
+/*
+ * V4L2 caps the EXT_SPS RPS payload length but not the SPS-derived counts
+ * that the helpers walk. Caps match the HEVC spec ranges.
+ */
+#define RKVDEC_HEVC_MAX_SHORT_TERM_REF_PIC_SETS	64
+#define RKVDEC_HEVC_MAX_LONG_TERM_REF_PICS_SPS	32
+#define RKVDEC_HEVC_MAX_RPS_NEG_POS_PICS	16
+
+static int rkvdec_hevc_validate_rps_ctrls(struct rkvdec_hevc_run *run)
+{
+	const struct v4l2_ctrl_hevc_sps *sps = run->sps;
+
+	if (run->ext_sps_lt_rps &&
+	    sps->num_long_term_ref_pics_sps >
+	    RKVDEC_HEVC_MAX_LONG_TERM_REF_PICS_SPS)
+		return -EINVAL;
+
+	if (run->ext_sps_st_rps) {
+		unsigned int i;
+
+		if (sps->num_short_term_ref_pic_sets >
+		    RKVDEC_HEVC_MAX_SHORT_TERM_REF_PIC_SETS)
+			return -EINVAL;
+
+		for (i = 0; i < sps->num_short_term_ref_pic_sets; i++) {
+			const struct v4l2_ctrl_hevc_ext_sps_st_rps *r =
+				&run->ext_sps_st_rps[i];
+
+			if (r->num_negative_pics >
+			    RKVDEC_HEVC_MAX_RPS_NEG_POS_PICS ||
+			    r->num_positive_pics >
+			    RKVDEC_HEVC_MAX_RPS_NEG_POS_PICS)
+				return -EINVAL;
+
+			if ((r->flags &
+			     V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED) &&
+			    (unsigned int)r->delta_idx_minus1 + 1 > i)
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 void rkvdec_hevc_assemble_hw_rps(struct rkvdec_hevc_run *run, struct rkvdec_rps *rps,
 				 struct v4l2_ctrl_hevc_ext_sps_st_rps *st_cache)
 {
+	if (rkvdec_hevc_validate_rps_ctrls(run)) {
+		pr_err_ratelimited("rkvdec: rejecting HEVC SPS/RPS controls with out-of-range counts\n");
+		return;
+	}
+
 	rkvdec_hevc_prepare_hw_st_rps(run, rps, st_cache);
 	rkvdec_hevc_assemble_hw_lt_rps(run, rps);
 }
-- 
2.53.0



^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-05-13 18:19 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-13 18:19 [PATCH] media: rkvdec: hevc: cap EXT SPS RPS control counts before descriptor assembly Michael Bommarito

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox