This report was generated by AI and manually verified.
Summary
src/lib/openjp2/j2k.c::opj_j2k_get_tile
can perform signed 32-bit arithmetic on tile-derived image coordinates that are
not representable as OPJ_INT32. A crafted J2K codestream with extreme SIZ
marker values makes decoding tile 1 reach a signed integer overflow at
src/lib/openjp2/j2k.c:12497.
The issue was reproduced by running the sanitizer-built opj_decompress
executable against the crafted codestream. UBSan reports signed integer
overflow inside opj_j2k_get_tile.
Affected Code
- File:
src/lib/openjp2/j2k.c
- Function:
opj_j2k_get_tile
- Public path:
opj_decompress -t 1
- Library dispatch path:
opj_get_decoded_tile -> opj_j2k_get_tile
- Vulnerable operation: signed arithmetic after narrowing tile/image
coordinates to OPJ_INT32
This is a library-code issue in libopenjp2, confirmed through the normal
opj_decompress executable path.
Impact
A crafted codestream can trigger undefined behavior during tile decoding. In the
validated UBSan build, this is reported as signed integer overflow. In
non-sanitized builds, the overflow can lead to incorrect component dimension
calculations and undefined behavior in the decode path.
Reproduction
PoC and evidence are available under:
Generate the crafted codestream:
python3 row-validation-output/case-008/pocs/generate_case008_poc.py \
--opj-compress build/bin/opj_compress \
--out-dir row-validation-output/case-008/inputs
Run:
UBSAN_OPTIONS=halt_on_error=0:print_stacktrace=1 \
build/bin/opj_decompress \
-i row-validation-output/case-008/inputs/case008_tile_overflow.j2k \
-o row-validation-output/case-008/tmp/case008_tile_overflow.pgx \
-t 1 \
-quiet
The PoC mutates the SIZ marker of a minimal J2K seed so that:
Xsiz = 0xffffffff
Ysiz = 1
XTsiz = 0x80000000
YTsiz = 1
XTOsiz = 0
YTOsiz = 0
This describes two huge horizontal tiles and makes tile 1 produce an
out-of-range signed coordinate in opj_j2k_get_tile.
Sanitizer Evidence
Representative UBSan output:
/home/kery-qi/yf/openjpeg/src/lib/openjp2/openjpeg.c:628:16: runtime error:
call to function opj_j2k_get_tile through pointer to incorrect function type
#0 0x7dc5b2508d4f in opj_get_decoded_tile /home/kery-qi/yf/openjpeg/src/lib/openjp2/openjpeg.c:628:16
#1 0x5ea866ec6c07 in main /home/kery-qi/yf/openjpeg/src/bin/jp2/opj_decompress.c:1601:18
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /home/kery-qi/yf/openjpeg/src/lib/openjp2/openjpeg.c:628:16
/home/kery-qi/yf/openjpeg/src/lib/openjp2/j2k.c:12497:69: runtime error:
signed integer overflow: 0 - -2147483648 cannot be represented in type 'OPJ_INT32' (aka 'int')
#0 0x7dc5b2479ced in opj_j2k_get_tile /home/kery-qi/yf/openjpeg/src/lib/openjp2/j2k.c:12497:69
#1 0x5ea866ec6c07 in main /home/kery-qi/yf/openjpeg/src/bin/jp2/opj_decompress.c:1601:18
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /home/kery-qi/yf/openjpeg/src/lib/openjp2/j2k.c:12497:69
ERROR -> opj_decompress: failed to decode tile!
The same target overflow was reproduced in repeated runs.
The executable also emits unrelated function-pointer-type UBSan diagnostics in
OpenJPEG dispatch wrappers. Those diagnostics are not used as the confirmation
for this report; the confirming diagnostic is the signed integer overflow in
opj_j2k_get_tile.
Root Cause
The tile geometry allows values at or above the signed 32-bit boundary. During
tile decoding, those values are narrowed to OPJ_INT32 and used in signed
subtraction. For the crafted tile, the computation reaches 0 - -2147483648,
which cannot be represented in OPJ_INT32.
Suggested Fix
Validate tile-derived component bounds before narrowing to signed 32-bit types.
Reject SIZ/tile combinations that cannot be represented by the downstream
component dimension calculations, or perform the intermediate calculations in a
wider checked integer type and only narrow after range validation.
This report was generated by AI and manually verified.
Summary
src/lib/openjp2/j2k.c::opj_j2k_get_tilecan perform signed 32-bit arithmetic on tile-derived image coordinates that are
not representable as
OPJ_INT32. A crafted J2K codestream with extreme SIZmarker values makes decoding tile 1 reach a signed integer overflow at
src/lib/openjp2/j2k.c:12497.The issue was reproduced by running the sanitizer-built
opj_decompressexecutable against the crafted codestream. UBSan reports signed integer
overflow inside
opj_j2k_get_tile.Affected Code
src/lib/openjp2/j2k.copj_j2k_get_tileopj_decompress -t 1opj_get_decoded_tile->opj_j2k_get_tilecoordinates to
OPJ_INT32This is a library-code issue in
libopenjp2, confirmed through the normalopj_decompressexecutable path.Impact
A crafted codestream can trigger undefined behavior during tile decoding. In the
validated UBSan build, this is reported as signed integer overflow. In
non-sanitized builds, the overflow can lead to incorrect component dimension
calculations and undefined behavior in the decode path.
Reproduction
PoC and evidence are available under:
2968064cf3b757e0b2de0016b0a80ff6761353388ad43001d4ebd96b4080f17dGenerate the crafted codestream:
Run:
The PoC mutates the SIZ marker of a minimal J2K seed so that:
Xsiz = 0xffffffffYsiz = 1XTsiz = 0x80000000YTsiz = 1XTOsiz = 0YTOsiz = 0This describes two huge horizontal tiles and makes tile 1 produce an
out-of-range signed coordinate in
opj_j2k_get_tile.Sanitizer Evidence
Representative UBSan output:
The same target overflow was reproduced in repeated runs.
The executable also emits unrelated function-pointer-type UBSan diagnostics in
OpenJPEG dispatch wrappers. Those diagnostics are not used as the confirmation
for this report; the confirming diagnostic is the signed integer overflow in
opj_j2k_get_tile.Root Cause
The tile geometry allows values at or above the signed 32-bit boundary. During
tile decoding, those values are narrowed to
OPJ_INT32and used in signedsubtraction. For the crafted tile, the computation reaches
0 - -2147483648,which cannot be represented in
OPJ_INT32.Suggested Fix
Validate tile-derived component bounds before narrowing to signed 32-bit types.
Reject SIZ/tile combinations that cannot be represented by the downstream
component dimension calculations, or perform the intermediate calculations in a
wider checked integer type and only narrow after range validation.