Fedora Account System
Red Hat Associate
Red Hat Customer
The issue happens when decoding Pixarlog codec images with PIXARLOGDATAFMT_8BITABGR output format and stride = 3 . The decoder writes 4 output bytes per 3 decoded samples (synthetic alpha byte) but advances the output cursor by 3 bytes. This mismatch causes a linear heap based buffer-overflow of approx. width bytes per scan line. For every 4-bytes in the overflow, the first is always 0x00 while the others are controlled. The overflow happens on a user allocated buffer, but according to the docs (TIFFReadScnaline.rst) the user is supposed to allocate a buffer of this TIFFScanlineSize(t) , which will return the incorrect size. The bug can be pinpointed to two locations in libtiff/tif_pixarlog.c - the horizontalAccumulate8abgr function (3->4 byte expansion), and PixarLogDecode which updates the output pointer. RCA PixarLogDecode dispatches on sp->user_datafmt: case PIXARLOGDATAFMT_8BITABGR: horizontalAccumulate8abgr(up, llen, sp->stride, (unsigned char *)op, sp->ToLinear8); op += llen * sizeof(unsigned char); // <-- WRONG for stride=3 break; horizontalAccumulate8abgr with stride == 3 emits 4 bytes per input triplet: if (stride == 3) { op[0] = 0; op[1] = t1; op[2] = t2; op[3] = t3; /* 4 bytes written */ n -= 3; while (n > 0) { n -= 3; wp += 3; op += 4; /* advance 4 per triplet */ op[0] = 0; op[1] = …; op[2] = …; op[3] = …; } } So for llen = stride * width = 3 * W input samples the function writes (llen / 3) * 4 = 4 * W bytes. PixarLogDecode then advances op by only llen = 3 * W. The next iteration starts W bytes before the position where the previous write ended, and on the final iteration the writes extend W bytes past the end of the buffer the caller allocated from TIFFScanlineSize (which is W * stride * 1 = 3 * W bytes for this configuration). Reachability Any application that selects PIXARLOGDATAFMT_8BITABGR via TIFFSetField(tif, TIFFTAG_PIXARLOGDATAFMT, PIXARLOGDATAFMT_8BITABGR) and then reads a PixarLog-compressed TIFF with SamplesPerPixel == 3 is affected. The standard format picker in TIFFRGBAImageBegin does not select 8BITABGR (it picks 8BIT, 16BIT or FLOAT), so TIFFReadRGBAImage is not directly affected. PoC I attached a c program, that when executed produces a file that will overflow a heap buffer by 64 bytes. To verify I compiled it along with ASan-enabled libtiff, and got: $ gcc -fsanitize=address -g -O1 pixarlog_heap_overflow_poc.c \ -I$LIBTIFF/libtiff -I$BUILD/libtiff \ -L$BUILD/libtiff -ltiff -Wl,-rpath,$BUILD/libtiff -o poc $ ./poc ================================================================= ==...==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x… at pc 0x… WRITE of size 1 at 0x… thread T0 #0 horizontalAccumulate8abgr libtiff/tif_pixarlog.c:470 #1 PixarLogDecode libtiff/tif_pixarlog.c:980 #2 TIFFReadScanline libtiff/tif_read.c:465 #3 main poc_pixarlog_8bitabgr.c:31 0 bytes to the right of 192-byte region The 192-byte region is the caller's TIFFScanlineSize-sized buffer (W * 3 = 192). The decoder writes 256 bytes ((W * 3 / 3) * 4 = 256) per row, producing a 64-byte overflow per row. pixarlog_heap_overflow_poc.c Fix I didn't open a PR for this fix, since I'm not sure how to make it confidential and I wanted the maintainer to review this issue first. If you want me to open the PR, lmk and I'll do it as instructed. I think that in order to fix, we need to correct the output pointer advancement in PixarLogDecode: case PIXARLOGDATAFMT_8BITABGR: horizontalAccumulate8abgr(up, llen, sp->stride, (unsigned char *)op, sp->ToLinear8); if (sp->stride == 3) op += (size_t)(llen / 3) * 4; /* 4 output bytes per triplet */ else op += (size_t)llen * sizeof(unsigned char); break; And also to somehow make TIFFScanlineSize return the correct size. We can maybe do this with introducing a codec ScanLinesize override that is checked in the function: /* tif_strip.c — TIFFScanlineSize64 */ if (tif->tif_scanlinesize_override) return tif->tif_scanlinesize_override(tif); // ...