Bug class: Heap OOB read
Reproduction steps:
oiiotool poc.heic -o /tmp/out.jpeg
poc (download from google drive)
Environment:
- OS: Ubuntu 22.04
- OIIO version: master
There is a bug in the heif input functionality of OpenImageIO. Specifically, in HeifInput::seek_subimage()
(src). A ImageSpec m_spec
is constructed with width and height obtained as follows:
m_spec = ImageSpec(m_ihandle.get_width(), m_ihandle.get_height(), bits / 8,
TypeUInt8);
This uses the libheif ImageHandle::get_width/height()
method, which returns the dimension of the heif image handle. These dimensions are later used in calls to HeifInput::read_native_scanline()
to read the decoded image's plane buffers:
const uint8_t* hdata = m_himage.get_plane(heif_channel_interleaved,
&ystride);
if (!hdata) {
errorfmt("Unknown read error");
return false;
}
hdata += (y - m_spec.y) * ystride;
memcpy(data, hdata, m_spec.width * m_spec.pixel_bytes());
However, there is no guarantee that the dimensions returned by ImageHandle::get_width/height()
match the size of the decoded image's planes. Instead, the decoded image's dimensions should be obtained with Image::get_width/height(channel)
(src). The original intention of this usage pattern is to accommodate transformations in the heif file -- the dimensions from the ImageHandle
are that of the untransformed image, while the dimensions from the Image
are that of the transformed image. However, since the dimensions returned from ImageHandle
are obtained by parsing the ispe (Image spatial Extents), it is possible for an attacker to forge the ispe values, which would create an ImageSpec
with incorrect dimensions. In such a case, there would be an OOB read on the decoded plane data if the incorrect dimensions in the ImageSpec
are trusted.
This is indeed the case in ImageInput::read_image()
. Using this C++ example, I triggered an ASan fault with this poc. I crafted this poc by using a regular heic file and forging the values of its ispe dimensions from (1440, 960) to (14400, 9600). It is possible to get arbitrary OOB reads by specially crafting the heif file. This poc also crashes oiiotool. This specific command will crash it: oiiotool poc.heic -o out.jpeg
(but really any operation that reads the entire image will work).
In the worst case, this can lead to an information disclosure vulnerability, particularly for programs that directly use the ImageInput
APIs.
The fix should be quite simple: Create the ImageSpec
as follows, using the Image::get_width/height()
methods as mentioned earlier.
m_spec = ImageSpec(m_himage.get_width(heif_channel_interleaved),
m_himage.get_height(heif_channel_interleaved),
bits / 8, TypeUInt8);
Bug class: Heap OOB read
Reproduction steps:
oiiotool poc.heic -o /tmp/out.jpeg
poc (download from google drive)
Environment:
There is a bug in the heif input functionality of OpenImageIO. Specifically, in
HeifInput::seek_subimage()
(src). AImageSpec m_spec
is constructed with width and height obtained as follows:This uses the libheif
ImageHandle::get_width/height()
method, which returns the dimension of the heif image handle. These dimensions are later used in calls toHeifInput::read_native_scanline()
to read the decoded image's plane buffers:However, there is no guarantee that the dimensions returned by
ImageHandle::get_width/height()
match the size of the decoded image's planes. Instead, the decoded image's dimensions should be obtained withImage::get_width/height(channel)
(src). The original intention of this usage pattern is to accommodate transformations in the heif file -- the dimensions from theImageHandle
are that of the untransformed image, while the dimensions from theImage
are that of the transformed image. However, since the dimensions returned fromImageHandle
are obtained by parsing the ispe (Image spatial Extents), it is possible for an attacker to forge the ispe values, which would create anImageSpec
with incorrect dimensions. In such a case, there would be an OOB read on the decoded plane data if the incorrect dimensions in theImageSpec
are trusted.This is indeed the case in
ImageInput::read_image()
. Using this C++ example, I triggered an ASan fault with this poc. I crafted this poc by using a regular heic file and forging the values of its ispe dimensions from (1440, 960) to (14400, 9600). It is possible to get arbitrary OOB reads by specially crafting the heif file. This poc also crashes oiiotool. This specific command will crash it:oiiotool poc.heic -o out.jpeg
(but really any operation that reads the entire image will work).In the worst case, this can lead to an information disclosure vulnerability, particularly for programs that directly use the
ImageInput
APIs.The fix should be quite simple: Create the
ImageSpec
as follows, using theImage::get_width/height()
methods as mentioned earlier.