Skip to content

Fix heap-buffer-overflow write in PICT UnpackBits#47

Open
mjbommar wants to merge 1 commit into
danoli3:masterfrom
mjbommar:fix/pict-unpackbits-oob-write
Open

Fix heap-buffer-overflow write in PICT UnpackBits#47
mjbommar wants to merge 1 commit into
danoli3:masterfrom
mjbommar:fix/pict-unpackbits-oob-write

Conversation

@mjbommar
Copy link
Copy Markdown

Sibling of merged PR #41 (UnpackPictRow). UnpackBits in Source/FreeImage/PluginPICT.cpp has the same unbounded-run defect: its per-row PackBits loop advances dst into the bitmap raster by an attacker-controlled run length with no check against the end of the raster, so a crafted PICT whose row decompresses past the image writes out of bounds on the heap (reachable via FreeImage_Load).

UnpackBits is the decoder used for 1/2/4/16-bpp PICT data; the 8/32-bpp paths already go through the bounded UnpackPictRow fixed in #41. It is reachable from both the version-1 bitmap opcode (0x98) and the version-2 DirectBitsRect/PackBitsRect opcodes (0x9a/0x98), so it triggers through normal content-sniffing format detection.

This PR bounds every write in the UnpackBits RLE loop to the allocated raster, exactly like #41: compute rasterEnd = FreeImage_GetBits(dib) + pitch * height once, and break out of the row loop if a run would write past it, in both the packed-data and unpacked-data code paths.

Verified: a PICT that previously triggered an AddressSanitizer heap-buffer-overflow now decodes without any out-of-bounds access, and well-formed PICT images still decode.

CWE-787 (out-of-bounds heap write); denial-of-service / memory corruption (the reachable write content is constrained, so this is not code execution).

The PackBits decompression loop in UnpackBits advances dst by the
decoded run length without verifying that the destination remains
within the allocated bitmap raster. A crafted PICT file with run
lengths that exceed the image causes expandBuf/expandBuf8 and the
repeat memcpy to write past the end of the bitmap.

This is the sibling of the UnpackPictRow fix (PR danoli3#41). UnpackBits is
the decoder used for 1/2/4/16-bpp PICT data (the 8/32-bpp paths go
through the now-bounded UnpackPictRow), and it has the same unbounded
run problem; it is reachable from both the version-1 bitmap opcode and
the version-2 DirectBitsRect/PackBitsRect opcodes.

Clamp each write to the allocated raster: compute the raster end once
(FreeImage_GetBits(dib) + pitch * height) and break out of the row loop
if a run would write past it, in both the packed-data and unpacked-data
code paths.

CWE-787 (Out-of-bounds Write)
Assisted-by: Claude:claude-opus-4-8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant