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

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/uclouvain/openjpeg/issues/861
## Description:
Issue: uclouvain/openjpeg#861
Title: [CVE-2016-9118] Heap Buffer Overflow in function pnmtoimage of convert.c
State: closed
Created by: YangY-Xiao
Created at: 2016-10-30 03:53:07+00:00
Labels: bug

Issue Body:
# **Description**

OpenJPEG Heap Buffer Overflow in function pnmtoimage of convert.c:1719
# **Testing Environment**

Ubuntu(16.04) + OpenJPEG(2.1.2)
# **Exception Information**
## **Address Sanitizer Output**

==9282==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xb57007f4 at pc 0x08146481 bp 0xbffe8268 sp 0xbffe825c
WRITE of size 4 at 0xb57007f4 thread T0
    #0 0x8146480  (/home/yang/openjpeg/openjpeg-2.1.2/build-clang/bin/opj_compress+0x8146480)
    #1 0x81333b6  (/home/yang/openjpeg/openjpeg-2.1.2/build-clang/bin/opj_compress+0x81333b6)
    #2 0xb7438636  (/lib/i386-linux-gnu/libc.so.6+0x18636)
    #3 0x805f227  (/home/yang/openjpeg/openjpeg-2.1.2/build-clang/bin/opj_compress+0x805f227)

0xb57007f4 is located 0 bytes to the right of 4-byte region [0xb57007f0,0xb57007f4)
allocated by thread T0 here:
    #0 0x81036f4  (/home/yang/openjpeg/openjpeg-2.1.2/build-clang/bin/opj_compress+0x81036f4)
    #1 0xb7721e0c  (/home/yang/openjpeg/openjpeg-2.1.2/build-clang/bin/libopenjp2.so.7+0x99e0c)
    #2 0xb769e081  (/home/yang/openjpeg/openjpeg-2.1.2/build-clang/bin/libopenjp2.so.7+0x16081)
    #3 0x8145543  (/home/yang/openjpeg/openjpeg-2.1.2/build-clang/bin/opj_compress+0x8145543)
    #4 0x81333b6  (/home/yang/openjpeg/openjpeg-2.1.2/build-clang/bin/opj_compress+0x81333b6)
    #5 0xb7438636  (/lib/i386-linux-gnu/libc.so.6+0x18636)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/home/yang/openjpeg/openjpeg-2.1.2/build-clang/bin/opj_compress+0x8146480) 
Shadow bytes around the buggy address:
  0x36ae00a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36ae00b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36ae00c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36ae00d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36ae00e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x36ae00f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa[04]fa
  0x36ae0100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36ae0110: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36ae0120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36ae0130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36ae0140: 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
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  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
==9282==ABORTING
## **GDB Information**

Program received signal SIGSEGV, Segmentation fault.
0x08051cb5 in pnmtoimage (filename=0xbf9b1e18 "crash/6.pgm", parameters=0xbf9b0718)
    at /home/yang/openjpeg/openjpeg-2.1.2/src/bin/jp2/convert.c:1719
1719                                image->comps[0].data[i] = (((uc>>bit) & 1)?0:255);
(rr) p i
$10 = 32646
(rr) p x
$11 = 32646
(rr) p y
$12 = 0
(rr) p image->comps[0].data 
$13 = (OPJ_INT32 *) 0x86251e8
(rr) p h
$14 = 2147483647
(rr) p w
$15 = 2147483647
(rr) p image->comps[0].data[i]
Cannot access memory at address 0x8645000
# **Analysis**

```
if(format == 4)
{
    int x, y, bit;
    unsigned char uc;
    i = 0;
    for(y = 0; y < h; ++y)
    {
        bit = -1; uc = 0;

        for(x = 0; x < w; ++x)
        {
            if(bit == -1)
            {
                bit = 7;
                uc = (unsigned char)getc(fp);
            }
            image->comps[0].data[i] = (((uc>>bit) & 1)?0:255);
            --bit; ++i;
        }
    }
}
```
# **Analysis**

function pnmtoimage(convert.c:1553)
   |
   |-->function read_pnm_header(fp, &header_info) 
           |     //FILE _fp; struct pnm_header header_info
           |
           |-->function skip_int(s, &ph->width)
                          |-->  return ph->width = 2147483647(0x7fffffff)  from atoi("555555555544\n")  
           |-->function skip_int(s, &ph->height)
                          |--> same as ph->width = 2147483647(0x7fffffff)  from atoi("555555555544\n")  
   |-->function opj_image_create
           |-->comp->data = (OPJ_INT32_) opj_calloc(comp->w \* comp->h, sizeof(OPJ_INT32)); 
                 |--> w = 0x7fffffff h = 0x7fffffff w*h = 1 (Integer Overflow)
                 |-->sizeof(comp->data) = 1
   |-->image->comps[0].data[i] = (((uc>>bit) & 1)?0:255); (convert:1719) 
           |--> access violation (heap buffer overflow)

crash.pgm(ubuntu)
0000000 3450 350a 3535 3535 3535 3535 3435 0a34
0000010 3535 3535 3535 3535 3535 3434 3404 0a34
0000020 bf23                                   
# **Poc**

Contact me if you need Poc file at YangX92@hotmail.com



Comments:
Comment by 1ucian0 on 2016-12-03 04:52:57+00:00:
Please, refer to this issue as CVE-2016-9118

---

Comment by fgeek on 2017-08-12 09:57:18+00:00:
Does openjpeg have some kind of test suite? The PoC file should be included there in cases like these.

---

Comment by rouault on 2017-08-13 12:30:29+00:00:
> Does openjpeg have some kind of test suite?

It does. Yes extending it is good practice, although sometimes a bit tricky to be relevant when using fuzzed files that might be rejected for other reasons by later fixes. So ideally files should exhibit one single defect and be conformant/usual for the rest.

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 1f1e968269bbd7eaade7955892a6d8c281b91df2
WORKDIR $SRC/openjpeg
COPY build.sh $SRC/

Additional files: