Project: libraw (libraw/libraw), language: c++
Vulnerability instance: libraw.cve-2018-20365
Sanitizer: address

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/LibRaw/LibRaw/issues/195
## Description:
Issue: LibRaw/LibRaw#195
Title: It exists heap-buffer-overflow when use function raw2image()
State: closed
Created by: fantasyoung
Created at: 2018-12-21 03:48:38+00:00

Issue Body:
### Description
It exists heap-buffer-overflow in LibRaw::raw2image() src/libraw_cxx.cpp:3423
### My test program
4channels in Libraw/bin
### Command and argument
./4channels 4channels_crash
### Crash Information
The output of exampletest with address sanitizer enabled
```
==98918==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62800000b900 at pc 0x7f498eedbe62 bp 0x7fff93fa5040 sp 0x7fff93fa47e8
WRITE of size 208 at 0x62800000b900 thread T0
    #0 0x7f498eedbe61 in __asan_memmove (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x8ce61)
    #1 0x42aae0 in LibRaw::raw2image() src/libraw_cxx.cpp:3423
    #2 0x404824 in main samples/4channels.cpp:110
    #3 0x7f498db6c82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #4 0x403df8 in _start (/home/wind/libraw_fuzz_new/as_libraw_7e29b/LibRaw-7e29b9f29449fde30cc878fbb137d61c14bba3a4/bin/4channels+0x403df8)

0x62800000b900 is located 0 bytes to the right of 14336-byte region [0x628000008100,0x62800000b900)
allocated by thread T0 here:
    #0 0x7f498eee779a in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x9879a)
    #1 0x455d8f in libraw_memmgr::calloc(unsigned long, unsigned long) libraw/libraw_alloc.h:56
    #2 0x410458 in LibRaw::calloc(unsigned long, unsigned long) src/libraw_cxx.cpp:557
    #3 0x429b34 in LibRaw::raw2image() src/libraw_cxx.cpp:3369
    #4 0x404824 in main samples/4channels.cpp:110
    #5 0x7f498db6c82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

SUMMARY: AddressSanitizer: heap-buffer-overflow ??:0 __asan_memmove
Shadow bytes around the buggy address:
  0x0c507fff96d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c507fff96e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c507fff96f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c507fff9700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c507fff9710: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c507fff9720:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c507fff9730: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c507fff9740: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c507fff9750: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c507fff9760: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c507fff9770: 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
==98918==ABORTING

```
### Version
the commit is 7e29b9f29449fde30cc878fbb137d61c14bba3a4
### POC File
[crash.zip](https://github.com/LibRaw/LibRaw/files/2701429/crash.zip)
### CREDIT
pu!m,Weiran Labs




Comments:
Comment by LibRaw on 2018-12-21 04:16:57+00:00:
OK, for strange reason I see only partial patch (previous one) in raw2image, will revisit github copy today.

---

Comment by carnil on 2018-12-22 20:24:01+00:00:
This is CVE-2018-20365

---

Comment by LibRaw on 2018-12-24 05:46:10+00:00:
CVE-2018-20363, CVE-2018-20364, CVE-2018-20365 - all three are assigned for the same problem

---

Comment by carnil on 2018-12-24 12:43:13+00:00:
Hi

On Sun, Dec 23, 2018 at 09:46:11PM -0800, LibRaw LLC wrote:
> CVE-2018-20363, CVE-2018-20364, CVE-2018-20365 - all three are
> assigned for the same problem

I'm just the messenger of the CVE while investigating some CVEs.

I noticed that MITRE has assigned the following set:

CVE-2018-20363:
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-20363
- https://github.com/LibRaw/LibRaw/issues/193

CVE-2018-20364:
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-20364
- https://github.com/LibRaw/LibRaw/issues/194

CVE-2018-20365:
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-20365
- https://github.com/LibRaw/LibRaw/issues/195

Do you mean the underlying issue of all those is the same and is the
once covered by #195?

Thanks already for your help and clarification to pin point the
issues.



---

Comment by LibRaw on 2018-12-24 12:54:16+00:00:
I see single problem: due to inconsistency in Sinar 4-shot files handling (introduced in current development branch), it is possible to read full-color data in one place, while try to read single-color data in another.
This requires two similar fixes in raw2image() and raw2image_ex() calls.
Because of my inattention, there are two separate patches for each fix (and both patches was reworked today).

Please note
 1) LibRaw 0.19 (stable) seems to not be affected by this specific problem because there is no Sinar 4-shot handling in this version. So, only development branch looks affected.
 2) however, the fix was backported to 0.19-branch to prevent similar problems (if any).

