Project: openjpeg (uclouvain/openjpeg), language: c++
Vulnerability instance: openjpeg.cve-2019-6988
Sanitizer: address

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/uclouvain/openjpeg/issues/1178
## Description:
Issue: uclouvain/openjpeg#1178
Title: memory exhauted and hangs long time when use 64bit opj_decompress (CVE-2019-6988)
State: open
Created by: yanxxd
Created at: 2019-01-17 14:49:50+00:00

Issue Body:
I found a problem which will cause memory is exhausted, and program hang for 8 minutes. My test server had 112GB of memory. This can cause denial of service. 

### Steps to Reproduce
1. Download and unzip [POC.zip]
[POC.zip](https://github.com/uclouvain/openjpeg/files/2769058/POC.zip)
2. Run `opj_decompress -i POC -o /tmp/1.png`
3. When I test it use 32bit opj_decompress with asan, the following is the output information
```
===========================================
The extension of this file is incorrect.
FOUND p:16. SHOULD BE .j2k or .jpc or .j2c
===========================================

[INFO] Start to read j2k main header (0).
[WARNING] Unknown marker
[WARNING] Unknown marker
[WARNING] Cannot take in charge mct data within multiple MCT records
[WARNING] Unknown marker
[ERROR] Unknown progression order in COD marker
[WARNING] Unknown marker
[WARNING] Cannot take in charge mct data within multiple MCT records
[WARNING] Unknown marker
[ERROR] Unknown progression order in COD marker
[WARNING] Unknown marker
[WARNING] Cannot take in charge mct data within multiple MCT records
[WARNING] Unknown marker
[ERROR] Unknown progression order in COD marker
[WARNING] Unknown marker
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
=================================================================
==26110==ERROR: AddressSanitizer: allocator is out of memory trying to allocate 0x2f4ad890 bytes
    #0 0x81083a5 in calloc /soft/clang/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:155:3
    #1 0xf7dda139 in opj_calloc ./openjpeg/src/lib/openjp2/opj_malloc.c:204:12
    #2 0xf7d7685c in opj_tcd_init_tile ./openjpeg/src/lib/openjp2/tcd.c:1111:56
    #3 0xf7d87c0f in opj_tcd_init_decode_tile ./openjpeg/src/lib/openjp2/tcd.c:1184:12
    #4 0xf793a827 in opj_j2k_decode_tiles ./openjpeg/src/lib/openjp2/j2k.c:10717:19
    #5 0xf785ba1c in opj_j2k_exec ./openjpeg/src/lib/openjp2/j2k.c:8105:33
```

### Analysis
1. Alloc too much big memory.
2. Maybe too many cycles

### System Configuration
- version: git commit 51f097e6d5754ddae93e716276fe8176b44ec548
- Environment: Ubuntu 16.04.3 TLS
- Memery Size: 112GB
- component: 64bit opj_decompress


These vulnerabilities have been found with a more efficient version of the AFL fuzzer.


Comments:
Comment by szukw000 on 2019-01-17 18:14:12+00:00:
I have a simple JPEG2000 reader. Using it I found:
```
NAME(/tmp/POC.j2k)
LENG(2694)

ENTER read_jp2c
[0]marker(0xff4f)
    soc len(0)
[2]marker(0xff51)
    siz len(50)
    capabilities(0)[extended: 0]
    x(0 : 2147418112) y(16 : 67108896)
    xt(0 : 377547551) yt(0 : 4194336)
    IMAGE w(2147418112) h(67108880) TILE w(377547551) h(4194336)
    nr_components(4)
      component[0] signed(0) prec(2) hsep(1) vsep(231)
      component[1] signed(1) prec(12) hsep(1) vsep(255)
      component[2] signed(0) prec(2) hsep(1) vsep(1)
      component[3] signed(0) prec(1) hsep(222) vsep(255)
[54]marker(0xffff)
test_marker: type(0xffff) prefix(0xff) suffix(0xff)
 I :MARKER 0xffff is unknown.
EXIT read_jp2c
    end - s ==> -62899
EXIT with end - s ==> 0 (DEC:0)
```
winfried

---

Comment by yanxxd on 2019-01-18 16:51:23+00:00:
Should memory checks be added to the program? Otherwise the memory will be exhausted.

---

Comment by szukw000 on 2019-01-20 10:48:11+00:00:
@yanxdd , @rouault ,
```
j2k.c, line 9497:
==================
    /* in the absence of JP2 boxes, consider different bit depth / sign */
    /* per component is allowed */
    l_j2k->m_cp.allow_different_bit_depth_sign = 1;


j2k.c, line 2237:
==================
            } else if (!l_cp->allow_different_bit_depth_sign
                       && (l_img_comp->prec != l_prec0 || l_img_comp->sgnd != l_sgnd0)) {
                opj_event_msg(p_manager, EVT_WARNING,
                              "Despite JP2 BPC!=255, precision and/or sgnd values for comp[%d] is different than comp[0]:\n"
                              "        [0] prec(%d) sgnd(%d) [%d] prec(%d) sgnd(%d)\n", i, l_prec0, l_sgnd0,
                              i, l_img_comp->prec, l_img_comp->sgnd);
            }


JP2 BPC!=255 : jp2->bpc gets a value in jp2.c .
Why a WARNING for allowed values?

All decompressors explicitly ask for equal values,
e.g. convertpng.c, line 321:
==================================================
        fprintf(stderr,
                "imagetopng: All components shall have the same subsampling, same bit depth, same sign.\n");
        fprintf(stderr, "\tAborting\n");


Testing dx and dy in j2k.c, I get:
===================================
[INFO] Start to read j2k main header (0).
openjpeg2-2018-12-26/src/lib/openjp2/j2k.c:2248:
        [0] prec0(2) prec(2) sgnd0(0) sgnd(0)
openjpeg2-2018-12-26/src/lib/openjp2/j2k.c:2248:
        [1] prec0(2) prec(12) sgnd0(0) sgnd(1)
openjpeg2-2018-12-26/src/lib/openjp2/j2k.c:2270:
        [1] dx0(1) dx(1) dy0(231) dy(255)
[ERROR] dy(255) != dy0(231)
[ERROR] Marker handler function failed to read the marker segment
ERROR -> opj_decompress: failed to read the header
```
winfried


---

Comment by nluedtke on 2019-01-30 14:14:47+00:00:
This was assigned [CVE-2019-6988](https://nvd.nist.gov/vuln/detail/CVE-2019-6988).

---

Comment by hlef on 2019-10-07 13:08:20+00:00:
@yanxxd is this issue invalid, or was it fixed at some point?

If this issue is invalid, we should ask for CVE rejection.

---

Comment by flobeier on 2020-02-29 23:52:26+00:00:
@yanxxd pinging you again, has this issue been fixed by now or was it invalid?

---

Comment by yanxxd on 2020-03-01 08:58:29+00:00:
I tested it use the latest version, git commit 563ecfb55ca77c0fc5ea19e4885e00f55ec82ca9. The program run about 10 minutes, CPU 100%, MEM 100%. The following is the output:
```
opj_decompress -i POC -o /tmp/1.png

===========================================
The extension of this file is incorrect.
FOUND /POC. SHOULD BE .j2k or .jpc or .j2c
===========================================

[INFO] Start to read j2k main header (0).
[WARNING] Unknown marker
[WARNING] Unknown marker
[WARNING] Cannot take in charge mct data within multiple MCT records
[WARNING] Unknown marker
[ERROR] Unknown progression order in COD marker
[WARNING] Unknown marker
[WARNING] Cannot take in charge mct data within multiple MCT records
[WARNING] Unknown marker
[ERROR] Unknown progression order in COD marker
[WARNING] Unknown marker
[WARNING] Cannot take in charge mct data within multiple MCT records
[WARNING] Unknown marker
[ERROR] Unknown progression order in COD marker
[WARNING] Unknown marker
[INFO] Main header has been correctly decoded.
[INFO] No decoded area parameters, set the decoded area to the whole image
Killed
```
You can reproduce it use the POC.

---

Comment by flobeier on 2020-03-01 12:10:10+00:00:
Thanks! Perhaps this issue should be reopened then.

---

Comment by rouault on 2020-03-06 14:38:09+00:00:
While for this particular file (POC), we could bail out earlier given a number of corruptions in segment markers, this wouldn't fix the underlying issue. This issue is a design one. The library pre-allocates precints and codeblocks related structures, such as tagtree, for a whole tile. In the case of POC, there are for example 37 million codeblocks for one precinct, which represents 4 GB of RAM for the codeblock working memory (and other GB for tagtree etc). Completely legit JPEG2000 images could be built with the same characteristics as those corrupted images, and with sufficient huge amount of RAM could be docoded. As fixing the design of openjpeg would be enormous work, a fix would probably to set some implementation-defined thresholds, not normally reached on "normal" images, and error out if they are reached, and let the user able to override them with some environment variable.

---

Comment by yanxxd on 2020-03-07 07:44:34+00:00:
Setting some implementation-defined thresholds may be a viable solution.

---

Comment by ckauhaus on 2020-05-20 09:52:59+00:00:
Any news on this?

---

Comment by utkarsh2102 on 2020-07-10 17:26:50+00:00:
Hiya!
Any ETA on this!?


---

Comment by malaterre on 2021-01-27 15:45:22+00:00:
@yanxxd can you reproduce CVE-2019-6988 using opj 2.4.0 ?

---

Comment by JaiKishan132 on 2021-05-14 11:15:49+00:00:
Hi, Any update on the issue?

---

Comment by kingysu on 2023-11-02 02:37:49+00:00:
> Hi, Any update on the issue?

@yanxxd @rouault 
1. I have investigated the problem recently. I found there is commit which has "solved" the problem. The commit is: [f3ee448 ](https://github.com/uclouvain/openjpeg/commit/f3ee448815eb992b8d4746e32c05e8289f30415f)[openjp2/j2k: Validate all SGcod/SPcod/SPcoc parameter values.](https://github.com/uclouvain/openjpeg/commit/f3ee448815eb992b8d4746e32c05e8289f30415f). 

2. After some debugging, I found the code which has "solved" the problem:
`    if (l_tccp->qmfbid > 1) {
        opj_event_msg(p_manager, EVT_ERROR,
                      "Error reading SPCod SPCoc element, Invalid transformation found\n");
        return OPJ_FALSE;
    }`

3. l_tccp->qmfbid's value is 255 and it's greater than 1, so the function will return false. Finally, the program will exit. According the spec, l_tccp->qmfbid's valid value shoud be 0 or 1.
4. This is the output:
===========================================
The extension of this file is incorrect.
FOUND /POC. SHOULD BE .j2k or .jpc or .j2c
===========================================

[INFO] Start to read j2k main header (0).
[WARNING] Unknown marker
[WARNING] Unknown marker
[WARNING] Cannot take in charge mct data within multiple MCT records
[WARNING] Unknown marker
[ERROR] Unknown progression order in COD marker
[ERROR] Error reading SPCod SPCoc element, Invalid transformation found
[ERROR] Error reading COD marker
[ERROR] Marker handler function failed to read the marker segment
ERROR -> opj_decompress: failed to read the header


Attachments:
https://github.com/uclouvain/openjpeg/files/2769058/POC.zip

Commit References:
563ecfb55ca77c0fc5ea19e4885e00f55ec82ca9
51f097e6d5754ddae93e716276fe8176b44ec548
f3ee448815eb992b8d4746e32c05e8289f30415f

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
mkdir -p build
cd build
cmake ..
make clean -s -j$(nproc)
make -j$(nproc) -s

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y make cmake g++
RUN git clone https://github.com/uclouvain/openjpeg openjpeg
RUN git -C openjpeg checkout 081de4b15f54cb4482035b7bf5e3fb443e4bc84b
WORKDIR $SRC/openjpeg
COPY build.sh $SRC/

Additional files: