Bug 2492871 (CVE-2026-12912) - CVE-2026-12912 libtiff: libtiff: Heap-based buffer overflow via crafted PixarLog-compressed TIFF image
Summary: CVE-2026-12912 libtiff: libtiff: Heap-based buffer overflow via crafted Pixar...
Keywords:
Status: NEW
Alias: CVE-2026-12912
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
high
high
Target Milestone: ---
Assignee: Product Security
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2026-06-25 12:47 UTC by OSIDB Bzimport
Modified: 2026-06-29 16:09 UTC (History)
2 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Embargoed:


Attachments (Terms of Use)

Description OSIDB Bzimport 2026-06-25 12:47:25 UTC
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);
// ...


Note You need to log in before you can comment on or make changes to this bug.