Also, in https://github.com/LibRaw/LibRaw/issues/193 discussion I see traces of some another problem, but I do not have POC (and I'm not sure that reporter has recompiled LibRaw after git pull).

Right now I assume that sinar-4-shot related case (all three CVEs) is resolved.

---

Comment by carnil on 2018-12-24 14:45:40+00:00:
thanks for the detailed reply. With `0.19.1` (currently in Debian unstable) I see for the case of #193 reproducer:

```
Starting program: /usr/lib/libraw/4channels /home/build/0000
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Processing file /home/build/0000

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7f4b2a0 in LibRaw::raw2image (this=this@entry=0x7ffffff74730)
    at src/libraw_cxx.cpp:3229
3229                imgdata.image[((row) >> IO.shrink) * S.iwidth + ((col) >> IO.shrink)][fcol(row, col)] =
(gdb) bt
#0  0x00007ffff7f4b2a0 in LibRaw::raw2image (this=this@entry=0x7ffffff74730)
    at src/libraw_cxx.cpp:3229
#1  0x000055555555529f in main (ac=2, av=0x7fffffffebd8) at samples/4channels.cpp:110
(gdb) list
3224          else
3225          {
3226            int row, col;
3227            for (row = 0; row < S.height; row++)
3228              for (col = 0; col < S.width; col++)
3229                imgdata.image[((row) >> IO.shrink) * S.iwidth + ((col) >> IO.shrink)][fcol(row, col)] =
3230                    imgdata.rawdata.raw_image[(row + S.top_margin) * S.raw_pitch / 2 + (col + S.left_margin)];
3231          }
3232        }
3233        else // if(decoder_info.decoder_flags & LIBRAW_DECODER_LEGACY)
(gdb)
```

---

Comment by LibRaw on 2018-12-24 15:01:40+00:00:
This sample is refused under windows (my primary dev. env), as it should.

Anyway, master-branch fix is backported to 0.19.2, so 0.19.2 should process it safely (tested w/ FreeBSD, sorry no Linux here).

---

Comment by pgajdos on 2019-01-08 20:25:09+00:00:
Apologize, what commit actually is supposed to fix this issue?

