Repository: uclouvain/openjpeg
Fuzzing engine: libfuzzer
Fuzz target: opj_decompress_fuzzer
Sanitizer: address
Crash type: Heap-buffer-overflow READ {*}

Sanitizer report:
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 4140116622
INFO: Loaded 1 modules   (8950 inline 8-bit counters): 8950 [0x56211da53640, 0x56211da55936), 
INFO: Loaded 1 PC tables (8950 PCs): 8950 [0x56211da55938,0x56211da78898), 
/out/opj_decompress_fuzzer: Running 1 inputs 1 time(s) each.
Running: /testcase/OSV-2017-35.poc
=================================================================
==7==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x5100000004e0 at pc 0x56211d8256b2 bp 0x7ffe8ed31120 sp 0x7ffe8ed308e0
READ of size 17179869180 at 0x5100000004e0 thread T0
SCARINESS: 26 (multi-byte-read-heap-buffer-overflow)
    #0 0x56211d8256b1 in __asan_memcpy /src/llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:63:3
    #1 0x56211d96c5ee in opj_dwt_decode_partial_tile /src/openjpeg/src/lib/openjp2/dwt.c:1831:17
    #2 0x56211d96c5ee in opj_dwt_decode /src/openjpeg/src/lib/openjp2/dwt.c:1230:16
    #3 0x56211d95eb0c in opj_tcd_dwt_decode /src/openjpeg/src/lib/openjp2/tcd.c:1781:19
    #4 0x56211d95eb0c in opj_tcd_decode_tile /src/openjpeg/src/lib/openjp2/tcd.c:1468:8
    #5 0x56211d90d30c in opj_j2k_decode_tile /src/openjpeg/src/lib/openjp2/j2k.c:8809:11
    #6 0x56211d92806f in opj_j2k_decode_tiles /src/openjpeg/src/lib/openjp2/j2k.c:10603:15
    #7 0x56211d908d52 in opj_j2k_exec /src/openjpeg/src/lib/openjp2/j2k.c:7979:33
    #8 0x56211d912ec9 in opj_j2k_decode /src/openjpeg/src/lib/openjp2/j2k.c:10860:11
    #9 0x56211d8674b3 in LLVMFuzzerTestOneInput /src/openjpeg/./tests/fuzzers/opj_decompress_fuzzer.cpp:197:13
    #10 0x56211d8843c0 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:614:13
    #11 0x56211d86f635 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:327:6
    #12 0x56211d8750cf in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:862:9
    #13 0x56211d8a0372 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
    #14 0x7f8d9eafe082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 0702430aef5fa3dda43986563e9ffcc47efbd75e)
    #15 0x56211d78e7ad in _start (/out/opj_decompress_fuzzer+0x7f7ad)

DEDUP_TOKEN: __asan_memcpy--opj_dwt_decode_partial_tile--opj_dwt_decode
0x5100000004e0 is located 0 bytes after 160-byte region [0x510000000440,0x5100000004e0)
allocated by thread T0 here:
    #0 0x56211d828267 in posix_memalign /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:142:3
    #1 0x56211d8ffbbe in opj_aligned_alloc_n /src/openjpeg/src/lib/openjp2/opj_malloc.c:61:9
    #2 0x56211d8ffbbe in opj_aligned_32_malloc /src/openjpeg/src/lib/openjp2/opj_malloc.c:218:12
    #3 0x56211d96b601 in opj_dwt_decode_partial_tile /src/openjpeg/src/lib/openjp2/dwt.c:1722:25
    #4 0x56211d96b601 in opj_dwt_decode /src/openjpeg/src/lib/openjp2/dwt.c:1230:16
    #5 0x56211d95eb0c in opj_tcd_dwt_decode /src/openjpeg/src/lib/openjp2/tcd.c:1781:19
    #6 0x56211d95eb0c in opj_tcd_decode_tile /src/openjpeg/src/lib/openjp2/tcd.c:1468:8
    #7 0x56211d90d30c in opj_j2k_decode_tile /src/openjpeg/src/lib/openjp2/j2k.c:8809:11
    #8 0x56211d92806f in opj_j2k_decode_tiles /src/openjpeg/src/lib/openjp2/j2k.c:10603:15
    #9 0x56211d908d52 in opj_j2k_exec /src/openjpeg/src/lib/openjp2/j2k.c:7979:33
    #10 0x56211d912ec9 in opj_j2k_decode /src/openjpeg/src/lib/openjp2/j2k.c:10860:11
    #11 0x56211d8674b3 in LLVMFuzzerTestOneInput /src/openjpeg/./tests/fuzzers/opj_decompress_fuzzer.cpp:197:13
    #12 0x56211d8843c0 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:614:13
    #13 0x56211d86f635 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:327:6
    #14 0x56211d8750cf in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:862:9
    #15 0x56211d8a0372 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
    #16 0x7f8d9eafe082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 0702430aef5fa3dda43986563e9ffcc47efbd75e)

