Skip to content

fix(jpeg2000): guard against oversized and decompression-bomb headers before decode#5327

Open
lgritz wants to merge 2 commits into
AcademySoftwareFoundation:mainfrom
lgritz:lg-jpeg2000
Open

fix(jpeg2000): guard against oversized and decompression-bomb headers before decode#5327
lgritz wants to merge 2 commits into
AcademySoftwareFoundation:mainfrom
lgritz:lg-jpeg2000

Conversation

@lgritz

@lgritz lgritz commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

check_open() validated the resolution only after opj_decode() had already run, so a corrupt or malicious header could make openjpeg spend a long time and allocate a huge buffer before OIIO ever rejected the file.

Add two pre-decode guards right after opj_read_header():

  1. Build a provisional ImageSpec from the header's canvas size and per-component precision (channel count can still grow later from palette expansion, but that only makes the image larger, so the header-based estimate is a safe lower bound), and run it through check_open() before calling opj_decode().

  2. Add a decompression-bomb check that rejects when the claimed uncompressed size both exceeds 1 GB and dwarfs the actual file size by more than 10000x -- a ratio far beyond anything a real JPEG2000 codestream produces.

The existing post-decode check_open() call stays in place as the authoritative check once the final channel count is known.

Also drop dead commented-out debug std::cout lines and an unused chantypes vector left over from earlier work.

Assisted-by: Claude Code / Claude Opus 4.8

lgritz added 2 commits July 19, 2026 21:44
… before decode

check_open() validated the resolution only after opj_decode() had
already run, so a corrupt or malicious header could make openjpeg
spend a long time and allocate a huge buffer before OIIO ever
rejected the file.

Add two pre-decode guards right after opj_read_header():

1. Build a provisional ImageSpec from the header's canvas size and
   per-component precision (channel count can still grow later from
   palette expansion, but that only makes the image larger, so the
   header-based estimate is a safe lower bound), and run it through
   check_open() before calling opj_decode().

2. That absolute-size check alone isn't enough: a 171-byte fuzzed
   codestream declared a 32 x 50331680 image (9216 MB), under the
   default limits:imagesize_MB (32 GB), so opj_decode still hung
   allocating ~9 GB and decoding 1.6 billion pixels. Add a
   decompression-bomb check that rejects when the claimed
   uncompressed size both exceeds 1 GB and dwarfs the actual file
   size by more than 10000x -- a ratio far beyond anything a real
   JPEG2000 codestream produces.

The existing post-decode check_open() call stays in place as the
authoritative check once the final channel count is known. Verified
the openjpeg conformance suite still decodes correctly, so neither
guard rejects real files.

Also drop dead commented-out debug std::cout lines and an unused
chantypes vector left over from earlier work.

Assisted-by: Claude Code / Claude Opus 4.8

Signed-off-by: Larry Gritz <lg@larrygritz.com>
Signed-off-by: Larry Gritz <lg@larrygritz.com>
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