With 0.19.2 I get for given testcase:
```
(gdb) run
Starting program: /usr/bin/4channels 4channels_crash
Processing file 4channels_crash
=================================================================
==25914==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x628000003900 at pc 0x7ffff704976e bp 0x7ffffff740b0 sp 0x7ffffff73860
WRITE of size 208 at 0x628000003900 thread T0
    #0 0x7ffff704976d in __interceptor_memmove (/usr/lib64/libasan.so.5+0x3a76d)
    #1 0x7ffff6f1f7b1 in LibRaw::raw2image() (/usr/lib64/libraw.so.19+0x1cc7b1)
    #2 0x401ea7  (/usr/bin/4channels+0x401ea7)
    #3 0x7ffff69b5fea in __libc_start_main (/lib64/libc.so.6+0x22fea)
    #4 0x401249  (/usr/bin/4channels+0x401249)

0x628000003900 is located 0 bytes to the right of 14336-byte region [0x628000000100,0x628000003900)
allocated by thread T0 here:
    #0 0x7ffff70fb0b8 in calloc (/usr/lib64/libasan.so.5+0xec0b8)
    #1 0x7ffff6f4d565 in libraw_memmgr::calloc(unsigned long, unsigned long) (/usr/lib64/libraw.so.19+0x1fa565)
    #2 0x7ffff6f0351a in LibRaw::calloc(unsigned long, unsigned long) (/usr/lib64/libraw.so.19+0x1b051a)
    #3 0x7ffff6f1e519 in LibRaw::raw2image() (/usr/lib64/libraw.so.19+0x1cb519)
    #4 0x401ea7  (/usr/bin/4channels+0x401ea7)
    #5 0x7ffff69b5fea in __libc_start_main (/lib64/libc.so.6+0x22fea)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/usr/lib64/libasan.so.5+0x3a76d) in __interceptor_memmove
Shadow bytes around the buggy address:
  0x0c507fff86d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c507fff86e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c507fff86f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c507fff8700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c507fff8710: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c507fff8720:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c507fff8730: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c507fff8740: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c507fff8750: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c507fff8760: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c507fff8770: 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
==25914==ABORTING

Program received signal SIGABRT, Aborted.
0x00007ffff69cb08b in raise () from /lib64/libc.so.6
(gdb) bt
#0  0x00007ffff69cb08b in raise () from /lib64/libc.so.6
#1  0x00007ffff69b44e9 in abort () from /lib64/libc.so.6
#2  0x00007ffff711835b in ?? () from /usr/lib64/libasan.so.5
#3  0x00007ffff71203e8 in ?? () from /usr/lib64/libasan.so.5
#4  0x00007ffff710555d in ?? () from /usr/lib64/libasan.so.5
#5  0x00007ffff7049793 in memmove () from /usr/lib64/libasan.so.5
#6  0x00007ffff6f1f7b2 in LibRaw::raw2image (this=0x7ffffff74320) at src/libraw_cxx.cpp:3242
#7  0x0000000000401ea8 in main (ac=2, av=0x7fffffffe848) at samples/4channels.cpp:110
(gdb) frame 6
#6  0x00007ffff6f1f7b2 in LibRaw::raw2image (this=0x7ffffff74320) at src/libraw_cxx.cpp:3242
3242	            memmove(&imgdata.image[row * S.width],
(gdb) l
3237	        if (S.width * 8 == S.raw_pitch)
3238	          memmove(imgdata.image, imgdata.rawdata.color4_image, S.width * S.height * sizeof(*imgdata.image));
3239	        else
3240	        {
3241	          for (int row = 0; row < S.height; row++)
3242	            memmove(&imgdata.image[row * S.width],
3243	                    &imgdata.rawdata.color4_image[(row + S.top_margin) * S.raw_pitch / 8 + S.left_margin],
3244	                    S.width * sizeof(*imgdata.image));
3245	        }
3246
(gdb)
```

---

Comment by LibRaw on 2019-01-09 06:19:30+00:00:
OK, got it.
It  is another problem, but from same POC: it is possible to trick raw2image/raw2image_ex to do half-size allocation (and than buffer overrun) even for full-color input data for Sinar 4-shot files.

---

Comment by LibRaw on 2019-01-10 06:48:35+00:00:
This patch should fix it: https://github.com/LibRaw/LibRaw/commit/a7c17cb6bbec1e79f058d84511f9c3b142cbdfa7

I do not consider this problem as serious as the original one, because it affects only half_size=1 case.

---

Comment by pgajdos on 2019-01-10 09:13:18+00:00:
This patch on top of 0.19.2 fixes the issue.
Thanks for your fast response!

Attachments:
https://github.com/LibRaw/LibRaw/files/2701429/crash.zip

Commit References:
7e29b9f29449fde30cc878fbb137d61c14bba3a4
a7c17cb6bbec1e79f058d84511f9c3b142cbdfa7

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
./configure --disable-examples
make -j$(nproc)

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y make autoconf automake libtool pkg-config
RUN git clone https://github.com/libraw/libraw libraw
RUN git -C libraw checkout e12cae8cbc7c73a7200f6e7621d71e113885ea72
WORKDIR $SRC/libraw
COPY build.sh $SRC/

Additional files:
filename: libraw_fuzzer.cc
content: /*  Copyright 2020 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 <stddef.h>
#include <stdint.h>

#include <string>

#include <libraw.h>

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  // Input less than 10mb
  if (size > 10000000) {
    return 0;
  }

  LibRaw lib_raw;

  int result = lib_raw.open_buffer(
      const_cast<char*>(reinterpret_cast<const char*>(data)), size);
  if (result != LIBRAW_SUCCESS) {
    return 0;
  }

  result = lib_raw.unpack();
  if (result != LIBRAW_SUCCESS) {
    return 0;
  }

  result = lib_raw.dcraw_process();
  if (result != LIBRAW_SUCCESS) {
    return 0;
  }

  return 0;
}