DEDUP_TOKEN: ___interceptor_posix_memalign--opj_aligned_alloc_n--opj_aligned_32_malloc
SUMMARY: AddressSanitizer: heap-buffer-overflow /src/openjpeg/src/lib/openjp2/dwt.c:1831:17 in opj_dwt_decode_partial_tile
Shadow bytes around the buggy address:
  0x510000000200: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x510000000280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x510000000300: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x510000000380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x510000000400: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
=>0x510000000480: 00 00 00 00 00 00 00 00 00 00 00 00[fa]fa fa fa
  0x510000000500: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x510000000580: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x510000000600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x510000000680: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x510000000700: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==7==ABORTING


Fix patch:
diff --git a/src/lib/openjp2/dwt.c b/src/lib/openjp2/dwt.c
index d33fbeb3..de3ff727 100644
--- a/src/lib/openjp2/dwt.c
+++ b/src/lib/openjp2/dwt.c
@@ -1642,20 +1642,24 @@ static void opj_dwt_get_band_coordinates(opj_tcd_tilecomp_t* tilec,
     OPJ_UINT32 x0b = bandno & 1;
     OPJ_UINT32 y0b = bandno >> 1;
     if (tbx0) {
-        *tbx0 = (nb == 0) ? tcx0 : opj_uint_ceildiv(tcx0 - (1U <<
-                (nb - 1)) * x0b, 1U << nb);
+        *tbx0 = (nb == 0) ? tcx0 :
+                (tcx0 <= (1U << (nb - 1)) * x0b) ? 0 :
+                opj_uint_ceildivpow2(tcx0 - (1U << (nb - 1)) * x0b, nb);
     }
     if (tby0) {
-        *tby0 = (nb == 0) ? tcy0 : opj_uint_ceildiv(tcy0 - (1U <<
-                (nb - 1)) * y0b, 1U << nb);
+        *tby0 = (nb == 0) ? tcy0 :
+                (tcy0 <= (1U << (nb - 1)) * y0b) ? 0 :
+                opj_uint_ceildivpow2(tcy0 - (1U << (nb - 1)) * y0b, nb);
     }
     if (tbx1) {
-        *tbx1 = (nb == 0) ? tcx1 : opj_uint_ceildiv(tcx1 - (1U <<
-                (nb - 1)) * x0b, 1U << nb);
+        *tbx1 = (nb == 0) ? tcx1 :
+                (tcx1 <= (1U << (nb - 1)) * x0b) ? 0 :
+                opj_uint_ceildivpow2(tcx1 - (1U << (nb - 1)) * x0b, nb);
     }
     if (tby1) {
-        *tby1 = (nb == 0) ? tcy1 : opj_uint_ceildiv(tcy1 - (1U <<
-                (nb - 1)) * y0b, 1U << nb);
+        *tby1 = (nb == 0) ? tcy1 :
+                (tcy1 <= (1U << (nb - 1)) * y0b) ? 0 :
+                opj_uint_ceildivpow2(tcy1 - (1U << (nb - 1)) * y0b, nb);
     }
 }
 
