Project: libgd (libgd/libgd), language: c++
Vulnerability instance: libgd.cve-2017-6363
Sanitizer: address

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/libgd/libgd/issues/383
## Description:
Issue: libgd/libgd#383
Title: Invalid read when call gdImageTiffPtr (CVE-2017-6363)
State: closed
Created by: varsleak
Created at: 2017-02-17 16:51:11+00:00
Labels: bug

Issue Body:
Description
========
Hi, when I fuzz the libgd, a invalid read occurs within the function tiffWriter of gd_tiff.c, it can be triggered by the 
[gdfile.txt](https://github.com/libgd/libgd/files/783796/gdfile.txt)

Valgrind tracker
========
```
➜  Bin git:(master) ✗ valgrind --leak-check=yes ./test_gd2_bug00209 ../../ddms/Bin/gdfile.gd  
==31702== Memcheck, a memory error detector
==31702== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==31702== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==31702== Command: ./test_gd2_bug00209 ../../ddms/Bin/gdfile.gd
==31702== 
==31702== Invalid read of size 4
==31702==    at 0x4E6F318: tiffWriter (gd_tiff.c:267)
==31702==    by 0x4E6FD24: gdImageTiffCtx (gd_tiff.c:446)
==31702==    by 0x4E712DF: gdImageTiffPtr (gd_tiff.c:1067)
==31702==    by 0x40158F: main (bug00209.c:36)
==31702==  Address 0x8177bdc is 249,468 bytes inside an unallocated block of size 4,104,832 in arena "client"
==31702== 
==31702== Invalid read of size 4
==31702==    at 0x4E6F365: tiffWriter (gd_tiff.c:268)
==31702==    by 0x4E6FD24: gdImageTiffCtx (gd_tiff.c:446)
==31702==    by 0x4E712DF: gdImageTiffPtr (gd_tiff.c:1067)
==31702==    by 0x40158F: main (bug00209.c:36)
==31702==  Address 0x8177fdc is 250,492 bytes inside an unallocated block of size 4,104,832 in arena "client"
==31702== 
==31702== Invalid read of size 4
==31702==    at 0x4E6F3AD: tiffWriter (gd_tiff.c:269)
==31702==    by 0x4E6FD24: gdImageTiffCtx (gd_tiff.c:446)
==31702==    by 0x4E712DF: gdImageTiffPtr (gd_tiff.c:1067)
==31702==    by 0x40158F: main (bug00209.c:36)
==31702==  Address 0x81783dc is 251,516 bytes inside an unallocated block of size 4,104,832 in arena "client"
==31702== 
==31702== 
==31702== HEAP SUMMARY:
==31702==     in use at exit: 72,704 bytes in 1 blocks
```



Comments:
Comment by vapier on 2017-02-17 17:05:01+00:00:
please post all code you're using to test things

---

Comment by varsleak on 2017-02-18 01:19:26+00:00:
```
int main(int argc, char * argv[])
{
    gdImagePtr im = 0;
    FILE *fp = 0;
    void * im2 = 0;
    int size = 0;

    if (argc != 2) return -1;

    fp = fopen(argv[1], "rb");
    if (fp){
	    im = gdImageCreateFromGd(fp);

	    if (im){
	    	im2 = gdImageTiffPtr(im, &size);

	    	if (im2){
	    		gdFree(im2);
	    	}
	    	gdImageDestroy(im);
		}
	    
	}

    fclose(fp);

    return gdNumFailures();
}
```

The other [image](https://github.com/libgd/libgd/files/784688/heap-buffer-overflow.txt) lead to heap-buffer-overflow.May be the same mistake.

The ASAN crash log:
```
➜  Bin git:(master) ✗ ./test_gd2_bug00209 heap-overflow.gd         
=================================================================
==8350==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x624000015bc4 at pc 0x7f4ed7593905 bp 0x7ffeb6df2f50 sp 0x7ffeb6df2f40
READ of size 4 at 0x624000015bc4 thread T0
    #0 0x7f4ed7593904 in tiffWriter /home/xrym/libgd/libgd.bak/src/gd_tiff.c:267
    #1 0x7f4ed75951d0 in gdImageTiffCtx /home/xrym/libgd/libgd.bak/src/gd_tiff.c:446
    #2 0x7f4ed7597a97 in gdImageTiffPtr /home/xrym/libgd/libgd.bak/src/gd_tiff.c:1067
    #3 0x401aca in main /home/xrym/libgd/libgd.bak/tests/gd2/bug00209.c:36
    #4 0x7f4ed716f82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #5 0x4018a8 in _start (/home/xrym/libgd/ddms/Bin/test_gd2_bug00209+0x4018a8)

AddressSanitizer can not describe address in more detail (wild memory access suspected).
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/xrym/libgd/libgd.bak/src/gd_tiff.c:267 tiffWriter
Shadow bytes around the buggy address:
  0x0c487fffab20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c487fffab30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c487fffab40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c487fffab50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c487fffab60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c487fffab70: fa fa fa fa fa fa fa fa[fa]fa fa fa fa fa fa fa
  0x0c487fffab80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c487fffab90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c487fffaba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c487fffabb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c487fffabc0: 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
==8350==ABORTING
```

---

Comment by varsleak on 2017-02-28 06:45:24+00:00:
CVE-2017-6363 was assigned.

---

Comment by vapier on 2018-01-31 19:55:39+00:00:
the gd image readers should have clamped the transparent index to a valid range.  i imagine you'd get a similar error if you tried to output to other image formats as we don't do bounds checking at output time (as we assume the inputs were correct to begin with).

i fixed the issue in the gd/gd2 image readers.

---

Comment by cmb69 on 2018-02-03 18:01:49+00:00:
In my opinion this issue should not have a CVE, since the GD and GD2 formats are documented to be "obsolete, and should only be used for development and testing purposes."

---

Comment by vapier on 2018-02-03 18:27:38+00:00:
it's too late at this point ;).  but regardless of our opinion on the formats, if they're available by default (and they have been), it means people using gd to accept arbitrary inputs from people (like php) are affected.

---

Comment by cmb69 on 2018-02-04 15:49:30+00:00:
Well, wrt. PHP the CVE is most likely irrelevant. Firstly, PHP does not have TIFF support (and rather likely the CVE is about this), and secondly, neither GIF, GD(2) nor PNG writing would exhibit a direct vulnerability – the GIF writer [just writes the byte](https://github.com/libgd/libgd/blob/gd-2.2.5/src/gd_gif_out.c#L1126), the GD(2) writer [also does this](https://github.com/libgd/libgd/blob/gd-2.2.5/src/gd_gd.c#L319), while the PNG writer already [caters to out-of-bounds values](https://github.com/libgd/libgd/blob/gd-2.2.5/src/gd_png.c#L842). The TIFF writer, however, would [cause an invalid read](https://github.com/libgd/libgd/blob/gd-2.2.5/src/gd_tiff.c#L264-L270). The other writers appear to be agnostic to the transparent color.

Generally, I agree, though – we can't know what users of libgd are doing.

Attachments:
https://github.com/libgd/libgd/files/783796/gdfile.txt
https://github.com/libgd/libgd/files/784688/heap-buffer-overflow.txt

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
./bootstrap.sh
./configure --prefix="$WORK" --disable-shared
make -j$(nproc) install

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

Additional files:
filename: parser_target.cc
content: // Copyright 2018 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 "gd.h"

#define PASTE(x) gdImageCreateFrom ## x ## Ptr
#define CREATE_IMAGE(FORMAT) PASTE(FORMAT)

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
    gdImagePtr im = CREATE_IMAGE(FUZZ_GD_FORMAT)(Size, (void*) Data);
    if (im) gdImageDestroy(im);
    return 0;
}