Re: [RFC PATCH] media: uvcvideo: compute frame buffer size in 64-bit arithmetic

Ricardo Ribalda <[email protected]>
Newsgroups org.kernel.vger.linux-media,org.kernel.vger.linux-kernel
Message-ID <CANiDSCsH3+0Mc-05gR0260efg4taTSuqr4kG1R8XABzD6E7ZoA@mail.gmail.com>
Hi Natasha

This has been previously discussed in the list:
https://lore.kernel.org/linux-media/[email protected]/

Maybe you can help reviewing it?

Thanks!

On Mon, 17 Aug 2026 at 14:40, Natasha Klaus
<[email protected]> wrote:
>
> uvc_parse_frame() computes the default frame buffer size as
>
>         frame->dwMaxVideoFrameBufferSize = format->bpp * frame->wWidth
>                                          * frame->wHeight / 8;
>
> format->bpp is u8 and wWidth and wHeight are u16, so all three operands
> promote to signed int and the product is evaluated in 32 bits. All three
> come from the frame descriptor and none of them is range checked, so a
> device can drive the product up to about 1.1e12 against a type that
> holds 2.1e9.
>
> The kernel builds with -fno-strict-overflow, so this is a defined
> wraparound rather than undefined behaviour, but the stored value is
> still wrong. A descriptor reporting bpp=207, wWidth=18501 and
> wHeight=43738 has a true frame size of 20937965595 and the driver
> stores 27. For bpp=233, wWidth=63435 and wHeight=58989 it stores 0, and
> uvc_queue_setup() then hands vb2 a zero plane size.
>
> Evaluate the product in 64-bit arithmetic by casting the first operand.
>
> Signed-off-by: Natasha Klaus <[email protected]>
> ---
> This is RFC because the patch is deliberately incomplete and I would
> rather you pick the remedy than guess at it.
>
> The cast fixes the arithmetic, but dwMaxVideoFrameBufferSize is a
> 32-bit field, so the assignment still truncates and sizes above 4 GiB
> are not representable. The zero case survives too: bpp=32,
> wWidth=32768, wHeight=32768 gives exactly 2^35, the 64-bit quotient is
> exactly 2^32, and the stored value is 0 again.
>
> So the open question is what should happen when a descriptor claims a
> frame that does not fit. As I see it:
>
>   1. this patch, accepting that oversized values truncate
>   2. cap at U32_MAX
>   3. reject the frame descriptor, on the grounds that a device claiming
>      a 100 GB frame is lying
>   4. range check wWidth, wHeight and bpp at parse time, which would
>      also cover the two sibling computations
>
> I am happy to send whichever you prefer as a proper patch.
>
> Two other places take the same unchecked operands the same way:
> uvc_v4l2_get_bytesperline() in uvc_v4l2.c, and the bandwidth estimate
> in uvc_fixup_video_ctrl() in uvc_video.c, which is clamped only from
> below. If you want those fixed I would send a series rather than fold
> them in here.
>
> How this came up: we are building a memory-safe Rust rewrite of the UVC
> descriptor parser and proving properties about it, and the Rust and the
> C disagreed on this field. Standalone reproducer, one command, builds
> under gcc and clang with and without -fno-strict-overflow:
>
>   https://github.com/runtimeverification/uvc-frame-size-overflow
>
> Two caveats. This was measured on the isolated expression with the
> kernel operand types, not on a running kernel and not on a UVC gadget,
> so the vb2 behaviour above comes from reading the code rather than from
> observing it. And I was unable to search the list archives from my
> environment, so apologies if this has already been discussed.
>
>  drivers/media/usb/uvc/uvc_driver.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
> index e289cc71ba98..5dfbd487732d 100644
> --- a/drivers/media/usb/uvc/uvc_driver.c
> +++ b/drivers/media/usb/uvc/uvc_driver.c
> @@ -297,8 +297,8 @@ static int uvc_parse_frame(struct uvc_device *dev,
>          * the value from the frame size.
>          */
>         if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
> -               frame->dwMaxVideoFrameBufferSize = format->bpp * frame->wWidth
> -                                                * frame->wHeight / 8;
> +               frame->dwMaxVideoFrameBufferSize =
> +                       (u64)format->bpp * frame->wWidth * frame->wHeight / 8;
>
>         /*
>          * Clamp the default frame interval to the boundaries. A zero
>
> base-commit: 8d3ae59288f1e7d58d76558a6ee96d533bc5019f
> --
> 2.34.1
>
>


-- 
Ricardo Ribalda
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.