Samsung / ONE

On-device Neural Engine
Other
429 stars 157 forks source link

Heap Buffer Overflow in JpegHelper::readJpeg #13348

Closed francobel closed 2 months ago

francobel commented 3 months ago

The vulnerable function JpegHelper::readJpeg in file jpeg_helper.cc is used to decompress jpegs and create a raw bitmap version of the image.

In JpegHelper::readJpeg, the values for cinfo.image_width and cinfo.image_height are retrieved directly from a jpeg file's header.

cinfo.image_width and cinfo.image_height can be manipulated by editing the header of the jpeg file being processed. They are two bytes each in the image's header so their values can range from 0x0000 to 0xFFFF. These variables are multiplied by cinfo.num_components.

When these three values are multiplied together they can exceed the limit of a 32-bit unsigned integer, leading to an integer overflow vulnerability. This product is used to set the size of the raw_image vector, which will store the decompressed jpeg. When the sizing arguments overflow, the vector becomes too small to store the decompressed data.

The program writes the decompressed image to the vector using the jpeg_read_scanlines function. If an integer overflow occurs, the function ends up writing to out-of-bounds memory due to the vector's small size. This causes data in memory adjacent to the vector to be overwritten.

An attacker is in control of the image's height, width, and contents. This allows an attacker to craft an exploit to overwrite data in memory with data they control.

hseok-oh commented 3 months ago

@francobel Thank you for your report. We are not using that module any more, but we will update to add limitation check of width and height.

hseok-oh commented 2 months ago

Patch is merged.

francobel commented 2 months ago

Hello, the applied patch may still be vulnerable. If the product of cinfo.output_width * cinfo.output_height * cinfo.num_components exceeds the max value of a 32-bit unsigned integer then it will result in an integer overflow. This will cause the result to wrap around to an unexpectedly small value. This small value will end up passing the size check of

if (cinfo.output_width * cinfo.output_height * cinfo.num_components > 16 * 1024 * 1024)
{
  printf("Image size is too large\n");
  return -1;
}