Talos Vulnerability Report


LibTIFF PixarLogDecode Remote Code Execution Vulnerability

October 25, 2016

Report ID



An exploitable heap based buffer overflow exists in the handling of compressed TIFF images in LibTIFF’s PixarLogDecode api. A crafted TIFF document can lead to a heap based buffer overflow resulting in remote code execution. The vulnerability can be triggered through any user controlled TIFF that is handled by this functionality.

Tested Versions

LibTiff - 4.0.6

Product URLs


CVSSv3 Score

8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H


This vulnerability is present in the PixarLogDecode function inside of LibTIFF. This vulnerability is present whenever attempting to decompress a PixarLog compressed TIFF image.

To decompress the PixarLog compressed data inside of a TIFF image, LibTIFF uses the Zlib compression library. First the parameters needed to pass to Zlib are set up with a function call to PixarLogSetupDecode. A buffer is allocated with the code shown below:

  tbuf_size = multiply_ms(multiply_ms(multiply_ms(sp->stride, td->td_imagewidth), td->td_rowsperstrip), sizeof(uint16));

  /* add one more stride in case input ends mid-stride */
  tbuf_size = add_ms(tbuf_size, sizeof(uint16) * sp->stride);
  if (tbuf_size == 0)
    return (0);   /* TODO: this is an error return without error report through TIFFErrorExt */
  sp->tbuf = (uint16 *) _TIFFmalloc(tbuf_size);

Later this buffer is used when calling the Zlib library function inflate which is responsible for the decompression.

  sp->stream.next_out = (unsigned char *) sp->tbuf;
  sp->stream.avail_out = (uInt) (nsamples * sizeof(uint16));

Now seeing how these parameters are used in the inflate function:

Output space is provided to deflate() by setting avail_out to the number of available output bytes and next_out to a pointer to that space.

            strm.avail_out = CHUNK;
            strm.next_out = out;

So seeing this we see that this is used by Zlib as a space to write output too. The problem arises with how LibTIFF calculates out these two values. First the buffer is calculated above with this line of code:

tbuf_size = multiply_ms(multiply_ms(multiply_ms(sp->stride, td->td_imagewidth), td->td_rowsperstrip), sizeof(uint16));

Which comes out significantly less than the avail_out value calculated below:

sp->stream.avail_out = (uInt) (nsamples * sizeof(uint16));

Passing this undersized buffer into the Zlib inflate function causes a heap overflow that could be potentially leveraged into remote code execution.

Crash Information

Crashed thread log =
: Dispatch queue: com.apple.main-thread
0   libsystem_platform.dylib        0x00007fff8b1b303b _platform_memmove$VARIANT$Haswell + 283
1   libz.1.dylib                    0x00007fff9563d945 inflate + 2424
2   libtiff.5.dylib                 0x000000010922235d PixarLogDecode + 301 (tif_pixarlog.c:795)
3   libtiff.5.dylib                 0x00000001092294af TIFFReadEncodedTile + 191 (tif_read.c:668)
4   libtiff.5.dylib                 0x000000010920a0a9 gtTileContig + 745 (tif_getimage.c:656)
5   libtiff.5.dylib                 0x0000000109209b55 TIFFReadRGBATile + 469 (tif_getimage.c:495)
6   a.out                           0x00000001091dbf46 main + 86
7   libdyld.dylib                   0x00007fff85a3e5ad start + 1

log name is: ./crashlogs/4.crashlog.txt
exception=EXC_BAD_ACCESS:signal=11:is_exploitable=yes:instruction_disassembly=.byte 0xc5 #bad opcode:instruction_address=0x00007fff8b1b303b:access_type=unknown:access_address=0x000000010985b000:
Crash accessing invalid address.  Consider running it again with libgmalloc(3) to see if the log changes.


Discovered by Tyler Bohan of Cisco Talos


2016-09-20 - Vendor Disclosure
2016-10-25 - Public Release