Skip to content

guard against integer overflow in width * height pixel count#3097

Open
sayedkaif27 wants to merge 3 commits intoAOMediaCodec:mainfrom
digiscrypt-tech:gainmap-width-height-overflow-guard
Open

guard against integer overflow in width * height pixel count#3097
sayedkaif27 wants to merge 3 commits intoAOMediaCodec:mainfrom
digiscrypt-tech:gainmap-width-height-overflow-guard

Conversation

@sayedkaif27
Copy link

Description

Guard against integer overflow when computing the pixel count in avifRGBImageComputeGainMap.

On 32-bit platforms (size_t = 32 bits), the expression (size_t)width * height can wrap
silently when both uint32_t operands are large, causing the subsequent
numPixels > SIZE_MAX / sizeof(float) check to operate on an already-corrupted value and
pass erroneously — leading to a heap buffer overflow during gain map computation.

Fix: add the standard unsigned overflow pre-check before the multiplication:

if (width != 0 && height > SIZE_MAX / width) {
    res = AVIF_RESULT_INVALID_ARGUMENT;
    goto cleanup;
}

@vrabaud
Copy link
Contributor

vrabaud commented Mar 12, 2026

Replacing the size_t arithmetic with uint64_t is easier no? There is another (size_t)width in that file (the only other one in the code base).

@sayedkaif27
Copy link
Author

I updated the patch to perform the multiplication in uint64_t and added the same change to the other (size_t)width * height

Copy link
Collaborator

@wantehchang wantehchang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for analyzing the libavif code. The code in question relies on the fact that if a pixel buffer has been allocated successfully, we can multiply the width or the rowBytes (also known as the stride) of the buffer by the height of the buffer using the size_t type.

In the code modified in this pull request, the pixel buffer is an input parameter of the functions. Since the functions did not allocate the pixel buffer, this becomes an API contract that the pixel buffer and its width, height, and rowBytes are all valid.

src/gainmap.c Outdated
res = AVIF_RESULT_INVALID_ARGUMENT;
goto cleanup;
}
const size_t numPixels = (size_t)numPixels64;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original code is correct. Please verify the following analysis.

width and height are defined as follows:

    const uint32_t width = baseRgbImage->width;
    const uint32_t height = baseRgbImage->height;

The original code relies on the API contract that baseRgbImage->width and baseRgbImage->height are the width and height of the baseRgbImage->pixels buffer. It is safe to multiply baseRgbImage->rowBytes by baseRgbImage->height using the size_t type. Since baseRgbImage->width <= baseRgbImage->rowBytes, it is also safe to multiply baseRgbImage->width by baseRgbImage->height using the size_t type.

src/gainmap.c Outdated
// Convert extended SDR (where 1.0 is SDR white) to nits.
clli->maxCLL = (uint16_t)AVIF_CLAMP(avifRoundf(rgbMaxLinear * SDR_WHITE_NITS), 0.0f, (float)UINT16_MAX);
const float rgbAverageLinear = rgbSumLinear / ((size_t)width * height);
const float rgbAverageLinear = rgbSumLinear / ((uint64_t)width * height);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original code is correct. Please check the following analysis.

width and height are defined as follows:

    const uint32_t width = baseImage->width;
    const uint32_t height = baseImage->height;

The original code relies on the API contract that baseImage->width and baseImage->height are the width and height of the baseImage->pixels buffer. It is safe to multiply baseImage->rowBytes by baseImage->height using the size_t type (done at line 119 and inside the avifGetRGBAPixel() call at line 147). Since baseImage->width <= baseImage->rowBytes, it is also safe to multiply baseImage->width by baseImage->height using the size_t type.

@sayedkaif27
Copy link
Author

Thanks for the clarification. I’ve updated the code back to size_t.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants