From: sashiko-bot@kernel.org
To: "Sofus Forstreuter" <sofus.c@icloud.com>
Cc: robh@kernel.org, devicetree@vger.kernel.org,
media-ci@linuxtv.org, conor+dt@kernel.org
Subject: Re: [PATCH 12/14] media: apple: avd: add vp9 support
Date: Fri, 18 Sep 2026 13:42:45 +0000 [thread overview]
Message-ID: <20260918134245.CFAE61F00898@smtp.kernel.org> (raw)
In-Reply-To: <20260918-avd-v1-12-49977931f455@icloud.com>
Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:
- [Critical] media: avd: vp9: heap buffer overflow via unvalidated tile_rows_log2
- [High] media: avd: vp9: integer underflow in set_tiles payload size calculation
- [High] media: avd: vp9: out-of-bounds read in avd_vp9_done due to wrong sizeof
- [High] media: avd: vp9: missing arithmetic carry in 64-bit DMA address calculation
- [High] media: avd: vp9: submit_num integer overflow causes missing submissions
- [High] media: avd: vp9: DMA buffer overflow due to missing tile_cols_log2 limit
- [High] media: avd: vp9: TOCTOU race via lockless v4l2_ctrl_vp9_frame access
- [Medium] media: avd: vp9: memory leak on error paths in avd_vp9_alloc_bufs
--
commit 949a9d5ecad27ff345d8f7547131d2a836e7879d
Author: Sofus Forstreuter <sofus.c@icloud.com>
media: apple: avd: add vp9 support
This commit adds hardware video decoding support for VP9 on Apple Silicon
devices via the Apple Video Decoder (AVD). It implements VP9-specific V4L2
controls and formats, along with state management and hardware command
submission.
> diff --git a/drivers/media/platform/apple/avd/avd-vp9.c b/drivers/media/platform/apple/avd/avd-vp9.c
> new file mode 100644
> index 0000000000000..76599a1a39811
> --- /dev/null
> +++ b/drivers/media/platform/apple/avd/avd-vp9.c
> @@ -0,0 +1,1072 @@
[ ... ]
> +struct avd_vp9_ctx {
> + struct v4l2_vp9_frame_symbol_counts cnts;
> + struct v4l2_vp9_frame_context probability_tables;
> + struct v4l2_vp9_frame_context frame_context[4];
> + struct avd_vp9_bufs {
[ ... ]
> + struct avd_buf probs;
> + } bufs;
> + struct avd_vp9_frame_info cur;
> + struct avd_vp9_frame_info last;
> + u8 submit_num;
[Severity: High]
Since submit_num in struct avd_vp9_ctx is an 8-bit integer, will it overflow
if a frame contains up to 4096 tiles (e.g. 64 rows * 64 columns)?
> +};
[ ... ]
> +static void set_tiles(struct avd_ctx *ctx, struct avd_vp9_run *run)
> +{
> + const struct v4l2_ctrl_vp9_frame *frame = run->decode_params;
> + struct avd_vp9_ctx *vp9_ctx = ctx->priv;
> + struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
> + const u8 *data = vb2_plane_vaddr(&src->vb2_buf, 0);
> +
> + u32 offset =
> + frame->uncompressed_header_size + frame->compressed_header_size;
> + u32 size = vb2_get_plane_payload(&src->vb2_buf, 0) - offset;
[Severity: High]
If offset is larger than the actual buffer payload, could size underflow
and become a very large 32-bit integer?
This would bypass the bounds check below:
if (tile_size > size - 4)
return;
and allow out-of-bounds kernel memory reads when reading the tile size.
> + u32 num_tile_rows = 1 << frame->tile_rows_log2;
> + u32 num_tile_cols = 1 << frame->tile_cols_log2;
> + u32 tile_size;
[ ... ]
> + if (row == num_tile_rows - 1 &&
> + col == num_tile_cols - 1) {
> + tile_size = size;
> + } else {
> + tile_size = get_unaligned_be32(&data[offset]);
> + /* i have crashed my computer because of this */
> + if (tile_size > size - 4)
> + return;
> + offset += 4;
> + size -= 4;
> + }
> + push(AVD_OP_CODED_DATA |
> + AVD_OP_CODED_DATA_ADDR(
> + run->base.coded_in >> 32),
> + "cm3_cmd_set_slice_data");
> + push((u32)((run->base.coded_in + offset) & 0xffffffff),
> + "til_ab4_tile_addr_low");
[Severity: High]
Does this DMA address calculation drop the arithmetic carry?
The upper 32 bits use run->base.coded_in >> 32, but the lower 32 bits are
(run->base.coded_in + offset) & 0xffffffff.
If adding offset causes the lower 32 bits to wrap, the hardware will receive
an incorrect 64-bit address for DMA reads.
> + push(tile_size, "til_ab8_tile_size");
[ ... ]
> +static int avd_vp9_alloc_bufs(struct avd_ctx *ctx)
> +{
> + struct avd_dev *avd = ctx->dev;
> + struct avd_vp9_ctx *vp9_ctx = ctx->priv;
> + int ret, w, h, bit_depth;
> +
> + w = fmt_width(ctx);
> + h = fmt_height(ctx);
> + bit_depth = (ctx->image_fmt == AVD_IMG_FMT_420_10BIT ||
> + ctx->image_fmt == AVD_IMG_FMT_422_10BIT) ?
> + 10 :
> + 8;
> +
> + ret = avd_buf_alloc(avd, &vp9_ctx->bufs.probs,
> + sizeof(struct avd_vp9_probs));
> + if (ret)
> + return ret;
[Severity: Medium]
If any allocation fails here and returns early, doesn't this leak the already
allocated DMA buffers?
The error path in avd_vp9_start() only frees vp9_ctx without calling
avd_buf_free() on the successful allocations.
[ ... ]
> + ret = avd_buf_alloc(avd, &vp9_ctx->bufs.ip_above,
> + DIV_ROUND_UP(w, 16) * 4 * bit_depth +
> + (VP9_MAX_TILE_COLS - 1) * 128);
[Severity: High]
Since ip_above is sized based on VP9_MAX_TILE_COLS (which is hardcoded to 16),
what happens if userspace requests a frame with up to 64 tile columns?
Without bounds checking on tile_cols_log2 in validate_dec_params(), the
hardware could overwrite past the end of this DMA buffer.
> + if (ret)
> + return ret;
[ ... ]
> +static int validate_dec_params(struct avd_ctx *ctx,
> + const struct v4l2_ctrl_vp9_frame *dec_params)
> +{
> + unsigned int aligned_width, aligned_height;
> +
> + if (dec_params->bit_depth > 10)
> + /* not implemented */
> + return -EINVAL;
> +
> + if (dec_params->profile == 1 || dec_params->profile > 2)
> + return -EINVAL;
> +
> + if (dec_params->frame_height_minus_1 + 1 < 64 ||
> + dec_params->frame_width_minus_1 + 1 < 64)
> + return -EINVAL;
[Severity: High]
Should there be a check here to ensure dec_params->tile_cols_log2 <= 4 to
prevent the hardware from exceeding the statically sized buffers based on
VP9_MAX_TILE_COLS?
[ ... ]
> +static int avd_vp9_run_preamble(struct avd_ctx *ctx, struct avd_vp9_run *run)
> +{
> + struct v4l2_ctrl *ctrl;
> + const struct v4l2_ctrl_vp9_frame *dec_params;
> + struct avd_vp9_ctx *vp9_ctx = ctx->priv;
> + unsigned int fctx_idx;
> + int ret;
> +
> + avd_run_preamble(ctx, &run->base);
> +
> + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
> + V4L2_CID_STATELESS_VP9_COMPRESSED_HDR);
> + if (WARN_ON(!ctrl))
> + return -EINVAL;
> + run->prob_updates = ctrl->p_cur.p;
> +
> + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_VP9_FRAME);
> + if (WARN_ON(!ctrl))
> + return -EINVAL;
> + dec_params = ctrl->p_cur.p;
> +
> + ret = validate_dec_params(ctx, dec_params);
> + if (ret)
> + return ret;
> +
> + run->decode_params = dec_params;
[Severity: High]
Is it safe to read ctrl->p_cur.p locklessly without v4l2_ctrl_lock()?
A concurrent VIDIOC_S_EXT_CTRLS ioctl could potentially modify dec_params
fields (like tile_cols_log2) after they pass validate_dec_params(), resulting
in a Time-of-Check to Time-of-Use race condition.
> +
> + vp9_ctx->cur.tx_mode = run->prob_updates->tx_mode;
[ ... ]
> +static int avd_vp9_run(struct avd_ctx *ctx)
> +{
> + struct avd_vp9_run run;
> + struct avd_vp9_ctx *vp9_ctx;
> + struct avd_decoded_buffer *dst;
> + int ret;
> +
> + ret = avd_vp9_run_preamble(ctx, &run);
> + if (ret) {
> + avd_run_postamble(ctx, &run.base);
> + return ret;
> + }
> +
> + ret = avd_init_job(
> + ctx, AVD_CODEC_VP9,
> + (1 << run.decode_params->tile_rows_log2) *
> + (1 << run.decode_params->tile_cols_log2) +
> + 1);
[Severity: Critical]
Can this multiplication overflow a signed 32-bit integer?
Because tile_rows_log2 and tile_cols_log2 are an unvalidated u8, setting them
to large values (e.g. 255) could cause the multiplication to wrap around to 0,
leaving avd_init_job() to allocate a drastically undersized buffer.
Then, during the loop in set_tiles():
for (int row = 0; row < num_tile_rows; row++)
for (int col = 0; col < num_tile_cols; col++) {
ctx->job.num++;
The iteration count would far exceed the allocation, and push() would write
out-of-bounds on the heap.
> + if (ret)
> + return ret;
[ ... ]
> +static void avd_vp9_done(struct avd_ctx *ctx, struct vb2_v4l2_buffer *src_buf,
> + struct vb2_v4l2_buffer *dst_buf,
> + enum vb2_buffer_state result)
> +{
[ ... ]
> + cnts = vp9_ctx->bufs.counts.cpu;
> +
> + for (i = 0; i < ARRAY_SIZE(cnts->tx16p); ++i)
> + memcpy(tx16p[i], cnts->tx16p[i],
> + sizeof(tx16p[0]));
[Severity: High]
Does this read out of bounds?
tx16p is u32[2][4], so sizeof(tx16p[0]) is 16 bytes. But the source array
cnts->tx16p[i] in struct avd_vp9_frame_symbol_counts is sized u32[3] (12
bytes), meaning this will over-read the source buffer.
> +
> + for (i = 0; i < 2; i++) {
[ ... ]
> +static void avd_vp9_submit(struct avd_ctx *ctx)
> +{
> + struct avd_vp9_ctx *vp9_ctx = ctx->priv;
> + struct avd_dev *avd = ctx->dev;
> + u32 submit_mask = ctx->dev->variant->revision == 3 ?
> + AVD_OP_EXEC_REV3_VP9_MASK :
> + 0;
> +
> + writel(AVD_OP_EXEC | submit_mask |
> + AVD_OP_EXEC_FLAG_START_REV4(avd->variant->revision ==
> + 4) |
> + AVD_OP_EXEC_FLAG_START_REV3(avd->variant->revision ==
> + 3) |
> + AVD_OP_EXEC_FIFO_IDX(ctx->fifo_idx) |
> + AVD_OP_EXEC_FIFO_MASK(avd->variant->fifo_slots),
> + avd->ctrl + avd->variant->submit_offset);
> + for (int i = 0; i < vp9_ctx->submit_num - 1; i++)
[Severity: High]
If submit_num wrapped to 0 due to an overflow from a large number of tiles,
would 0 - 1 promote to a signed -1 (int), causing the i < -1 loop to never
execute and dropping the necessary hardware submissions?
> + writel(AVD_OP_EXEC | submit_mask |
> + AVD_OP_EXEC_FIFO_IDX(ctx->fifo_idx) |
> + AVD_OP_EXEC_FIFO_MASK(avd->variant->fifo_slots),
> + avd->ctrl + avd->variant->submit_offset);
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260918-avd-v1-0-49977931f455@icloud.com?part=12
next prev parent reply other threads:[~2026-09-18 13:42 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-18 13:15 [PATCH 00/14] media: apple: add avd driver Sofus Forstreuter
2026-09-18 13:15 ` [PATCH 01/14] media: v4l2: Add P210 pixel format Sofus Forstreuter
2026-09-18 13:26 ` sashiko-bot
2026-09-18 13:15 ` [PATCH 02/14] dt-bindings: media: add apple,avd Sofus Forstreuter
2026-09-18 13:22 ` sashiko-bot
2026-09-19 6:46 ` Krzysztof Kozlowski
2026-09-20 7:53 ` Sofus Forstreuter
2026-09-20 10:08 ` Krzysztof Kozlowski
2026-09-20 11:08 ` Sofus Forstreuter
2026-09-20 8:10 ` Andy Yan
2026-09-20 10:50 ` [PATCH " Sofus Forstreuter
2026-09-18 13:15 ` [PATCH 03/14] arm64: dts: apple: t8103: add avd nodes Sofus Forstreuter
2026-09-18 13:25 ` sashiko-bot
2026-09-18 13:15 ` [PATCH 04/14] arm64: dts: apple: t8112: " Sofus Forstreuter
2026-09-18 13:25 ` sashiko-bot
2026-09-18 13:15 ` [PATCH 05/14] arm64: dts: apple: t8122: " Sofus Forstreuter
2026-09-18 13:24 ` sashiko-bot
2026-09-18 13:15 ` [PATCH 06/14] arm64: dts: apple: t600x: " Sofus Forstreuter
2026-09-18 13:15 ` [PATCH 07/14] arm64: dts: apple: t602x: " Sofus Forstreuter
2026-09-18 13:15 ` [PATCH 08/14] arm64: dts: apple: t6030: " Sofus Forstreuter
2026-09-18 13:28 ` sashiko-bot
2026-09-18 13:15 ` [PATCH 09/14] arm64: dts: apple: t6031: " Sofus Forstreuter
2026-09-18 13:15 ` [PATCH 10/14] media: apple: add avd driver Sofus Forstreuter
2026-09-18 13:36 ` sashiko-bot
2026-09-19 6:49 ` Krzysztof Kozlowski
2026-09-19 10:49 ` Sofus Forstreuter
2026-09-18 13:15 ` [PATCH 11/14] media: apple: avd: add h264 support Sofus Forstreuter
2026-09-18 13:40 ` sashiko-bot
2026-09-18 13:15 ` [PATCH 12/14] media: apple: avd: add vp9 support Sofus Forstreuter
2026-09-18 13:42 ` sashiko-bot [this message]
2026-09-18 13:15 ` [PATCH 13/14] media: apple: avd: add hevc support Sofus Forstreuter
2026-09-18 13:46 ` sashiko-bot
2026-09-18 13:15 ` [PATCH 14/14] media: apple: avd: add av1 support Sofus Forstreuter
2026-09-18 13:43 ` sashiko-bot
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=20260918134245.CFAE61F00898@smtp.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox