On Sat Sep 5 18:58:18 2026 +0300, Maxim Skokov wrote:
> syzbot reports a vmalloc out-of-bounds write in the test pattern
> generator:
>
> BUG: KASAN: vmalloc-out-of-bounds in tpg_fill_plane_pattern
> drivers/media/common/v4l2-tpg/v4l2-tpg-core.c:2617 [inline]
> BUG: KASAN: vmalloc-out-of-bounds in tpg_fill_plane_buffer+0x2063/0x4160
> drivers/media/common/v4l2-tpg/v4l2-tpg-core.c:2705
> Write of size 720 at addr ffffc900038f9d50 by task vivid-000-vid-c/6017
>
> The reproducer requests a 720x49 NV12 capture format, i.e. an odd
> height for a format whose chroma plane is vertically subsampled.
>
> The buffer size is derived from the height by a truncating division:
>
> sizes[p] = (tpg_g_line_width(&dev->tpg, p) * h) /
> dev->fmt_cap->vdownsampling[p] +
> dev->fmt_cap->data_offset[p];
>
> For a single buffer holding both planes tpg_g_line_width() returns
> 720 + 720 / 2 = 1080, so 1080 * 49 = 52920 bytes get allocated.
>
> tpg_fill_plane_buffer() however emits one chroma line for every two
> luma lines, i.e. DIV_ROUND_UP(49, 2) = 25 lines, and thus needs
> 49 * 720 + 25 * 720 = 53280 bytes. The memcpy() of the last chroma
> line runs 360 bytes past the end of the buffer.
>
> An odd height is not meaningful for a 4:2:0 format in the first place,
> since the chroma plane would have to hold half a line. Rather than
> fixing up each of the ~10 sites that divide the height by
> vdownsampling[], round the height down to a multiple of the vertical
> subsampling factor where it enters the driver. Adjusting the format is
> what TRY_FMT/S_FMT are for, and it keeps every later division exact.
>
> Formats without vertical subsampling are unaffected and keep accepting
> odd heights.
>
> Tested with the syzbot reproducer, which no longer triggers the splat,
> and by streaming NV12, NV21, YUV420, YVU420 and YUYV at heights 47,
> 48, 49, 51, 480, 481 and 1081. v4l2-compliance gives identical results
> before and after (48 of 50 succeeded on the vivid device in both
> cases; the two failures are pre-existing and unrelated).
>
> Fixes: ddcaee9dd4c0 ("[media] vivid: add support for single buffer planar
> formats")
> Cc: [email protected]
> Reported-by: [email protected]
> Closes: https://syzkaller.appspot.com/bug?extid=cb43e758a4dc84dd467f
> Signed-off-by: Maxim Skokov <[email protected]>
> Signed-off-by: Hans Verkuil <[email protected]>
Patch committed.
Thanks,
Hans Verkuil
drivers/media/test-drivers/vivid/vivid-vid-cap.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
---
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c
b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
index e20449084709..147af0f9b077 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
@@ -570,6 +570,7 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv,
const struct vivid_fmt *fmt;
unsigned bytesperline, max_bpl;
unsigned factor = 1;
+ unsigned int vdiv = 1;
unsigned w, h;
unsigned p;
bool user_set_csc = !!(mp->flags & V4L2_PIX_FMT_FLAG_SET_CSC);
@@ -622,6 +623,18 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv,
mp->height = r.height / factor;
}
+ /*
+ * The chroma planes of vertically subsampled formats hold
+ * height / vdownsampling lines. If the height is not a multiple of
+ * the subsampling factor, then the buffer size calculations round
+ * that number down while the test pattern generator rounds it up,
+ * so the generator writes one line past the end of the buffer.
+ * Round the height down to keep both in sync.
+ */
+ for (p = 0; p < fmt->planes; p++)
+ vdiv = max(vdiv, fmt->vdownsampling[p]);
+ mp->height = rounddown(mp->height, vdiv);
+
/* This driver supports custom bytesperline values */
mp->num_planes = fmt->buffers;
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]