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

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/libgd/libgd/issues/211
## Description:
Issue: libgd/libgd#211
Title: gdCtxPrintf vsnprintf return value not checked - leaks stack memory
State: closed
Created by: fmunozs
Created at: 2016-05-13 05:35:49+00:00
Labels: bug

Issue Body:
## Description:

See reproduction test case, length from the failed vsnprintf attempt [1] to copy more than 8000 chars on a 4096 buffer, vsnprintf [2] "a return value of size or more means that the output was truncated", however libgd returns this length as is and PHP prints more information from memory than it should.

Libgd isn't checking the vsnprintf return value and PHP 5.5 will print the length specified, leaking memory data.

```
/* {{{ gdCtxPrintf */
static void gdCtxPrintf(gdIOCtx * out, const char *format, ...)
{
    char buf[4096];
    int len;
    va_list args;

    va_start(args, format);
    len = vsnprintf(buf, sizeof(buf)-1, format, args); 
     // if len > 4096 data was truncated
     // but libgd returns this value as is 
    va_end(args);
    out->putBuf(out, buf, len);
}
```

This was reported to PHP 

https://bugs.php.net/bug.php?id=72115

Compile PHP 5.5 with ASAN. 

BP on https://github.com/php/php-src/blob/PHP-5.5/ext/gd/gd_ctx.c#L39

```
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/user/php/php-55/sapi/cli/php -n -dextension=/home/user/php/php-55/modules/gd.so /home/user/img.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".

Breakpoint 1, _php_image_output_putbuf (ctx=0xb46ddf38, buf=0xbfffa69c, l=8017) at /home/user/php/php-55/ext/gd/gd_ctx.c:39
39              return php_write((void *)buf, l TSRMLS_CC);
(gdb) print l
$7 = 8017
```

[1] https://github.com/libgd/libgd/blob/master/src/gd_xbm.c#L188
[2] http://linux.die.net/man/3/vsnprintf /
## Test script:

```
<?php
$var1=imagecreatetruecolor ( 2 , 2);
$var2=str_repeat("ABCD", 1030);
$var3=0;
imagexbm($var1, $var2, $var3);
```
## Actual result:

```
#define ABCDAB... <random stuff from memory> ...
=================================================================                                                                                                              
==3897==ERROR: AddressSanitizer: stack-buffer-underflow on address 0xbfffb750 at pc 0xb7aa6dbd bp 0xbfffa408 sp 0xbfff9fdc                                                                                 
READ of size 8017 at 0xbfffb750 thread T0                                                                                                                                                                  
    #0 0xb7aa6dbc  (/usr/lib/i386-linux-gnu/libasan.so.2+0x3ddbc)                                                                                                                                          
    #1 0x99388cf in sapi_cli_single_write /home/user/php/php-55/sapi/cli/php_cli.c:273                                                                                                                     
    #2 0x9938a01 in sapi_cli_ub_write /home/user/php/php-55/sapi/cli/php_cli.c:308                                                                                                                         
    #3 0x920f82f in php_output_op /home/user/php/php-55/main/output.c:1094                                                                                                                                 
    #4 0x920f82f in php_output_write /home/user/php/php-55/main/output.c:270       
    #5 0x919debb in php_write /home/user/php/php-55/main/main.c:671                                                                                                                                        
    #6 0xb44b1a3b in _php_image_output_putbuf /home/user/php/php-55/ext/gd/gd_ctx.c:39                                                                                                                     
    #7 0xb44638ba  (/usr/lib/i386-linux-gnu/libgd.so.3+0x318ba)                                                                                                                                            
    #8 0xb4463ddf in gdImageXbmCtx (/usr/lib/i386-linux-gnu/libgd.so.3+0x31ddf)                                                                                                                            
    #9 0xb44e0a2e in _php_image_output_ctx /home/user/php/php-55/ext/gd/gd_ctx.c:187                                                                                                                           
    #10 0xb44e0a2e in zif_imagexbm /home/user/php/php-55/ext/gd/gd.c:2702
    #11 0x992dc59 in zend_do_fcall_common_helper_SPEC /home/user/php/php-55/Zend/zend_vm_execute.h:550
    #12 0x96854cf in execute_ex /home/user/php/php-55/Zend/zend_vm_execute.h:363
    #13 0x99225d6 in zend_execute /home/user/php/php-55/Zend/zend_vm_execute.h:388
    #14 0x9472ed1 in zend_execute_scripts /home/user/php/php-55/Zend/zend.c:1327
    #15 0x91a7e7c in php_execute_script /home/user/php/php-55/main/main.c:2525
    #16 0x99379c4 in do_cli /home/user/php/php-55/sapi/cli/php_cli.c:994
    #17 0x808a06c in main /home/user/php/php-55/sapi/cli/php_cli.c:1378
    #18 0xb764c636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)
    #19 0x808a78a  (/home/user/php/php-55/sapi/cli/php+0x808a78a)

Address 0xbfffb750 is located in stack of thread T0 at offset 0 in frame
    #0 0xb44dfe0f in zif_imagexbm /home/user/php/php-55/ext/gd/gd.c:2701
```



Comments:
Comment by vapier on 2016-05-13 14:04:30+00:00:
we probably should extend the IO layer to accept a va_list rather than go through a local buffer.  then we can just pass it down directly w/out any stack allocation.


---

Comment by fmunozs on 2016-05-27 01:44:44+00:00:
Hello, will this get a CVE assigned? Thanks.


---

Comment by vapier on 2016-05-27 04:07:56+00:00:
i don't care much about CVE's.  just upgrade to the latest version and be done.


---

Comment by kaplanlior on 2016-07-07 16:37:18+00:00:
CVE-2016-5116 at http://seclists.org/oss-sec/2016/q2/430


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