Summary
A malformed JPEG 2000 codestream can reproducibly crash the OpenJPEG tile header decoding path under AddressSanitizer.
The crash occurs as a READ SEGV in:
opj_tcd_get_decoded_tile_size()
src/lib/openjp2/tcd.c:1426
I am not making a strong claim about code execution. At minimum, this appears to be a reproducible decoder crash / robustness issue caused by invalid decoded-resolution state handling.
Reproducer
Attached archive:
openjpeg_tcd1426.zip
The archive contains:
OpenJPEG_tcd1426_invalid_resolution_state_report_en.md
openjpeg_tcd1426_crash_input.j2k
openjpeg_tcd1426_asan.log
Crash input metadata:
Filename: openjpeg_tcd1426_crash_input.j2k
SHA-256: 660ce4995e12714ba9ed3b19b310fd3d52a5bff27e42a3bf3690bba976083f2e
Size: 5476 bytes
Reproduction Command
BIN=/home/js/ctf_dreamhack/fuzzing/2_fuzz/openjpeg/campaign/bin/tile_header_data_partial_afl_asan
CRASH="/path/to/openjpeg_tcd1426_crash_input.j2k"
ASAN_OPTIONS=detect_leaks=0:symbolize=1:handle_segv=1:abort_on_error=0 \
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
"$BIN" "$CRASH" 2>&1 | tee /tmp/openjpeg_tcd1426_asan.log
ASAN Output
AddressSanitizer:DEADLYSIGNAL
=================================================================
ERROR: AddressSanitizer: SEGV on unknown address 0x615fffffffc8
The signal is caused by a READ memory access.
#0 opj_tcd_get_decoded_tile_size
src/lib/openjp2/tcd.c:1426:37
#1 opj_j2k_read_tile_header
src/lib/openjp2/j2k.c:10097:24
#2 opj_read_tile_header
src/lib/openjp2/openjpeg.c:575:16
#3 LLVMFuzzerTestOneInput
campaign/harnesses/tile_header_data_partial_fuzzer.cpp:344:10
#4 main
campaign/harnesses/tile_header_data_partial_afl_driver.cpp:50:5
SUMMARY: AddressSanitizer: SEGV
src/lib/openjp2/tcd.c:1426:37
in opj_tcd_get_decoded_tile_size
Root Cause Summary
The crash appears to be related to opj_j2k_set_decoded_resolution_factor() updating the decoder state's m_reduce field before validating whether the requested resolution factor is legal.
The reproducer contains a COD marker at offset 136.
COD payload:
00000001000204040001
byte_at_145 = 0x02
num decomposition raw = 2
OpenJPEG numresolutions = raw + 1 = 3
res_factor = 3
If the caller ignores the failure return value from opj_set_decoded_resolution_factor() and continues decoding, opj_tcd_init_tile() can later compute:
minimum_num_resolutions = 3 - 3 = 0
This is consistent with opj_tcd_get_decoded_tile_size() deriving a resolutions - 1 pointer and crashing on a read.
Suggested Fix / Hardening Direction
Validate res_factor before mutating decoder state.
Current order:
p_j2k->m_cp.m_specific_param.m_dec.m_reduce = res_factor;
if (res_factor >= max_res) {
return OPJ_FALSE;
}
Suggested order:
if (res_factor >= max_res) {
return OPJ_FALSE;
}
p_j2k->m_cp.m_specific_param.m_dec.m_reduce = res_factor;
Additional hardening ideas:
- Validate
minimum_num_resolutions before using it to derive a pointer into resolutions.
- Treat a failed
opj_set_decoded_resolution_factor() as fatal in callers, or restore the previous state on failure.
- Add a regression test using the attached reproducer.
Reporter Attribution
Thank you for taking the time to review this report.
Summary
A malformed JPEG 2000 codestream can reproducibly crash the OpenJPEG tile header decoding path under AddressSanitizer.
The crash occurs as a READ SEGV in:
I am not making a strong claim about code execution. At minimum, this appears to be a reproducible decoder crash / robustness issue caused by invalid decoded-resolution state handling.
Reproducer
Attached archive:
openjpeg_tcd1426.zip
The archive contains:
Crash input metadata:
Reproduction Command
ASAN Output
Root Cause Summary
The crash appears to be related to
opj_j2k_set_decoded_resolution_factor()updating the decoder state'sm_reducefield before validating whether the requested resolution factor is legal.The reproducer contains a
CODmarker at offset136.If the caller ignores the failure return value from
opj_set_decoded_resolution_factor()and continues decoding,opj_tcd_init_tile()can later compute:This is consistent with
opj_tcd_get_decoded_tile_size()deriving aresolutions - 1pointer and crashing on a read.Suggested Fix / Hardening Direction
Validate
res_factorbefore mutating decoder state.Current order:
Suggested order:
Additional hardening ideas:
minimum_num_resolutionsbefore using it to derive a pointer intoresolutions.opj_set_decoded_resolution_factor()as fatal in callers, or restore the previous state on failure.Reporter Attribution
Thank you for taking the time to review this report.