Bug #69295 [Ver]: segfault w/ memory corruption in _efree() on unserialize
| From: | cmb@php.net | Date: | Mon, 08 Aug 2016 15:27:30 +0000 |
| Subject: | Bug #69295 [Ver]: segfault w/ memory corruption in _efree() on unserialize | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-203085@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=69295&edit=1
ID: 69295
Updated by: cmb@php.net
Reported by: brian dot carpenter at gmail dot com
Summary: segfault w/ memory corruption in _efree() on
unserialize
Status: Verified
Type: Bug
Package: Reproducible crash
Operating System: Debian 7
PHP Version: PHP-7
Block user comment: N
Private report: N
New Comment:
I can reproduce invalid reads/writes (apparently NULL pointer
derefs) with current PHP-5.6 and master (didn't check other
versions) with Anatol's test script (the original isn't available
anymore; I had to concatenate the strings in Anatol's script to
make it work). However, valgrind doesn't report an unrecognised
instruction (which might be bogus anyway, as it's possible that
"the instruction is legitimate but Valgrind doesn't handle it").
The following has been produced by running against a debug build
of current master (e20e9c6):
vagrant@debian-8:/vagrant/php-src$ USE_ZEND_ALLOC=0 valgrind -q sapi/cli/php -n
../69295.php
==4581== Invalid write of size 8
==4581== at 0x4C2F467: memset (vg_replace_strmem.c:1094)
==4581== by 0x63F8B1: zend_hash_real_init_ex (zend_hash.c:154)
==4581== by 0x63FB50: zend_hash_real_init (zend_hash.c:203)
==4581== by 0x59000E: php_var_unserialize_ex (var_unserializer.re:716)
==4581== by 0x58EAB1: process_nested_data (var_unserializer.re:372)
==4581== by 0x58EEA0: object_common2 (var_unserializer.re:469)
==4581== by 0x58FD4F: php_var_unserialize_ex (var_unserializer.re:875)
==4581== by 0x58EAB1: process_nested_data (var_unserializer.re:372)
==4581== by 0x58EEA0: object_common2 (var_unserializer.re:469)
==4581== by 0x58FD4F: php_var_unserialize_ex (var_unserializer.re:875)
==4581== by 0x58EAB1: process_nested_data (var_unserializer.re:372)
==4581== by 0x590051: php_var_unserialize_ex (var_unserializer.re:719)
==4581== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==4581==
==4581==
==4581== Process terminating with default action of signal 11 (SIGSEGV)
==4581== Access not within mapped region at address 0x0
==4581== at 0x4C2F467: memset (vg_replace_strmem.c:1094)
==4581== by 0x63F8B1: zend_hash_real_init_ex (zend_hash.c:154)
==4581== by 0x63FB50: zend_hash_real_init (zend_hash.c:203)
==4581== by 0x59000E: php_var_unserialize_ex (var_unserializer.re:716)
==4581== by 0x58EAB1: process_nested_data (var_unserializer.re:372)
==4581== by 0x58EEA0: object_common2 (var_unserializer.re:469)
==4581== by 0x58FD4F: php_var_unserialize_ex (var_unserializer.re:875)
==4581== by 0x58EAB1: process_nested_data (var_unserializer.re:372)
==4581== by 0x58EEA0: object_common2 (var_unserializer.re:469)
==4581== by 0x58FD4F: php_var_unserialize_ex (var_unserializer.re:875)
==4581== by 0x58EAB1: process_nested_data (var_unserializer.re:372)
==4581== by 0x590051: php_var_unserialize_ex (var_unserializer.re:719)
==4581== If you believe this happened as a result of a stack
==4581== overflow in your program's main thread (unlikely but
==4581== possible), you can try to increase the size of the
==4581== main thread stack using the --main-stacksize= flag.
==4581== The main thread stack size used in this run was 8388608.
Segmentation fault
Previous Comments:
------------------------------------------------------------------------
[2015-06-08 20:09:47] stas@php.net
As these seem to be reproducible only in PHP 7, no need to list as security. Also, the second one
seems to be completely different issue, so I'd suggest filing a separate issue.
------------------------------------------------------------------------
[2015-06-08 18:37:30] brian dot carpenter at gmail dot com
I have another test case that causes a similar crash (at least according to the valgrind output).
vex amd64->IR: unhandled instruction bytes: 0xF3 0x4D 0xF 0xBC 0xE4 0x45 0x1 0xC4
==59766== valgrind: Unrecognised instruction at address 0x1319a3a.
==59766== at 0x1319A3A: zend_mm_alloc_pages (zend_alloc.c:483)
==59766== by 0x131B81C: zend_mm_alloc_small_slow (zend_alloc.c:1190)
==59766== by 0x155F573: virtual_cwd_startup (zend_virtual_cwd.c:431)
==59766== by 0x1412DCC: zend_startup (zend.c:640)
==59766== by 0x11C6F98: php_module_startup (main.c:2066)
==59766== by 0x181CFCC: php_cgi_startup (cgi_main.c:915)
==59766== by 0x43B4AC: main (cgi_main.c:1894)
==59766== Your program just tried to execute an instruction that Valgrind
==59766== did not recognise. There are two possible reasons for this.
==59766== 1. Your program has a bug and erroneously jumped to a non-code
==59766== location. If you are running Memcheck and you just saw a
==59766== warning about a bad jump, it's probably your program's fault.
==59766== 2. The instruction is legitimate but Valgrind doesn't handle it,
==59766== i.e. it's Valgrind's fault. If you think this is the case or
==59766== you are not sure, please let us know and we'll try to fix it.
==59766== Either way, Valgrind will now raise a SIGILL signal which will
==59766== probably kill your program.
==59766==
==59766== Process terminating with default action of signal 4 (SIGILL)
==59766== Illegal opcode at address 0x1319A3A
==59766== at 0x1319A3A: zend_mm_alloc_pages (zend_alloc.c:483)
==59766== by 0x131B81C: zend_mm_alloc_small_slow (zend_alloc.c:1190)
==59766== by 0x155F573: virtual_cwd_startup (zend_virtual_cwd.c:431)
==59766== by 0x1412DCC: zend_startup (zend.c:640)
==59766== by 0x11C6F98: php_module_startup (main.c:2066)
==59766== by 0x181CFCC: php_cgi_startup (cgi_main.c:915)
==59766== by 0x43B4AC: main (cgi_main.c:1894)
Illegal instruction
I can't get a stack trace in gdb, all I get is this:
Starting program: /home/geeknik/php-src/sapi/cgi/php-cgi test00-min
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
X-Powered-By: PHP/7.0.0-dev
Content-type: text/html; charset=UTF-8
<br />
<b>Fatal error</b>: Uncaught EngineException: Call to undefined function t() in
/home/geeknik/php-tmp/out/fuzzer04/crashes/test00-min:2
Stack trace:
#0 {main}
thrown in <b>/home/geeknik/php-tmp/out/fuzzer04/crashes/test00-min</b> on line
<b>2</b><br />
[Inferior 1 (process 41113) exited with code 0377]
Hexdump:
0000000 3f3c 6870 0a70 6124 613d 7272 7961 8028
0000010 612e 7272 7961 2928 3b29 2874 3b29
000001e
Test case: https://www.dropbox.com/s/zhelyjjnuw67v39/test00-min?dl=0
------------------------------------------------------------------------
[2015-05-22 09:54:39] kaplan@php.net
Let's start by fixing it for PHP 7? Then we can dig into the 5.5/5.6 reproduction.
------------------------------------------------------------------------
[2015-04-28 05:38:57] stas@php.net
I am still unable to reproduce it anywhere but PHP 7.
------------------------------------------------------------------------
[2015-04-20 00:20:05] brian dot carpenter at gmail dot com
I just rebuilt PHP directly from git source (PHP 7.0.0-dev (cli) (built: Apr 19 2015 19:01:39)) and
this issue is still present, however, the GDB output is a bit different than before:
Reading symbols from /home/geeknik/php-src/sapi/cli/php...done.
gdb-peda$ run test.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 60129542144 bytes)
in /home/geeknik/test.php on line 1
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX: 0x7ffff6000040 --> 0x0
RBX: 0x7ffff605d7e0 --> 0x7ffff6056348 --> 0x8000000100000000
RCX: 0x1
RDX: 0x1e4
RSI: 0x201a00000
RDI: 0x201be48f0
RBP: 0x0
RSP: 0x7fffffffb9b0 --> 0x7ffff6053000 --> 0x0
RIP: 0x134f84e (<_efree+238>: cmp rax,QWORD PTR [rsi])
R8 : 0x0
R9 : 0x20 (' ')
R10: 0x7ffff60555a0 --> 0x7ffff6055500 --> 0x7ffff6055000 --> 0x7ffff6055020 -->
0x7ffff6055460 --> 0x7ffff6055440 --> 0x7ffff6055400 --> 0x7ffff60553e0 -->
0x7ffff60553c0 --> 0x7ffff60553a0 --> 0x7ffff6055380 --> 0x7ffff6055360 -->
0x7ffff6055340 --> 0x7ffff6055320 --> 0x7ffff6055300 --> 0x7ffff60552e0 -->
0x7ffff60552c0 --> 0x7ffff60552a0 --> 0x7ffff6055280 --> 0x7ffff6055260 -->
0x7ffff6055240 --> 0x7ffff6055220 --> 0x7ffff6055200 --> 0x7ffff60551e0 -->
0x7ffff60551c0 --> 0x7ffff60551a0 --> 0x7ffff6055180 --> 0x7ffff6055160 -->
0x7ffff6055140 --> 0x7ffff6055120 --> 0x7ffff6055100 --> 0x7ffff60550e0 -->
0x7ffff60550c0 --> 0x7ffff60550a0 --> 0x7ffff6055080 --> 0x7ffff6055060 -->
0x7ffff6055040 --> 0x7ffff6055420 --> 0x7ffff6055600 --> 0x7ffff6055620 -->
0x7ffff6055640 --> 0x7ffff6055660 --> 0x7ffff6055680 --> 0x7ffff60556a0 -->
0x7ffff60556c0 --> 0x7ffff60556e0 --> 0x7ffff6055700 --> 0x7ffff6055720 -->
0x7ffff6055740 --> 0x7ffff6055760 --> 0x7ffff6055780 --> 0x7ffff60557a0 !
--> 0x7ffff60557c0 --> 0x7ffff60557e0 --> 0x7ffff6055800 --> 0x7ffff6055820 -->
0x7ffff6055840 --> 0x7ffff6055860 --> 0x7ffff6055880 --> 0x7ffff60558a0 -->
0x7ffff60558c0 --> 0x7ffff60558e0 --> 0x7ffff6055900 --> 0x7ffff6055920 -->
0x7ffff6055940 --> 0x7ffff6055960 --> 0x7ffff6055980 --> 0x7ffff60559a0 -->
0x7ffff60559c0 --> 0x7ffff60559e0 --> 0x7ffff6055a00 --> 0x7ffff6055a20 -->
0x7ffff6055a40 --> 0x7ffff6055a60 --> 0x7ffff6055a80 --> 0x7ffff6055aa0 -->
0x7ffff6055ac0 --> 0x7ffff6055ae0 --> 0x7ffff6055b00 --> 0x7ffff6055b20 -->
0x7ffff6055b40 --> 0x7ffff6055b60 --> 0x7ffff6055b80 --> 0x7ffff6055ba0 -->
0x7ffff6055bc0 --> 0x7ffff6055be0 --> 0x7ffff6055c00 --> 0x7ffff6055c20 -->
0x7ffff6055c40 --> 0x7ffff6055c60 --> 0x7ffff6055c80 --> 0x7ffff6055ca0 -->
0x7ffff6055cc0 --> 0x7ffff6055ce0 --> 0x7ffff6055d00 --> 0x7ffff6055d20 -->
0x7ffff6055d40 --> 0x7ffff6055d60 --> 0x7ffff6055d80 --> 0x7ffff6055da0 -->
0x7ffff6055dc0 --> 0x7ffff6055de0 --> 0x7ffff6055e00 --> 0x7ffff6055e20 !
--> 0x7ffff6055e40 --> 0x7ffff6055e60 --> 0x7ffff6055e80 --> 0!
x7ffff6055ea0 --> 0x7ffff6055ec0 --> 0x7ffff6055ee0 --> 0x7ffff6055f00 -->
0x7ffff6055f20 --> 0x7ffff6055f40 --> 0x7ffff6055f60 --> 0x7ffff6055f80 -->
0x7ffff6055fa0 --> 0x7ffff6055fc0 --> 0x7ffff6055fe0 --> 0x0
R11: 0x7ffff605c6b8 --> 0x80800000002
R12: 0x7ffff6056348 --> 0x8000000100000000
R13: 0x0
R14: 0x1
R15: 0x1f6b900 --> 0x18
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x134f840 <_efree+224>: mov rsi,rdi
0x134f843 <_efree+227>: shr rdx,0xc
0x134f847 <_efree+231>: and rsi,0xffffffffffe00000
=> 0x134f84e <_efree+238>: cmp rax,QWORD PTR [rsi]
0x134f851 <_efree+241>: mov ecx,DWORD PTR [rsi+rdx*4+0x1f8]
0x134f858 <_efree+248>: jne 0x134fa90 <_efree+816>
0x134f85e <_efree+254>: xchg ax,ax
0x134f860 <_efree+256>: lea rsp,[rsp-0x98]
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffb9b0 --> 0x7ffff6053000 --> 0x0
0008| 0x7fffffffb9b8 --> 0x41d3eb7ce9929000
0016| 0x7fffffffb9c0 --> 0x0
0024| 0x7fffffffb9c8 --> 0x149b306 (<zend_array_destroy+4246>: xchg ax,ax)
0032| 0x7fffffffb9d0 --> 0x0
0040| 0x7fffffffb9d8 --> 0x41d3eb7ce9929000
0048| 0x7fffffffb9e0 --> 0x14a28e6 (<zend_hash_graceful_reverse_destroy+2038>: )
0056| 0x7fffffffb9e8 --> 0x7ffff605d7e0 --> 0x7ffff6056348 --> 0x8000000100000000
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x000000000134f84e in _efree ()
gdb-peda$ bt
#0 0x000000000134f84e in _efree ()
#1 0x000000000149b306 in zend_array_destroy ()
#2 0x000000000149bed5 in zend_array_destroy ()
#3 0x00000000015a1fdd in zend_object_std_dtor ()
#4 0x00000000015bab22 in zend_objects_store_free_object_storage ()
#5 0x00000000013be403 in shutdown_executor ()
#6 0x000000000142a4a8 in zend_deactivate ()
#7 0x00000000011ea1ad in php_request_shutdown ()
#8 0x0000000001807337 in do_cli ()
at /home/geeknik/php-src/sapi/cli/php_cli.c:1135
#9 0x000000000043bbb1 in main ()
at /home/geeknik/php-src/sapi/cli/php_cli.c:1334
#10 0x00007ffff6a1dead in __libc_start_main (main=<optimized out>,
argc=<optimized out>, ubp_av=<optimized out>, init=<optimized out>,
fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe358)
at libc-start.c:244
#11 0x000000000043be41 in _start ()
gdb-peda$ p $rip
$1 = (void (*)()) 0x134f84e <_efree+238>
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=69295
--
Edit this bug report at https://bugs.php.net/bug.php?id=69295&edit=1