Skip to content

[V4] Validate BMP headers before allocating pixel storage - #3252

Merged
JimBobSquarePants merged 2 commits into
release/4.1.xfrom
fix/bmp-header-validation-v4
Oct 27, 2026
Merged

JimBobSquarePants merged 2 commits into
release/4.1.xfrom
fix/bmp-header-validation-v4

Conversation

@JimBobSquarePants

Copy link
Copy Markdown
Member

Prerequisites

  • I have written a descriptive pull-request title
  • I have verified that there are no overlapping pull-requests open
  • I have verified that I am following the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules 👮.
  • I have provided test coverage for my change (where applicable)

Description

Backport #3223 to release/4.1.x, including the review corrections. This branch includes current release/4.1.x. It remains draft until the main fix is merged.

Reject unsupported RGB bit depths in both Identify and Load. Reject truncated uncompressed RGB and bit-fields data before allocating pixel storage. Count available rows by division so maximum 32-bit dimensions cannot overflow the check. Retain support for missing final-row padding and both row orders. RLE data is excluded from the fixed-size check.

Invalid layouts and dimensions that cannot fit the available pixel data remain fatal under all SegmentIntegrityHandling modes. No public API changes are required.

All new inputs are stored files: 13 fixtures, 1,228 bytes total. Their headers, masks, lengths and intended truncations were independently checked. Pillow also verifies the pixels in both valid fixtures. Tests use the existing TestFile cache and test allocator. No test inputs are generated at runtime.

Verification

  • Release .NET 8: 442 BMP, ICO, CUR, ANI, general format and invalid-dimension tests passed.
  • Release .NET 10: the same 442 tests passed.
  • No tolerances or reference images changed.

Backports #3223. Addresses #3235 for V4.

jafin and others added 2 commits October 27, 2026 13:39
An uncompressed bitmap with a bit depth other than 1, 2, 4, 8, 16, 24 or 32 was
accepted by Identify, and Load failed with an ImageFormatException or a
NotSupportedException depending on the depth. The header reader now rejects such
depths with an InvalidImageContentException, so identification and decoding agree.

An uncompressed or bit fields header could also declare far more pixel data than the
stream holds. The decoder allocated the full pixel buffer before the first row read
failed, and a single short row decoded without error. The declared pixel data is now
checked against the remaining stream before the image is allocated; only the padding
of the last row may be missing.
Count available complete rows after reserving the final row's pixel bytes.
This avoids long overflow for maximum 32-bit BMP dimensions and rejects
impossible dimensions before any pixel buffer request in every integrity mode.
Retain missing final padding and both stored row orders.

Replace the PR's runtime BMP builder and encoder-generated input with 13 fixed
files (1228 bytes total). Independently check their headers, lengths, masks,
and intended truncations; Pillow also verifies both valid pixel arrays.
Extend allocation assertions to detect any Rgba32 allocation, including split
buffers, rather than only one allocation the size of the complete image.

Current main fails 11 malformed-file cases; the original patch still fails
the maximum-dimension regression. Release .NET 10: 392 BMP/ICO/CUR/ANI tests
and 50 general format/dimension tests pass with the corrected patch.
@JimBobSquarePants
JimBobSquarePants marked this pull request as ready for review October 27, 2026 03:54
@JimBobSquarePants
JimBobSquarePants merged commit 24f07bf into release/4.1.x Oct 27, 2026
11 checks passed
@JimBobSquarePants
JimBobSquarePants deleted the fix/bmp-header-validation-v4 branch October 27, 2026 03:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BMP decoder accepts invalid uncompressed bit depths in Identify and allocates the full pixel buffer for truncated files

2 participants