From: David Laight <david.laight.linux@gmail.com>
To: Noam Ben Shimon <noambs2999@gmail.com>
Cc: laurent.pinchart@ideasonboard.com, hansg@kernel.org,
mchehab@kernel.org, linux-media@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH] media: uvcvideo: Fix integer overflow in frame buffer size calculation
Date: Tue, 18 Aug 2026 09:28:03 +0100 [thread overview]
Message-ID: <20260818092803.4f51e6dc@pumpkin> (raw)
In-Reply-To: <20260807101433.54886-1-noambs2999@gmail.com>
On Fri, 7 Aug 2026 13:14:33 +0300
Noam Ben Shimon <noambs2999@gmail.com> wrote:
> In the function uvc_parse_frame(), it recomputes
> dwMaxVideoFrameBufferSize for uncompressed formats. This helps working
> around devices that report it wrong:
>
> frame->dwMaxVideoFrameBufferSize = format->bpp * frame->wWidth
> * frame->wHeight / 8;
>
> These three arguments originate from the device's own descriptors, and
> therefore can be decided by it. bpp is a u8 and wWidth and wHeight are
> u16. The expression is evaluated in int, and the maximum value is
> 255 * 65535 * 65535 (which is roughly 510 times INT_MAX).
> A device that declares large dimensions therefore overflows a signed
> int here.
> The kernel is built using -fno-strict-overflow, so this wraps rather
> than being miscompiled, but the wrapped value (which is often negative)
> is then divided by 8 and stored in a u32 used as a size.
>
> Two examples for this (using legal field values):
>
> - 32 bpp, 16384x4096: the product is exactly 2^31 and wraps to
> INT_MIN. After division and conversion to u32 the field has the
> value 4026531840 rather than 268435456.
>
> - 16 bpp, 16384x16384: the product is exactly 2^32 and wraps to 0.
> The field holds 0, rather than the correct 536870912.
>
> I don't think memory corruption is a consequence of this. The value
> reaches uvc_queue_setup() as the vb2 buffer size, and every copy on the
> decode path is bounded by buf->length, which uvc_buffer_prepare() gets
> from vb2_plane_size() rather than this field. What a wrapped value does
> instead is make the driver describe the stream inconsistently.
> For an uncompressed format uvc_fixup_video_ctrl() copies it into
> ctrl->dwMaxVideoFrameSize unconditionally, and that becomes the
> sizeimage reported by VIDIOC_G_FMT. This is while width, height and
> bytesperline continue to describe the full frame.
> This also makes uvc_video_validate_buffer() mark error on all frames,
> because it is comparing bytesused against the same number.
>
> Compute the size in 64-bit, and if the result does not fit in the u32
> field then reject the frame descriptor. An uncompressed frame this
> large is probably not a real device and rejection is consistent with
> the other checks over malformed-descriptors in this function.
>
> Fixes: c0efd232929c ("V4L/DVB (8145a): USB Video Class driver")
> Signed-off-by: Noam Ben Shimon <noambs2999@gmail.com>
> ---
> drivers/media/usb/uvc/uvc_driver.c | 18 +++++++++++++++---
> 1 file changed, 15 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> index e289cc71ba98..d319368f9d21 100644
> --- a/drivers/media/usb/uvc/uvc_driver.c
> +++ b/drivers/media/usb/uvc/uvc_driver.c
> @@ -296,9 +296,21 @@ static int uvc_parse_frame(struct uvc_device *dev,
> * information. For uncompressed formats this can be fixed by computing
> * the value from the frame size.
> */
> - if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
> - frame->dwMaxVideoFrameBufferSize = format->bpp * frame->wWidth
> - * frame->wHeight / 8;
> + if (!(format->flags & UVC_FMT_FLAG_COMPRESSED)) {
> + u64 bufsize;
> +
> + bufsize = (u64)format->bpp * frame->wWidth * frame->wHeight / 8;
I'd bet there is a requirement that width*bpp is a multiple of 8 (or even 32)?
You definitely don't want the divide rounding down!
> + if (bufsize > U32_MAX) {
Should that be >= ?
> + uvc_dbg(dev, DESCR,
> + "device %d videostreaming interface %d FRAME %u: computed buffer size overflows\n",
s/buffer/frame buffer/ ?
> + dev->udev->devnum,
> + alts->desc.bInterfaceNumber,
> + frame->bFrameIndex);
I'd include the bpp, width and height values in the trace.
If the error happens the first thing you need the the three values.
David
> + return -EINVAL;
> + }
> +
> + frame->dwMaxVideoFrameBufferSize = bufsize;
> + }
>
> /*
> * Clamp the default frame interval to the boundaries. A zero
>
> base-commit: f9a2394a23482bfd330911e9c8295b71724feacd
prev parent reply other threads:[~2026-08-18 8:28 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-07 10:14 [PATCH] media: uvcvideo: Fix integer overflow in frame buffer size calculation Noam Ben Shimon
2026-08-10 14:12 ` Ricardo Ribalda
2026-08-12 10:32 ` [PATCH v2] " Noam Ben Shimon
2026-08-18 6:45 ` Natasha Klaus
2026-08-18 6:54 ` Ricardo Ribalda
2026-08-18 6:57 ` Ricardo Ribalda
2026-08-18 7:59 ` [PATCH] media: uvcvideo: Skip frame descriptors with a zero computed size Natasha Klaus
2026-08-18 8:31 ` Ricardo Ribalda
2026-08-18 9:40 ` Natasha Klaus
2026-08-18 9:53 ` Natasha Klaus
2026-08-18 10:18 ` Ricardo Ribalda
2026-08-18 10:32 ` Natasha Klaus
2026-08-18 10:40 ` Ricardo Ribalda
2026-08-18 8:28 ` David Laight [this message]
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=20260818092803.4f51e6dc@pumpkin \
--to=david.laight.linux@gmail.com \
--cc=hansg@kernel.org \
--cc=laurent.pinchart@ideasonboard.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=mchehab@kernel.org \
--cc=noambs2999@gmail.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