Bug #69295 [Ver]: segfault w/ memory corruption in _efree() on unserialize

From: 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

« previous php.bugs (#203085) next »