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

================= Bug Report (1/2) ==================
## Source: GitHub Issue
## URL: https://github.com/libjpeg-turbo/libjpeg-turbo/issues/258
## Description:
Issue: libjpeg-turbo/libjpeg-turbo#258
Title: AddressSanitizer: heap-buffer-overflow inside get_8bit_row (rdbmp.c)
State: closed
Created by: hongxuchen
Created at: 2018-07-20 13:44:22+00:00
Labels: bug, fixed

Issue Body:
(This was firstly mentioned in https://github.com/mozilla/mozjpeg/issues/299 and following @kornelski's suggestion I checked f4b8a5c and found similar issues; note that libjpeg did not trigger several crashes that mozjpeg triggered).

It can be triggered with `cjpeg -outfile /dev/null $POC` where $POC can be found [in this directory](https://github.com/ntu-sec/pocs/tree/master/libjpeg-f4b8a5c) (files ending with .bmp). ASAN messages are like:

```
=================================================================
==27647==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x611000000150 at pc 0x000000524062 bp 0x7ffd414b8060 sp 0x7ffd414b8058
READ of size 1 at 0x611000000150 thread T0
    #0 0x524061 in get_8bit_row /home/hongxu/FOT/libjpeg-turbo/rdbmp.c:209:26
    #1 0x513497 in main /home/hongxu/FOT/libjpeg-turbo/cjpeg.c:664:21
    #2 0x7fe82e562b96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310
    #3 0x41aa49 in _start (/home/hongxu/FOT/libjpeg-turbo/cjpeg+0x41aa49)

Address 0x611000000150 is a wild pointer.
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/hongxu/FOT/libjpeg-turbo/rdbmp.c:209:26 in get_8bit_row
Shadow bytes around the buggy address:
  0x0c227fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c227fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c227fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c227fff8000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c227fff8010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c227fff8020: 00 00 00 00 00 00 07 fa fa fa[fa]fa fa fa fa fa
  0x0c227fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c227fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c227fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c227fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c227fff8070: 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
==27647==ABORTING
```


================= Bug Report (2/2) ==================
## Source: GitHub Issue
## URL: https://github.com/mozilla/mozjpeg/issues/299
## Description:
Issue: mozilla/mozjpeg#299
Title: AddressSanitizer: heap-buffer-overflow inside get_8bit_row (rdbmp.c)
State: open
Created by: hongxuchen
Created at: 2018-07-20 04:57:53+00:00

Issue Body:
Our fuzzer detected several buffer overflow errors inside `get_8bit_row` (lines 145, 146, and 147) as of 7678cba. These can be triggered with `cjpeg -outfile /dev/null $POC` where $POC can be found [in this directory](https://github.com/ntu-sec/pocs/tree/master/mozjpeg-7678cba) (files ending with `.bmp`). Error messages are like:

```
=================================================================
==6549==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60d0000000d3 at pc 0x0000005270a1 bp 0x7ffdb2cc6390 sp 0x7ffdb2cc6388
READ of size 1 at 0x60d0000000d3 thread T0
    #0 0x5270a0 in get_8bit_row /home/hongxu/FOT/mozjpeg-clang/rdbmp.c:145:17
    #1 0x526cb9 in preload_image /home/hongxu/FOT/mozjpeg-clang/rdbmp.c:270:10
    #2 0x514cce in main /home/hongxu/FOT/mozjpeg-clang/cjpeg.c:810:21
    #3 0x7f66c720bb96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310
    #4 0x41b0f9 in _start (/home/hongxu/FOT/mozjpeg-clang/install/bin/cjpeg+0x41b0f9)

0x60d0000000d3 is located 12 bytes to the right of 135-byte region [0x60d000000040,0x60d0000000c7)
allocated by thread T0 here:
    #0 0x4dafb0 in malloc (/home/hongxu/FOT/mozjpeg-clang/install/bin/cjpeg+0x4dafb0)
    #1 0x7f66c8794358 in jpeg_get_large /home/hongxu/FOT/mozjpeg-clang/jmemnobs.c:56:19
    #2 0x7f66c878deca in alloc_large /home/hongxu/FOT/mozjpeg-clang/jmemmgr.c:393:30
    #3 0x7f66c878e3a7 in alloc_sarray /home/hongxu/FOT/mozjpeg-clang/jmemmgr.c:477:28
    #4 0x524fea in start_input_bmp /home/hongxu/FOT/mozjpeg-clang/rdbmp.c:401:24
    #5 0x514059 in main /home/hongxu/FOT/mozjpeg-clang/cjpeg.c:753:3
    #6 0x7f66c720bb96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/hongxu/FOT/mozjpeg-clang/rdbmp.c:145:17 in get_8bit_row
Shadow bytes around the buggy address:
  0x0c1a7fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c1a7fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c1a7fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c1a7fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c1a7fff8000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
=>0x0c1a7fff8010: 00 00 00 00 00 00 00 00 07 fa[fa]fa fa fa fa fa
  0x0c1a7fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c1a7fff8060: 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
==6549==ABORTING
```


Comments:
Comment by kornelski on 2018-07-20 12:06:42+00:00:
Does this affect libjpeg-turbo as well?

---

Comment by hongxuchen on 2018-07-20 13:10:34+00:00:
@kornelski libjpeg-turbo seems affected (corresponding lines are 209 and 211, https://github.com/libjpeg-turbo/libjpeg-turbo/blob/master/rdbmp.c).

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 0fa7850aeb273204acd57be11f328b2be5d97dc6
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;
    }

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

    tjDestroy(jpegDecompressor);

    return 0;
}