@@ -1711,14 +1715,12 @@ static OPJ_BOOL opj_dwt_decode_partial_tile(opj_tcd_t *tcd,
     }
     h_mem_size = opj_dwt_max_resolution(tr, numres);
     /* overflow check */
-    if (h_mem_size > (SIZE_MAX / PARALLEL_COLS_53 / sizeof(OPJ_INT32))) {
+    if (h_mem_size > (SIZE_MAX / sizeof(OPJ_INT32))) {
         /* FIXME event manager error callback */
         return OPJ_FALSE;
     }
-    /* We need PARALLEL_COLS_53 times the height of the array, */
-    /* since for the vertical pass */
-    /* we process PARALLEL_COLS_53 columns at a time */
-    h_mem_size *= PARALLEL_COLS_53 * sizeof(OPJ_INT32);
+
+    h_mem_size *= sizeof(OPJ_INT32);
     h.mem = (OPJ_INT32*)opj_aligned_32_malloc(h_mem_size);
     if (! h.mem) {
         /* FIXME event manager error callback */
diff --git a/src/lib/openjp2/tcd.c b/src/lib/openjp2/tcd.c
index 7a5e2b44..1c56c1b3 100644
--- a/src/lib/openjp2/tcd.c
+++ b/src/lib/openjp2/tcd.c
@@ -2414,14 +2414,18 @@ OPJ_BOOL opj_tcd_is_subband_area_of_interest(opj_tcd_t *tcd,
     /* equation B-15 of the standard */
     OPJ_UINT32 x0b = bandno & 1;
     OPJ_UINT32 y0b = bandno >> 1;
-    OPJ_UINT32 tbx0 = (nb == 0) ? tcx0 : opj_uint_ceildiv(tcx0 - (1U <<
-                      (nb - 1)) * x0b, 1U << nb);
-    OPJ_UINT32 tby0 = (nb == 0) ? tcy0 : opj_uint_ceildiv(tcy0 - (1U <<
-                      (nb - 1)) * y0b, 1U << nb);
-    OPJ_UINT32 tbx1 = (nb == 0) ? tcx1 : opj_uint_ceildiv(tcx1 - (1U <<
-                      (nb - 1)) * x0b, 1U << nb);
-    OPJ_UINT32 tby1 = (nb == 0) ? tcy1 : opj_uint_ceildiv(tcy1 - (1U <<
-                      (nb - 1)) * y0b, 1U << nb);
+    OPJ_UINT32 tbx0 = (nb == 0) ? tcx0 :
+                      (tcx0 <= (1U << (nb - 1)) * x0b) ? 0 :
+                      opj_uint_ceildivpow2(tcx0 - (1U << (nb - 1)) * x0b, nb);
+    OPJ_UINT32 tby0 = (nb == 0) ? tcy0 :
+                      (tcy0 <= (1U << (nb - 1)) * y0b) ? 0 :
+                      opj_uint_ceildivpow2(tcy0 - (1U << (nb - 1)) * y0b, nb);
+    OPJ_UINT32 tbx1 = (nb == 0) ? tcx1 :
+                      (tcx1 <= (1U << (nb - 1)) * x0b) ? 0 :
+                      opj_uint_ceildivpow2(tcx1 - (1U << (nb - 1)) * x0b, nb);
+    OPJ_UINT32 tby1 = (nb == 0) ? tcy1 :
+                      (tcy1 <= (1U << (nb - 1)) * y0b) ? 0 :
+                      opj_uint_ceildivpow2(tcy1 - (1U << (nb - 1)) * y0b, nb);
     OPJ_BOOL intersects;
 
     if (tbx0 < filter_margin) {