Project: libjpeg-turbo (libjpeg-turbo/libjpeg-turbo), language: c++
Vulnerability instance: libjpeg-turbo.cve-2020-13790
Sanitizer: address

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/libjpeg-turbo/libjpeg-turbo/issues/433
## Description:
Issue: libjpeg-turbo/libjpeg-turbo#433
Title: Heap-based buffer over-read in get_rgb_row() in rdppm.c
State: closed
Created by: sanjeevk001
Created at: 2020-05-25 18:37:38+00:00
Labels: bug, fixed

Issue Body:
**Have you searched the existing issues (both open and closed) in the libjpeg-turbo issue tracker to ensure that this bug report is not a duplicate?**
Yes

**Does this bug report describe one of the [two known and unsolvable issues with the JPEG format](https://libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf)?**
No

**Clear and concise description of the bug:**
 Heap-based buffer over-read in get_rgb_row() in rdppm.c

**Steps to reproduce the bug (using *only* libjpeg-turbo):**
 Compile with Address Sanitizer (ASan) :  
./cjpeg ./reproducer 

Without ASan: 
valgrind -q ./cjpeg ./reproducer

**Image(s) needed in order to reproduce the bug (if applicable):**

[reproducer.zip](https://github.com/libjpeg-turbo/libjpeg-turbo/files/4678450/reproducer.zip)

**Expected behavior:**


**Observed behavior:**

```
==2127==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62900000417f at pc 0x55f48a780991 bp 0x7ffccfe84010 sp 0x7ffccfe84000
READ of size 1 at 0x62900000417f thread T0
    #0 0x55f48a780990 in get_rgb_row libjpeg-turbo/rdppm.c:434
    #1 0x55f48a77cadd in main libjpeg-turbo/cjpeg.c:664
    #2 0x7f9476b50b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #3 0x55f48a77d049 in _start (libjpeg-turbo/build/cjpeg+0x6049)

0x62900000417f is located 104 bytes to the right of 16151-byte region [0x629000000200,0x629000004117)
allocated by thread T0 here:
    #0 0x7f947730db40 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb40)
    #1 0x7f9476fea6cb in alloc_small libjpeg-turbo/jmemmgr.c:318
    #2 0x55f48a785157 in jinit_read_ppm libjpeg-turbo/rdppm.c:756
    #3 0x55f48a77c8cb in select_file_type libjpeg-turbo/cjpeg.c:118
    #4 0x55f48a77c8cb in main libjpeg-turbo/cjpeg.c:636
    #5 0x7f9476b50b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)

SUMMARY: AddressSanitizer: heap-buffer-overflow libjpeg-turbo/rdppm.c:434 in get_rgb_row
Shadow bytes around the buggy address:
  0x0c527fff87d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c527fff87e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c527fff87f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c527fff8800: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c527fff8810: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c527fff8820: 00 00 07 fa fa fa fa fa fa fa fa fa fa fa fa[fa]
  0x0c527fff8830: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c527fff8840: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c527fff8850: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c527fff8860: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c527fff8870: 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
==2127==ABORTING
```

**Platform(s) (compiler version, operating system version, CPU) on which the bug was observed:**

gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0, Linux 5.3.0-51-generic 

**libjpeg-turbo release(s), commit(s), or branch(es) in which the bug was observed (always test the tip of the master branch or the latest [stable pre-release](https://libjpeg-turbo.org/DeveloperInfo/PreReleases) to verify that the bug hasn't already been fixed):**

libjpeg-turbo version 2.0.5 (master)

**If the bug is a regression, the specific commit that introduced the regression (use `git bisect` to determine this):**


**Additional information:**



Comments:
Comment by carnil on 2020-06-03 20:30:15+00:00:
This issue got CVE-2020-13790 assigned.

---

Comment by dcommander on 2020-06-03 21:06:37+00:00:
Added CVE ID to the change log.  Thanks.

---

Comment by bird8693 on 2020-11-04 03:26:12+00:00:
> This issue got CVE-2020-13790 assigned.
@carnil  Can you tell me where did you apply for this CVE? The application I submitted to the CVE website has not yet been replied.

Attachments:
https://github.com/libjpeg-turbo/libjpeg-turbo/files/4678450/reproducer.zip

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
cmake . -DCMAKE_INSTALL_PREFIX=$WORK -DENABLE_STATIC:bool=on
make "-j$(nproc)"
make install -j$(nproc)

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y make autoconf automake libtool nasm curl cmake
RUN git clone https://github.com/libjpeg-turbo/libjpeg-turbo libjpeg-turbo
RUN git -C libjpeg-turbo checkout a2291b252de1413a13db61b21863ae7aea0946f3
WORKDIR $SRC/libjpeg-turbo
COPY build.sh $SRC/

Additional files:
filename: libjpeg_turbo_fuzzer.cc
content: /*
# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
################################################################################
*/

#include <stdint.h>
#include <stdlib.h>

#include <memory>

#include <turbojpeg.h>


extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    tjhandle jpegDecompressor = tjInitDecompress();

    int width, height, subsamp, colorspace;
    int res = tjDecompressHeader3(
        jpegDecompressor, data, size, &width, &height, &subsamp, &colorspace);

    // Bail out if decompressing the headers failed, the width or height is 0,
    // or the image is too large (avoids slowing down too much). Cast to size_t to
    // avoid overflows on the multiplication
    if (res != 0 || width == 0 || height == 0 || ((size_t)width * height > (1024 * 1024))) {
        tjDestroy(jpegDecompressor);
        return 0;
    }

    const int buffer_size = width * height * 3;
    std::unique_ptr<unsigned char[]> buf(new unsigned char[buffer_size]);
    tjDecompress2(
        jpegDecompressor, data, size, buf.get(), width, 0, height, TJPF_RGB, 0);

    // For memory sanitizer, test each output byte
    const unsigned char* raw_buf = buf.get();
    int count = 0;
    for( int i = 0; i < buffer_size; i++ )
    {
        if (raw_buf[i])
        {
            count ++;
        }
    }
    if (count == buffer_size)
    {
        // Do something with side effect, so that all the above tests don't
        // get removed by the optimizer.
        free(malloc(1));
    }

    tjDestroy(jpegDecompressor);

    return 0;
}