[PATCH v7 16/19] media: meson: vdec: Configure DMA mask and segment size in probe
sashiko-bot at kernel.org
sashiko-bot at kernel.org
Mon Jul 13 05:55:10 PDT 2026
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
New issues:
- [High] Hardware interrupts are not masked prior to calling `synchronize_irq()`, leading to a race condition that causes a Use-After-Free of `sess->priv`.
- [High] Misuse of `scoped_guard` inside a `while (1)` loop combined with inverted logic causes the workqueue to busy-wait infinitely when no data is available.
- [Medium] Missing release barriers when publishing `core->cur_sess` allows the lockless ISR to observe an uninitialized or stale session state.
Pre-existing issues:
- [Critical] vp9_update_header trusts user-provided frame sizes to calculate offsets, leading to integer overflows and massive out-of-bounds memory accesses via memmove.
- [High] `meson_canvas_get` retrieves a pointer to the provider's private data but immediately drops its reference to the provider device, leading to a Use-After-Free if the provider driver is unbound.
- [Medium] Potential NULL pointer dereference if the driver is probed without a device tree node.
--
--- Patch [16]: [PATCH v7 16/19] media: meson: vdec: Configure DMA mask and segment size in probe ---
commit 8dd369d994b7e2a6a1fb0db5dcba10a32f46beaa
Author: Anand Moon <linux.amoon at gmail.com>
media: meson: vdec: Configure DMA mask and segment size in probe
This commit addresses missing explicit DMA constraints in the vdec probe
routine. It enforces a 32-bit coherent DMA allocation window and maximizes
the contiguous allocation segment boundary constraint to UINT_MAX.
> diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c
> --- a/drivers/staging/media/meson/vdec/vdec.c
> +++ b/drivers/staging/media/meson/vdec/vdec.c
> @@ -1186,6 +1186,16 @@ static int vdec_probe(struct platform_device *pdev)
> if (IS_ERR(core->canvas))
> return PTR_ERR(core->canvas);
>
> + /* Enforce strict 32-bit DMA limit to match hardware capabilities */
> + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to set 32-bit DMA mask\n");
> +
> + ret = vb2_dma_contig_set_max_seg_size(dev, UINT_MAX);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "Failed to set DMA max segment size\n");
> +
> of_id = of_match_node(vdec_dt_match, dev->of_node);
> core->platform = of_id->data;
[Severity: Medium]
This isn't a bug introduced by this patch, but can this lead to a NULL pointer
dereference if the driver is probed without a device tree node? If a user
with privileges binds the driver manually via sysfs without an associated
device tree node, dev->of_node is NULL. The of_match_node() call will
return NULL, causing of_id->data to be dereferenced blindly.
[Severity: High]
Can this regression cause a use-after-free of sess->priv in the interrupt
handler?
drivers/staging/media/meson/vdec/vdec.c:vdec_stop_streaming() {
...
/* Synchronize and flush pending hardware interrupt service routines */
synchronize_irq(core->vdec_irq);
/* Ensure esparser ISR finishes executing */
synchronize_irq(core->esparser_irq);
cancel_work_sync(&sess->esparser_queue_work);
mutex_lock(&core->lock);
if (core->cur_sess == sess) {
vdec_poweroff(sess);
...
}
It appears hardware interrupts are not masked prior to calling
synchronize_irq(), which could allow an interrupt to fire immediately
after synchronize_irq() returns. Because vdec_poweroff() is responsible
for masking the hardware interrupts, could the main thread then free
sess->priv while the concurrently executing ISR dereferences it?
[Severity: High]
Does this loop correctly process the buffer queue or does it spin infinitely?
drivers/staging/media/meson/vdec/esparser.c:esparser_queue_all_src() {
...
while (1) {
struct vb2_v4l2_buffer *vbuf = NULL;
bool processed_frame = false;
scoped_guard(mutex, &sess->lock) {
/* Safe atomic tracking check: exit loop if session is shutting down */
if (READ_ONCE(sess->should_stop))
return;
/* Queue completely empty: exit work loop cleanly */
vbuf = v4l2_m2m_next_src_buf(sess->m2m_ctx);
if (!vbuf)
break;
...
}
When v4l2_m2m_next_src_buf() returns NULL, the break statement seems to only
exit the inner for loop created by the scoped_guard macro. This bypasses the
subsequent loop exit conditions and repeats the while (1) loop endlessly,
potentially causing a CPU lockup on the workqueue thread. Additionally, if a
buffer is present, could this break out of the loop completely instead of
processing the queue?
[Severity: Medium]
Can the lockless ISR observe an uninitialized or stale session state due to
missing release barriers?
drivers/staging/media/meson/vdec/vdec.c:vdec_start_streaming() {
...
/* If already half-initialized, do not re-initialize */
if (sess->status == STATUS_INIT) {
mutex_unlock(&core->lock);
return 0;
}
sess->status = STATUS_INIT;
core->cur_sess = sess;
mutex_unlock(&core->lock);
...
}
Because core->cur_sess is assigned using a plain store, could the compiler or
CPU reorder this store before earlier initialization steps like
sess->status = STATUS_INIT? If the lockless ISR uses smp_load_acquire(), it
might observe the new session pointer but the old memory state.
[Severity: High]
This is a pre-existing issue, but does this code cause a use-after-free if the
provider driver is unbound?
drivers/soc/amlogic/meson-canvas.c:meson_canvas_get() {
...
canvas_pdev = of_find_device_by_node(canvas_node);
of_node_put(canvas_node);
if (!canvas_pdev)
return ERR_PTR(-EPROBE_DEFER);
...
canvas = dev_get_drvdata(&canvas_pdev->dev);
put_device(&canvas_pdev->dev);
if (!canvas)
return ERR_PTR(-EINVAL);
return canvas;
}
The put_device() call immediately drops the device reference before returning
the pointer. Since no device link is maintained, could an admin or
unprivileged user with sysfs access unbind the amlogic-canvas driver,
freeing the memory while the vdec driver still holds and uses the
dangling pointer?
[Severity: Critical]
This is a pre-existing issue, but does this size calculation prevent integer
overflows and out-of-bounds memory accesses?
drivers/staging/media/meson/vdec/esparser.c:vp9_update_header() {
...
for (cur_frame = 0; cur_frame < num_frames; cur_frame++) {
frame_size[cur_frame] = 0;
for (cur_mag = 0; cur_mag < mag; cur_mag++) {
if (mag_ptr >= dsize)
return -EINVAL;
frame_size[cur_frame] |=
(dp[mag_ptr] << (cur_mag * 8));
mag_ptr++;
}
if (cur_frame == 0)
tot_frame_size[cur_frame] =
frame_size[cur_frame];
else
tot_frame_size[cur_frame] =
tot_frame_size[cur_frame - 1] +
frame_size[cur_frame];
total_datasize += frame_size[cur_frame];
}
...
}
It appears user-provided frame sizes are added blindly without overflow
protection. If a user crafts a V4L2 VP9 buffer payload with two frames
specifying sizes that sum to 0 (e.g., 0x40000000 and 0xC0000000), could
this bypass the new_frame_size bounds check? The driver might then use
one of the huge frame sizes in a memmove operation, leading to
out-of-bounds reads and writes on the kernel heap.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260713120840.17427-1-linux.amoon@gmail.com?part=16
More information about the linux-amlogic
mailing list