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

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/libgd/libgd/issues/209
## Description:
Issue: libgd/libgd#209
Title: global out of bounds read when encoding gif from malformed input with gd2togif
State: closed
Created by: hannob
Created at: 2016-05-08 12:06:28+00:00
Labels: bug

Issue Body:
The attached file causes a global out of bounds read error in the function output (gd_gif_out.c), called by compress/GifEncode. This was found with the help of american fuzzy lop and address sanitizer.

To test pass the attached file (zip-packed due to github limitations) to gd2togif compiled with address sanitizer.

The full address sanitizer error message:

```
==26159==ERROR: AddressSanitizer: global-buffer-overflow on address 0x00000055e4b0 at pc 0x000000531231 bp 0x7ffc8a6e0610 sp 0x7ffc8a6e0608
READ of size 8 at 0x00000055e4b0 thread T0
    #0 0x531230 in output /f/libgd/libgd/src/gd_gif_out.c:1454:20
    #1 0x52fb4a in compress /f/libgd/libgd/src/gd_gif_out.c:1407:3
    #2 0x52b87a in GIFEncode /f/libgd/libgd/src/gd_gif_out.c:1142:2
    #3 0x52b87a in gdImageGifCtx /f/libgd/libgd/src/gd_gif_out.c:236
    #4 0x52bb13 in gdImageGif /f/libgd/libgd/src/gd_gif_out.c:197:2
    #5 0x4f3cc6 in main /f/libgd/libgd/src/gd2togif.c:40:2
    #6 0x7f2ab391b78f in __libc_start_main /var/tmp/portage/sys-libs/glibc-2.23-r2/work/glibc-2.23/csu/../csu/libc-start.c:289
    #7 0x418fa8 in _start (/mnt/ram/gd/gd2togif+0x418fa8)

0x00000055e4b0 is located 16 bytes to the left of global variable 'masks' defined in 'gd_gif_out.c:1445:22' (0x55e4c0) of size 136
0x00000055e4b0 is located 41 bytes to the right of global variable '<string literal>' defined in 'gd_gif_out.c:1078:29' (0x55e480) of size 7
  '<string literal>' is ascii string 'GIF87a'
SUMMARY: AddressSanitizer: global-buffer-overflow /f/libgd/libgd/src/gd_gif_out.c:1454:20 in output
Shadow bytes around the buggy address:
  0x0000800a3c40: 00 00 f9 f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00
  0x0000800a3c50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800a3c60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800a3c70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800a3c80: 07 f9 f9 f9 f9 f9 f9 f9 00 00 01 f9 f9 f9 f9 f9
=>0x0000800a3c90: 07 f9 f9 f9 f9 f9[f9]f9 00 00 00 00 00 00 00 00
  0x0000800a3ca0: 00 00 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 f9 f9
  0x0000800a3cb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800a3cc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000800a3cd0: 00 00 00 00 07 f9 f9 f9 f9 f9 f9 f9 00 00 00 00
  0x0000800a3ce0: 00 00 00 00 00 00 00 00 f9 f9 f9 f9 00 00 00 00
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
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==26159==ABORTING
```

[libgd-global-oob-GIFEncode.zip](https://github.com/libgd/libgd/files/253896/libgd-global-oob-GIFEncode.zip)



Comments:
Comment by pierrejoye on 2016-07-19 07:02:03+00:00:
@vapier Please add a test case :)


---

Comment by cmb69 on 2016-07-19 08:50:01+00:00:
I've added a test case in PR #265, but the test takes "forever".


---

Comment by pierrejoye on 2016-07-19 09:08:50+00:00:
Oh was much faster here. So let close again this issue. :/ thanks!


---

Comment by cmb69 on 2016-07-19 09:21:09+00:00:
> Oh was much faster here.

Do you mean that the test ran much faster, or that you were faster to submit another test case. If the former, please leave that ticket open, because I feel that there is something wrong with reading the GD2 image (that should only take some ms on a slow machine). I'll have a look at it ASAP.


---

Comment by pierrejoye on 2016-07-19 09:26:22+00:00:
test runs way faster here. But not critical to have in 2.2.3


---

Comment by un-fmunozs on 2016-07-25 18:54:03+00:00:
Maybe a test case based on this https://bugs.php.net/bug.php?id=72519 will be faster?


---

Comment by cmb69 on 2017-01-23 19:12:35+00:00:
> […] because I feel that there is something wrong with reading the GD2 image […]

Indeed, there was something wrong, namely a DOS vulnerability, which has been fixed with c6bb583c (available as of GD 2.2.4). I'm going to add a regression test for the submitted image. Presumably, the fixes in gd_gif_out.c are not strictly necessary, but they're adding a second safety net.



Attachments:
https://github.com/libgd/libgd/files/253896/libgd-global-oob-GIFEncode.zip

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