Skip to content

Commit 54fd812

Browse files
committed
Zend: Fix type confusion in Exception::getTraceAsString().
A crafted, deliberately truncated unserialize() payload can leave Exception::$trace holding a non-array value, since the typed-property check is skipped on the parse failure path. getTraceAsString() then reinterpreted the object as a HashTable, causing an out-of-bounds read. Guard against a non-array trace and return an empty string instead. Fix #222257
1 parent 78d394e commit 54fd812

2 files changed

Lines changed: 36 additions & 2 deletions

File tree

Zend/tests/gh22257.phpt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
GH-22257 (Type confusion / OOB read in Exception::getTraceAsString() with a non-array trace)
3+
--CREDITS--
4+
012git012
5+
--FILE--
6+
<?php
7+
/* A crafted, deliberately truncated payload leaves Exception::$trace holding a
8+
* non-array value (the typed-property check is skipped on the parse failure path).
9+
* The half-built object is then exposed to getTraceAsString() through SplHeap's
10+
* delayed __unserialize(), which used to type-confuse the object as a HashTable. */
11+
$n = "\x00";
12+
$r = unserialize(
13+
'O:9:"Exception":1:{' .
14+
's:16:"' . $n . 'Exception' . $n . 'trace";' .
15+
'O:8:"stdClass":2:{' .
16+
's:1:"0";' .
17+
'O:10:"SplMaxHeap":2:{' .
18+
'i:0;a:0:{}' .
19+
'i:1;a:2:{' .
20+
's:5:"flags";i:0;' .
21+
's:13:"heap_elements";a:2:{i:0;s:0:"";i:1;R:1;}' .
22+
'}' .
23+
'}' .
24+
'z' .
25+
'}}'
26+
);
27+
var_dump($r);
28+
echo "OK\n";
29+
?>
30+
--EXPECTF--
31+
Warning: unserialize(): Error at offset %d of %d bytes in %s on line %d
32+
bool(false)
33+
OK

Zend/zend_exceptions.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -685,8 +685,9 @@ ZEND_METHOD(Exception, getTraceAsString)
685685
}
686686

687687
ZVAL_DEREF(trace);
688-
/* Type should be guaranteed by property type. */
689-
ZEND_ASSERT(Z_TYPE_P(trace) == IS_ARRAY);
688+
if (UNEXPECTED(Z_TYPE_P(trace) != IS_ARRAY)) {
689+
RETURN_EMPTY_STRING();
690+
}
690691
RETURN_NEW_STR(zend_trace_to_string(Z_ARRVAL_P(trace), /* include_main */ true));
691692
}
692693
/* }}} */

0 commit comments

Comments
 (0)