From: sashiko-bot@kernel.org
To: "Sofus Forstreuter" <sofus.c@icloud.com>
Cc: devicetree@vger.kernel.org, robh@kernel.org, conor+dt@kernel.org,
media-ci@linuxtv.org
Subject: Re: [PATCH v3 11/17] arm64: dts: apple: t8103: add avd nodes
Date: Tue, 20 Oct 2026 13:27:26 +0000 [thread overview]
Message-ID: <sashiko-outbox-179022@kernel.org> (raw)
In-Reply-To: <20261020-avd-v3-11-85cbaa2125d8@icloud.com>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Critical] media: apple: avd: out-of-bounds memory accesses in HEVC tile handling
- [Critical] media: apple: avd: integer overflow and OOB access in HEVC slice handling
- [Critical] media: apple: avd: out-of-bounds accesses and error return in avd-h264.c
- [Critical] media: apple: avd: missing bounds and NULL checks in AV1 and VP9 decoders
- [High] media: apple: avd: swapped hdiv and vdiv in fill_comp()
--
commit 6d0e4afb9549b778000654c1e09e6223d962c39e
Author: Sofus Forstreuter <sofus.c@icloud.com>
arm64: dts: apple: t8103: add avd nodes
This patch adds the Apple AVD DART IOMMU and video-codec device tree nodes
for the Apple T8103 SoC, enabling the AVD V4L2 stateless video decoder.
> diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi
> index 5b68bf0df4e6b..530290e7cb32e 100644
> --- a/arch/arm64/boot/dts/apple/t8103.dtsi
> +++ b/arch/arm64/boot/dts/apple/t8103.dtsi
> @@ -984,6 +984,38 @@ pinctrl_aop: pinctrl@24a820000 {
> <AIC_IRQ 274 IRQ_TYPE_LEVEL_HIGH>;
> };
>
> + avd_dart: iommu@269010000 {
> + compatible = "apple,t8103-dart";
> + reg = <0x2 0x69010000 0x0 0x4000>;
> + interrupt-parent = <&aic>;
> + interrupts = <AIC_IRQ 547 IRQ_TYPE_LEVEL_HIGH>;
> + #iommu-cells = <1>;
> + power-domains = <&ps_avd_sys>;
> + };
> +
> + video-codec@269070000 {
> + compatible = "apple,t8103-avd";
[Severity: Critical]
Enabling the video-codec@269070000 node exposes the AVD V4L2 M2M stateless
decoder to userspace. Can crafted HEVC controls trigger out-of-bounds memory
accesses and division by zero in drivers/media/platform/apple/avd/avd-hevc.c
through avd_device_run() -> avd_hevc_run()?
First, struct v4l2_ctrl_hevc_pps defines column_width_minus1[20] and
row_height_minus1[22], and std_validate_compound() in
drivers/media/v4l2-core/v4l2-ctrls-core.c does not bound
num_tile_columns_minus1 or num_tile_rows_minus1 when
V4L2_HEVC_PPS_FLAG_TILES_ENABLED is set. However, avd_hevc_validate_pps()
allows up to HEVC_MAX_TILE_COLS (40) and HEVC_MAX_TILE_ROWS (44):
drivers/media/platform/apple/avd/avd-hevc.c:avd_hevc_validate_pps() {
if (pps->num_tile_columns_minus1 + 1 > HEVC_MAX_TILE_COLS ||
pps->num_tile_rows_minus1 + 1 > HEVC_MAX_TILE_ROWS)
return -EINVAL;
}
When compute_tiles_non_uniform() iterates up to pps->num_tile_columns_minus1
and pps->num_tile_rows_minus1:
drivers/media/platform/apple/avd/avd-hevc.c:compute_tiles_non_uniform() {
for (i = 0; i < pps->num_tile_columns_minus1; i++) {
column_width[i] = MIN(pps->column_width_minus1[i] + 1,
pic_in_cts_width);
sum += column_width[i];
}
column_width[i] = pic_in_cts_width - sum;
sum = 0;
for (i = 0; i < pps->num_tile_rows_minus1; i++) {
row_height[i] = MIN(pps->row_height_minus1[i] + 1,
pic_in_cts_height);
sum += row_height[i];
}
row_height[i] = pic_in_cts_height - sum;
}
Doesn't this read past pps->column_width_minus1[20] and
pps->row_height_minus1[22] (and past the end of struct v4l2_ctrl_hevc_pps)?
Second, in compute_tiles_non_uniform() above, each entry is only clamped
individually to pic_in_cts_width or pic_in_cts_height. If sum exceeds
pic_in_cts_width or pic_in_cts_height, won't the u16 assignment to
column_width[i] or row_height[i] underflow to a large positive value, causing
compute_bd() to produce col_bd and row_bd entries larger than
pic_in_ctbs_width and pic_in_ctbs_height, which then overflows the heap-
allocated ctb_addr_rs_to_ts and tile_ids arrays in compute_rs_to_ts() and
compute_tile_ids()?
drivers/media/platform/apple/avd/avd-hevc.c:compute_tile_ids() {
for (j = 0, tile_idx = 0; j <= pps->num_tile_rows_minus1; j++)
for (i = 0; i <= pps->num_tile_columns_minus1; i++, tile_idx++)
for (y = row_bd[j]; y < row_bd[j + 1]; y++)
for (x = col_bd[i]; x < col_bd[i + 1]; x++)
tile_ids[ctb_addr_rs_to_ts
[y * pic_in_ctbs_width +
x]] = tile_idx;
}
Third, avd_hevc_validate_sps() does not reject zero
pic_width_in_luma_samples / pic_height_in_luma_samples or out-of-range
log2_min_luma_coding_block_size_minus3 /
log2_diff_max_min_luma_coding_block_size. In avd_hevc_compute_tiles():
drivers/media/platform/apple/avd/avd-hevc.c:avd_hevc_compute_tiles() {
max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size +
log2_min_cb_size);
pic_in_ctbs_width = (width + max_cu_width - 1) / max_cu_width;
pic_in_ctbs_height = (height + max_cu_width - 1) / max_cu_width;
pic_in_ctbs_size = pic_in_ctbs_height * pic_in_ctbs_width;
}
Can this shift out of bounds and divide by zero before avd_hevc_alloc_scratch()
checks if (!max_cu_width), or result in ZERO_SIZE_PTR dereferences when width
or height is zero?
[Severity: Critical]
In drivers/media/platform/apple/avd/avd-hevc.c, can avd_hevc_run_preamble()
and stream_slices() also overflow when validating and iterating HEVC slice
segments?
In avd_hevc_run_preamble(), sum is a 32-bit signed int accumulating __u32
num_entry_point_offsets across up to 1800 slices:
drivers/media/platform/apple/avd/avd-hevc.c:avd_hevc_run_preamble() {
for (i = 0; i < run->num_slices; i++)
sum += (*run->sl)[i].num_entry_point_offsets;
if (sum && sum != run->num_entry_point_offsets)
return -EINVAL;
}
Since std_validate_compound() does not bound num_entry_point_offsets, can
crafted values (for example, sl[0].num_entry_point_offsets = 2 and
sl[1].num_entry_point_offsets = 0xfffffffe) overflow sum to 0 or a small
value matching run->num_entry_point_offsets? That causes avd_init_job() to
allocate only run.num_slices + run.num_entry_point_offsets + 1 segments in
ctx->job.segments while stream_slices() loops sl->num_entry_point_offsets + 1
times, reading past (*run->entry_point_offsets) and writing past
ctx->job.segments via push() and avd_end_segment().
Additionally, in stream_slices(), pos is incremented for every segment with
NEW_TILE_ID:
drivers/media/platform/apple/avd/avd-hevc.c:stream_slices() {
row = pos / num_cols;
col = pos % num_cols;
}
and passed to submit_slice_segment():
drivers/media/platform/apple/avd/avd-hevc.c:submit_slice_segment() {
if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED)
push(AVD_SL_DIM_END_ROW((hflip ? 4 : 0) |
(vflip ? 8 : 0)) |
AVD_SL_DIM_END_COL(col) |
AVD_SL_DIM_END_Y(row_bd[row + 1] - 1) |
AVD_SL_DIM_END_X(col_bd[col + 1] - 1),
"cm3_set_ctb_xy");
}
Without checking that row <= pps->num_tile_rows_minus1, won't pos / num_cols
exceed HEVC_MAX_TILE_ROWS and read row_bd[row] and row_bd[row + 1] out of
bounds on the stack?
[Severity: Critical]
In drivers/media/platform/apple/avd/avd-h264.c (enabled on T8103 via
AVD_CAPABILITY_H264), are there also out-of-bounds accesses and an uninitialized
error return reachable from userspace?
1. In stream_slice(), sl->ref_pic_list1[0].index is an unvalidated u8 from
V4L2_CID_STATELESS_H264_SLICE_PARAMS (not checked by std_validate_compound()
in drivers/media/v4l2-core/v4l2-ctrls-core.c):
drivers/media/platform/apple/avd/avd-h264.c:stream_slice() {
/* sl->ref_pic_list1[0].index < ARRAY_SIZE(decode->dpb) */
/* bidirectional reference of previous mv */
ref = avd_get_ref_buf(
ctx, &dst->base.vb,
decode->dpb[sl->ref_pic_list1[0].index].reference_ts);
}
Doesn't this read past the 16-entry decode->dpb array when index >= 16?
2. In avd_h264_realloc_slices(), when h264_ctx->slice_num reaches
h264_ctx->alloc_slice_num, job->num is already alloc_slice_num + 1 (1 header
segment from stream_hdr() plus alloc_slice_num slice segments from
stream_slice()), matching the allocated capacity of job->buf.cpu:
drivers/media/platform/apple/avd/avd-h264.c:avd_h264_realloc_slices() {
memcpy(job->segments, job->buf.cpu,
sizeof(*job->segments) * (job->num + 1));
}
Won't copying job->num + 1 entries read one struct avd_segment past the end of
job->buf.cpu (and if job->buf.size is already large enough earlier in
avd_h264_realloc_slices(), return 0 without updating job->num_alloc)?
3. In avd_h264_run(), avd_h264_realloc_slices() is only called when
ctx->job.segments is non-NULL:
drivers/media/platform/apple/avd/avd-h264.c:avd_h264_run() {
if (ctx->job.segments &&
h264_ctx->slice_num >= h264_ctx->alloc_slice_num) {
ret = avd_h264_realloc_slices(ctx);
if (ret)
goto postamble;
}
h264_ctx->active_slice = &h264_ctx->slices[h264_ctx->slice_num];
}
Since avd_h264_done() only resets h264_ctx->slice_num when
V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF is not set, what happens if userspace
submits slices with first_mb_in_slice != 0 and
V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF set? With ctx->job.segments still NULL,
won't h264_ctx->slice_num increment past h264_ctx->alloc_slice_num and write
past the end of h264_ctx->slices?
4. In avd_h264_start(), ret is 0 after avd_h264_validate_sps() succeeds:
drivers/media/platform/apple/avd/avd-h264.c:avd_h264_start() {
h264_ctx->slices = kzalloc_objs(*h264_ctx->slices,
h264_ctx->alloc_slice_num, GFP_KERNEL);
if (!h264_ctx->slices)
goto err_free_ctx;
}
If kzalloc_objs() fails here, doesn't avd_h264_start() free h264_ctx, set
ctx->priv = NULL, and return 0 to avd_start_streaming(), causing a NULL
pointer dereference in avd_h264_run()?
[Severity: Critical]
In drivers/media/platform/apple/avd/avd-vp9.c and
drivers/media/platform/apple/avd/avd-av1.c, could several missing bounds and
NULL checks cause crashes or out-of-bounds memory accesses?
1. In avd-vp9.c (enabled on T8103 via AVD_CAPABILITY_VP9), set_tiles() calls
vb2_plane_vaddr() on a VB2_DMABUF-capable queue:
drivers/media/platform/apple/avd/avd-vp9.c:set_tiles() {
const u8 *data = vb2_plane_vaddr(&src->vb2_buf, 0);
...
tile_size = get_unaligned_be32(&data[offset]);
}
and in avd-av1.c, avd_av1_set_prob() also calls vb2_plane_vaddr() without
checking for NULL:
drivers/media/platform/apple/avd/avd-av1.c:avd_av1_set_prob() {
memcpy(vb2_plane_vaddr(&dst->base.vb.vb2_buf, 0) +
AVD_AV1_CDFS_OFFSET(dst->base.vb.vb2_buf.planes[0].length,
dst->av1.color_size),
av1_ctx->bufs.probs.cpu, sizeof(struct avd_av1_cdfs));
}
Since vb2_dc_vaddr() returns NULL if dma_buf_vmap_unlocked() fails or is not
supported by the exporter, can these dereference NULL?
2. In avd_av1_set_prob() above, neither validate_av1_frame() nor avd-av1.c
validates frame->frame_width_minus_1 + 1 and frame->frame_height_minus_1 + 1
against the CAPTURE buffer dimensions. If update_dec_buf_info() computes
dst->av1.color_size larger than dst->base.vb.vb2_buf.planes[0].length, won't
AVD_AV1_CDFS_OFFSET() underflow and cause memcpy() to write out of bounds
before the buffer?
3. In drivers/media/platform/apple/avd/avd-av1.c:set_tiles(), __u32
tile_group->tile_row and tile_group->tile_col are assigned to signed int
before the bounds check:
drivers/media/platform/apple/avd/avd-av1.c:set_tiles() {
tile_row = tile_group->tile_row;
tile_col = tile_group->tile_col;
if (tile_col >= V4L2_AV1_MAX_TILE_COLS ||
tile_row >= V4L2_AV1_MAX_TILE_ROWS)
return -EINVAL;
}
Can values >= 0x80000000 become negative, bypass this check, and index
tile_info arrays out of bounds?
4. In drivers/media/platform/apple/avd/avd-av1.c:set_ref_hdr(),
frame->ref_frame_idx[i] (__s8) is not validated by validate_av1_frame():
drivers/media/platform/apple/avd/avd-av1.c:set_ref_hdr() {
if (frame->reference_frame_ts[frame->ref_frame_idx[i]] ==
frame->reference_frame_ts[frame->ref_frame_idx[j]]) {
}
Can negative or out-of-range ref_frame_idx values index out of bounds of
frame->reference_frame_ts[8]? Similarly, avd_av1_get_ref_buf() checks idx
against V4L2_AV1_TOTAL_REFS_PER_FRAME (8) instead of V4L2_AV1_REFS_PER_FRAME
(7) before indexing frame->ref_frame_idx[7], and avd_av1_set_prob() only
checks primary_ref_frame == 7 rather than >= V4L2_AV1_REFS_PER_FRAME.
5. In drivers/media/platform/apple/avd/avd-av1.c:avd_av1_run_preamble():
drivers/media/platform/apple/avd/avd-av1.c:avd_av1_run_preamble() {
if (run->frame->tile_info.tile_cols * run->frame->tile_info.tile_rows >
ctrl->new_elems)
return -EINVAL;
}
Should this check ctrl->elems instead of ctrl->new_elems when reading from
ctrl->p_cur.p?
6. In drivers/media/platform/apple/avd/avd-av1.c:calc_upscale():
drivers/media/platform/apple/avd/avd-av1.c:calc_upscale() {
*step_x = ((downscaled_plane_w << SUPERRES_SCALE_BITS) +
(upscaled_plane_w / 2)) /
upscaled_plane_w;
}
If frame->upscaled_width is 0, won't upscaled_plane_w be 0 and trigger a
division by zero?
7. In drivers/media/platform/apple/avd/avd-av1.c:set_refs(), alpha, beta,
gamma, and delta are declared outside the reference loop:
drivers/media/platform/apple/avd/avd-av1.c:set_refs() {
s64 alpha = 0, beta = 0, gamma = 0, delta = 0;
}
Since avd_av1_dec_get_shear_params() returns early without clearing its output
parameters when mat[2] <= 0, won't a subsequent reference frame reuse stale
shear parameters from an earlier iteration?
[Severity: High]
In drivers/media/platform/apple/avd/avd-drv.c, are info->vdiv and info->hdiv
swapped when fill_comp() calculates the UV plane size and metadata?
drivers/media/platform/apple/avd/avd-drv.c:fill_comp() {
/* uv has 16x16 tiles and 8 bytes of metadata per tile */
calc_tile_meta(width / info->vdiv, height / info->hdiv,
v4l2_format_info_bpp(info, 1), 16, 8, &uv,
&uv_meta);
}
In drivers/media/v4l2-core/v4l2-common.c:v4l2_format_info(), the 4:2:2 formats
V4L2_PIX_FMT_APPLE_AX16 and V4L2_PIX_FMT_APPLE_AX23 define .hdiv = 2 and
.vdiv = 1. Passing width / info->vdiv and height / info->hdiv to
calc_tile_meta(u32 w, u32 h, ...) divides width by 1 and height by 2 instead
of width / info->hdiv and height / info->vdiv, which miscalculates the UV tile
count, UV metadata offset (comp->offsets[2]), and total buffer size
(comp->size) whenever width or height is an odd multiple of 16.
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-avd-v3-0-85cbaa2125d8@icloud.com?part=11
next prev parent reply other threads:[~2026-10-20 13:27 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-20 9:37 [PATCH v3 00/17] media: apple: add avd driver Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 01/17] dt-bindings: media: add apple,avd Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 02/17] media: v4l2: Add P210 pixel format Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 03/17] media: v4l2: Add Apple interchange pixel formats Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:56 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 04/17] media: v4l2-ctrls: validate av1 tile info Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 10:10 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 05/17] media: v4l2-ctrls: validate vp9 tile_rows_log2 Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 06/17] media: apple: add avd driver Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 10:34 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 07/17] media: apple: avd: add h264 support Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 10:55 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 08/17] media: apple: avd: add vp9 support Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 11:22 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 09/17] media: apple: avd: add hevc support Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 11:40 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 10/17] media: apple: avd: add av1 support Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 12:50 ` sashiko-bot
2026-10-20 9:37 ` [PATCH v3 11/17] arm64: dts: apple: t8103: add avd nodes Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 13:27 ` sashiko-bot [this message]
2026-10-20 9:37 ` [PATCH v3 12/17] arm64: dts: apple: t8112: " Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 13/17] arm64: dts: apple: t8122: " Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 14/17] arm64: dts: apple: t600x: " Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 15/17] arm64: dts: apple: t602x: " Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 16/17] arm64: dts: apple: t6030: " Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
2026-10-20 9:37 ` [PATCH v3 17/17] arm64: dts: apple: t6031: " Sofus Forstreuter
2026-10-20 9:37 ` Sofus Forstreuter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-179022@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=media-ci@linuxtv.org \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=sofus.c@icloud.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.