libheif icon indicating copy to clipboard operation
libheif copied to clipboard

poc of HEIC crash

Open hackerfactor opened this issue 2 years ago • 19 comments

A user just uploaded to my site a file called "poc.heic" that causes libheif to crash.

The HEIC file structure is valid. The error is coming from somewhere deeper.

The HEIC file contains 4 images. Primary, thumb1, and thumb2 will crash. Thumb3 renders as really corrupted.

I have temporarily placed the file at https://hackerfactor.com/private/poc-heic.zip. The zip contains poc.heic.

hackerfactor avatar Feb 15 '23 14:02 hackerfactor

Thanks, but I could not reproduce this. Even with older versions of libheif and libde265. Can you give more details? Which versions of libheif and libde265? Which OS? Stack-trace?

farindk avatar Feb 16 '23 14:02 farindk

@farindk I'm seeing the crash with old and new libraries.

Tested: Set1: "libaom.so.3.0.0", "libde265.so.0.1.1", "libx265.so.200", "libheif.so.1.11.0" (really old) Set2: "libaom.so.3.3.0", "libde265.so.0.1.1", "libx265.so.201", "libheif.so.1.12.0" (old) Set3: "libaom.so.3.6.0", "libde265.so.0.1.4", "libx265.so.207", "libheif.so.1.15.1" (new/current)

OS: Ubuntu 20.04.5 LTS NOTE: I'm compiling from source, not using the repository libraries.

Compiling method: aom: rm -rf aom git clone https://aomedia.googlesource.com/aom (cd aom/build ; cmake -DBUILD_SHARED_LIBS=1 .. ; make)

libde265: rm -rf libde265 git clone https://github.com/strukturag/libde265.git (cd libde265 ; ./autogen.sh ; ./configure --disable-sherlock265 ; make)

x265_git: rm -rf x265_git git clone https://bitbucket.org/multicoreware/x265_git.git (cd x265_git/build ; cmake ../source ; make)

libheif: rm -rf libheif git clone https://github.com/strukturag/libheif.git # Use gcc-4.8 for maximum cross-platform compatibility; not all Linux are binary compatible (cd libheif ; ./autogen.sh ; CC=gcc-4.8 CXX=g++-4.8 ./configure ; make)

I haven't tried a stack trace yet.

hackerfactor avatar Feb 16 '23 21:02 hackerfactor

Oh interesting... libheif/examples/ heif-info, heif-convert both work (no crash). Looks like the problem may be in how my code is calling the library. (Diving deeper.)

hackerfactor avatar Feb 16 '23 21:02 hackerfactor

