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

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/LibRaw/LibRaw/issues/192
## Description:
Issue: LibRaw/LibRaw#192
Title: Stack-buffer-overflow bug
State: closed
Created by: DawnYang-cn
Created at: 2018-12-19 02:36:42+00:00

Issue Body:
Hello!
I am learning AFL-Fuzz recently,and I found a bug in this project.
POC is [here](https://github.com/DawnYang-cn/Fuzz-crashes/blob/master/LibRaw_crashes_1)
Please confirm
Best regards
### Version
release 0.19.1
### Environment
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609
disable-shared
./raw-identify POC 
### Information
=================================================================
==95677==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffdcba9ac0 at pc 0x7f04239a06c3 bp 0x7fffdcba9020 sp 0x7fffdcba87c8
WRITE of size 45 at 0x7fffdcba9ac0 thread T0
    #0 0x7f04239a06c2 in __interceptor_strncpy (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x766c2)
    #1 0x487e28 in LibRaw::parse_makernote(int, int) internal/dcraw_common.cpp:10349
    #2 0x499188 in LibRaw::parse_exif(int) internal/dcraw_common.cpp:11857
    #3 0x4a9da2 in LibRaw::parse_tiff_ifd(int) internal/dcraw_common.cpp:13262
    #4 0x4b5af2 in LibRaw::parse_tiff(int) internal/dcraw_common.cpp:14080
    #5 0x4ce14f in LibRaw::identify() internal/dcraw_common.cpp:17781
    #6 0x50e4c7 in LibRaw::open_datastream(LibRaw_abstract_datastream*) src/libraw_cxx.cpp:2014
    #7 0x507894 in LibRaw::open_file(char const*, long long) src/libraw_cxx.cpp:1052
    #8 0x404c16 in main samples/raw-identify.cpp:136
    #9 0x7f04223f082f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #10 0x4040f8 in _start (/home/dawn/Libraw-asan/LibRaw-0.19.1/bin/raw-identify+0x4040f8)

Address 0x7fffdcba9ac0 is located in stack of thread T0 at offset 2448 in frame
    #0 0x48584d in LibRaw::parse_makernote(int, int) internal/dcraw_common.cpp:10091

  This frame has 43 object(s):
    [32, 33) 'uc'
    [96, 97) 'uc'
    [160, 162) 'table_buf_0x0116_len'
    [224, 226) 'table_buf_0x2010_len'
    [288, 290) 'table_buf_0x9050_len'
    [352, 354) 'table_buf_0x9400_len'
    [416, 418) 'table_buf_0x9402_len'
    [480, 482) 'table_buf_0x9403_len'
    [544, 546) 'table_buf_0x9406_len'
    [608, 610) 'table_buf_0x940c_len'
    [672, 674) 'table_buf_0x940e_len'
    [736, 740) 'tag'
    [800, 804) 'type'
    [864, 868) 'len'
    [928, 932) 'save'
    [992, 996) 'c'
    [1056, 1064) 'table_buf_0x0116'
    [1120, 1128) 'table_buf_0x2010'
    [1184, 1192) 'table_buf_0x9050'
    [1248, 1256) 'table_buf_0x9400'
    [1312, 1320) 'table_buf_0x9402'
    [1376, 1384) 'table_buf_0x9403'
    [1440, 1448) 'table_buf_0x9406'
    [1504, 1512) 'table_buf_0x940c'
    [1568, 1576) 'table_buf_0x940e'
    [1632, 1648) 'wb'
    [1696, 1712) 'wb'
    [1760, 1784) 'oly_lensid'
    [1824, 1856) 'words'
    [1888, 1932) 'SamsungKey'
    [1984, 1986) 'yy'
    [2048, 2051) 'mm'
    [2112, 2115) 'dd'
    [2176, 2184) 'sOlyID'
    [2240, 2249) 'buffer'
    [2304, 2314) 'buf'
    [2368, 2384) 'ystr'
    [2432, 2448) 'ynum' <== Memory access at offset 2448 overflows this variable
    [2496, 2513) 'buffer'
    [2560, 2580) 'LensInfo'
    [2624, 2688) 'FujiSerial'
    [2720, 2784) 'tbuf'
    [2816, 3140) 'buf97'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow ??:0 __interceptor_strncpy
Shadow bytes around the buggy address:
  0x10007b96d300: f2 f2 00 00 00 f4 f2 f2 f2 f2 00 00 00 00 f2 f2
  0x10007b96d310: f2 f2 00 00 00 00 00 04 f4 f4 f2 f2 f2 f2 02 f4
  0x10007b96d320: f4 f4 f2 f2 f2 f2 03 f4 f4 f4 f2 f2 f2 f2 03 f4
  0x10007b96d330: f4 f4 f2 f2 f2 f2 00 f4 f4 f4 f2 f2 f2 f2 00 01
  0x10007b96d340: f4 f4 f2 f2 f2 f2 00 02 f4 f4 f2 f2 f2 f2 00 00
=>0x10007b96d350: f4 f4 f2 f2 f2 f2 00 00[f4]f4 f2 f2 f2 f2 00 00
  0x10007b96d360: 01 f4 f2 f2 f2 f2 00 00 04 f4 f2 f2 f2 f2 00 00
  0x10007b96d370: 00 00 00 00 00 00 f2 f2 f2 f2 00 00 00 00 00 00
  0x10007b96d380: 00 00 f2 f2 f2 f2 00 00 00 00 00 00 00 00 00 00
  0x10007b96d390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007b96d3a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 f4
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
==95677==ABORTING

WRLAB


Comments:
Comment by LibRaw on 2018-12-19 08:02:26+00:00:
Could you please make sure you've tested with LibRaw 0.19.1 (exactly)?
The PoC you provide does not traces to parse_makernote() call, it refuses earlier (checked under Windows/64 bit).

Meanwhile, ynum_len check is definitely needed in code.

---

Comment by LibRaw on 2018-12-19 08:19:07+00:00:
Should be fixed by these patches:
0.19: https://github.com/LibRaw/LibRaw/commit/fbf60377c006eaea8d3eca3f5e4c654909dcdfd2
master: https://github.com/LibRaw/LibRaw/commit/b957c2efb6c67c057650cdf03b435dc0cc78c516

Please check and report if it is not

---

Comment by DawnYang-cn on 2018-12-19 08:27:23+00:00:
Oh,I downloaded this project in the official website yesterday.
Now I used the master branch and the asan show information blow.
My fault 
```
=================================================================
==22081==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffcca14d3b0 at pc 0x7f10cd88d6c3 bp 0x7ffcca14d1b0 sp 0x7ffcca14c958
WRITE of size 45 at 0x7ffcca14d3b0 thread T0
    #0 0x7f10cd88d6c2 in __interceptor_strncpy (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x766c2)
    #1 0x482a4b in LibRaw::parseFujiMakernotes(unsigned int, unsigned int, unsigned int, unsigned int) internal/dcraw_common.cpp:9585
    #2 0x49c8e5 in LibRaw::parse_makernote(int, int) internal/dcraw_common.cpp:11901
    #3 0x4a4962 in LibRaw::parse_exif(int) internal/dcraw_common.cpp:12563
    #4 0x4b2209 in LibRaw::parse_tiff_ifd(int) internal/dcraw_common.cpp:13772
    #5 0x4bc9a0 in LibRaw::parse_tiff(int) internal/dcraw_common.cpp:14505
    #6 0x4d61dd in LibRaw::identify() internal/dcraw_common.cpp:18365
    #7 0x519533 in LibRaw::open_datastream(LibRaw_abstract_datastream*) src/libraw_cxx.cpp:2112
    #8 0x511c6e in LibRaw::open_file(char const*, long long) src/libraw_cxx.cpp:1099
    #9 0x404c1e in main samples/raw-identify.cpp:142
    #10 0x7f10cc53482f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #11 0x403ed8 in _start (/home/wind/libraw_fuzz_new/as_libraw/LibRaw-master/bin/raw-identify+0x403ed8)

Address 0x7ffcca14d3b0 is located in stack of thread T0 at offset 432 in frame
    #0 0x482467 in LibRaw::parseFujiMakernotes(unsigned int, unsigned int, unsigned int, unsigned int) internal/dcraw_common.cpp:9556

  This frame has 9 object(s):
    [32, 36) 'c'
    [96, 128) 'words'
    [160, 162) 'yy'
    [224, 227) 'mm'
    [288, 291) 'dd'
    [352, 368) 'ystr'
    [416, 432) 'ynum' <== Memory access at offset 432 overflows this variable
    [480, 544) 'FujiSerial'
    [576, 640) 'tbuf'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow ??:0 __interceptor_strncpy
Shadow bytes around the buggy a
```

---

Comment by fgeek on 2018-12-23 05:08:02+00:00:
@DawnYang-cn you might want to quote program output text. See https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code "Blocks of code are either fenced by lines with three back-ticks". Thanks for your efforts!

---

Comment by DawnYang-cn on 2018-12-26 06:43:05+00:00:
I got that! Thank you!
@fgeek 

Commit References:
b957c2efb6c67c057650cdf03b435dc0cc78c516
fbf60377c006eaea8d3eca3f5e4c654909dcdfd2

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