Oh, I found the problem. The ispe says the image should be 1280x4439. However, the decoded image from heif_decode_image() is 1280x854. (I'm trying to copy 1280x4439, so it fails.)

I'm not seeing any decode errors. Shouldn't there be something that denotes a truncated image?

hackerfactor avatar Feb 16 '23 22:02 hackerfactor

In my opinion, the ispe specification is bad. It (informally) specifies the raw image size before it is being transformed (rotated, cropped, ...). I don't see why this should be of any value to the user, who is only interested in the final image size. Moreover, the ispe size might vary from the actual encoded size. But we have to live with the standard as it is.

My advice would be to completely ignore the ispe content.

I'm cross linking this to the related #773.

farindk avatar Feb 17 '23 11:02 farindk

Without ispe, how do you recommend/propose tools like ExifTool identify the image size without rendering the image?

hackerfactor avatar Feb 18 '23 00:02 hackerfactor

As far as I can tell, if there are any transforms beyond a simple crop, you basically have to run the entire compositing engine anyway to obtain the final canvas size, even if you don't perform the pixel manipulation part of it.

silverbacknet avatar Feb 18 '23 00:02 silverbacknet

@hackerfactor can I take this corrupted image in my test's suite?

bigcat88 avatar Feb 18 '23 10:02 bigcat88

@bigcat88 The corrupt image isn't mine, so I cannot give permission. It was an upload to FotoForensics.com. The ToS at FotoForensics says that all images can be used for research. As long as your test suite is research-only and private/personal (not distributed, not sold), then that's fine. But if it's part of an open source set, then that's a no.

hackerfactor avatar Feb 19 '23 13:02 hackerfactor

@silverbacknet wrote:

As far as I can tell, if there are any transforms beyond a simple crop, you basically have to run the entire compositing engine anyway to obtain the final canvas size, even if you don't perform the pixel manipulation part of it.

That's disappointing. Especially given the time and resources needed to decode a HEIC file. That's a lot of overhead to just find out the dimensions.

hackerfactor avatar Feb 19 '23 14:02 hackerfactor

It's all calculable from the metadata alone, so the full thing doesn't have to be parsed. If there are no derived images, then just start at the ispe box, and keep walking, recalculating w & h for every transformative box you encounter. The only ones that would really affect it are clap (crop), irot (rotation), and iscl (scaling). I was thinking about overlays too, but I forgot that's derived only.

If there are derived images (tiled or overlaid) then those will have the actual final size in their structs.

If there are multiple base or derived images, you have to pick which you want to show, then.

silverbacknet avatar Feb 20 '23 00:02 silverbacknet

I don't see why this should be of any value to the user, who is only interested in the final image size.

I disagree. See also https://github.com/strukturag/libheif/pull/555

kmilos avatar Feb 20 '23 11:02 kmilos

start at the ispe box

That's the problem. In the crash poc file, the ispe does not match the decoded image dimensions.

hackerfactor avatar Feb 24 '23 16:02 hackerfactor

in the python bindings i made the decision to mark such files as corrupted (when ispe shows less size than the decoded size) and later on will just add a new api that always first decodes the image and then get the image info as farindk suggests - for those who are interested in corrupted files.

Edited(19 March): it was a bad idea, some cameras store in ispe value that will be after applied rotation. So the only way to get true height and width is to get them after decoding.

bigcat88 avatar Feb 24 '23 17:02 bigcat88

in the python bindings i made the decision to mark such files as corrupted (when ispe shows less size than the decoded size) and later on will just add a new api that always first decodes the image and then get the image info as farindk suggests - for those who are interested in corrupted files.

Edited(19 March): it was a bad idea, some cameras store in ispe value that will be after applied rotation. So the only way to get true height and width is to get them after decoding.

Just curious: Is this image satisfy HEIF standard?
This is an example that was submitted to me, when ispe values differs from encoded in image. Sony ILCE-7M4

bigcat88 avatar Mar 21 '23 11:03 bigcat88

Is this [image](https://github.com/bigcat88/pillow_heif/raw/master/tests/images/heif_special/guitar_cw90.hif) satisfy HEIF standard? Cool! I haven't seen a HEIX file before. And 16-bit depth! Looks valid to me.

The ispe matches the image dimensions before transformations (rotation).

hackerfactor avatar Mar 29 '23 14:03 hackerfactor

@farindk

In my opinion, the ispe specification is bad. It (informally) specifies the raw image size before it is being transformed (rotated, cropped, ...). I don't see why this should be of any value to the user, who is only interested in the final image size. Moreover, the ispe size might vary from the actual encoded size. But we have to live with the standard as it is.

@hackerfactor

That's the problem. In the crash poc file, the ispe does not match the decoded image dimensions.

This kind of misses the point of descriptive item properties. The point of the descriptive item properties is to allow a parser to quickly determine basic properties about a file without actually having to call into specific codecs.

All transform properties and derived items tell you what the output is, assuming you know the input. So as long as you know the input, you can fully reason about all existing properties and item types.

But for a coded item you would have to call into a codec to get information about the input. This is problematic for multiple reasons:

  • If you have a large and complex file containing many image items, you would potentially have to load/download the full file just to be able to say what the output dimensions are. (This is also the reason why the spec strongly encourages the meta to be placed at the start of the file.)
  • Your HEIF parser all of a sudden needs to call out to potentially multiple codec libraries just to be able to reason about image items and validate that derivation chains make sense.

Because of this it was decided that all image items shall have an ispe property that tells you what the dimensions of the input reconstructions are, since that is the part that is not codec-agnostic. With the ispe, a parser can reason about things like buffer dimensions needed, which jobs can be done by dedicated HW/GPU and so on, without actually having to parse the codec bitstream first.

At decode time the HEIF parser will need to validate that the output of the decoder matches the ispe and the pixi. There may very well be a mismatch, at which point the file is non-compliant and should be rejected. But these types of checks are required for all image formats. The point of the ispe and pixi is to give you a kind of contract between the container and the codec levels that can be verified and reasoned about per item.

leo-barnes avatar Apr 28 '23 14:04 leo-barnes

Admittedly it would have been nice if all images had to end up in with an auxC box, even if composed of just one source image with no transforms. That would simplify parsing even more, just look for the auxC (or identical clone for the master image), and it would also be useful as yet another check for validity across the entire chain.

silverbacknet avatar Apr 28 '23 17:04 silverbacknet

@bigcat88

Just curious: Is this image satisfy HEIF standard? This is an example that was submitted to me, when ispe values differs from encoded in image. Sony ILCE-7M4

ispe comes before transformative properties, which is technically not valid. But apart from that it seems fine. (Although having a hidden JPEG thumb is slightly weird.)

leo-barnes avatar May 08 '23 12:05 leo-barnes