Skip to content

Commit 6ff4a2d

Browse files
committed
Fix GH-16318: Recursive array segfaults soap encoding
This adds recursion protection to the array encoders. Closes GH-16347.
1 parent 41d75f4 commit 6ff4a2d

File tree

3 files changed

+57
-0
lines changed

3 files changed

+57
-0
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ PHP NEWS
3737
. Fixed bug GH-16385 (Unexpected null returned by session_set_cookie_params).
3838
(nielsdos)
3939

40+
- SOAP:
41+
. Fixed bug GH-16318 (Recursive array segfaults soap encoding). (nielsdos)
42+
4043
- Sockets:
4144
. Fixed bug with overflow socket_recvfrom $length argument. (David Carlier)
4245

ext/soap/php_encoding.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,6 +2136,13 @@ static void add_xml_array_elements(xmlNodePtr xmlParam,
21362136
xmlNodePtr xparam;
21372137

21382138
if (data && Z_TYPE_P(data) == IS_ARRAY) {
2139+
if (UNEXPECTED(Z_IS_RECURSIVE_P(data))) {
2140+
zend_value_error("Recursive array cannot be encoded");
2141+
return;
2142+
}
2143+
2144+
GC_TRY_PROTECT_RECURSION(Z_ARRVAL_P(data));
2145+
21392146
ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(data), zdata) {
21402147
if (j >= dims[0]) {
21412148
break;
@@ -2184,6 +2191,8 @@ static void add_xml_array_elements(xmlNodePtr xmlParam,
21842191
j++;
21852192
}
21862193
}
2194+
2195+
GC_TRY_UNPROTECT_RECURSION(Z_ARRVAL_P(data));
21872196
} else {
21882197
for (j=0; j<dims[0]; j++) {
21892198
if (dimension == 1) {
@@ -2701,6 +2710,13 @@ static xmlNodePtr to_xml_map(encodeTypePtr type, zval *data, int style, xmlNodeP
27012710
FIND_ZVAL_NULL(data, xmlParam, style);
27022711

27032712
if (Z_TYPE_P(data) == IS_ARRAY) {
2713+
if (UNEXPECTED(Z_IS_RECURSIVE_P(data))) {
2714+
zend_value_error("Recursive array cannot be encoded");
2715+
return NULL;
2716+
}
2717+
2718+
GC_TRY_PROTECT_RECURSION(Z_ARRVAL_P(data));
2719+
27042720
ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(data), int_val, key_val, temp_data) {
27052721
item = xmlNewNode(NULL, BAD_CAST("item"));
27062722
xmlAddChild(xmlParam, item);
@@ -2728,6 +2744,8 @@ static xmlNodePtr to_xml_map(encodeTypePtr type, zval *data, int style, xmlNodeP
27282744
xparam = master_to_xml(get_conversion(Z_TYPE_P(temp_data)), temp_data, style, item);
27292745
xmlNodeSetName(xparam, BAD_CAST("value"));
27302746
} ZEND_HASH_FOREACH_END();
2747+
2748+
GC_TRY_UNPROTECT_RECURSION(Z_ARRVAL_P(data));
27312749
}
27322750
if (style == SOAP_ENCODED) {
27332751
set_ns_and_type(xmlParam, type);

ext/soap/tests/gh16318.phpt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
GH-16318 (Recursive array segfaults soap encoding)
3+
--EXTENSIONS--
4+
soap
5+
--FILE--
6+
<?php
7+
8+
// SOAP-ENC array
9+
$tmp =& $test1;
10+
$test1[] = $tmp;
11+
12+
// map array
13+
$test2 = [];
14+
$test2["a"] = "a";
15+
$test2[] =& $test2;
16+
17+
class TestSoapClient extends SoapClient {
18+
public function __doRequest(string $request, string $location, string $action, int $version, bool $oneWay = false): ?string
19+
{
20+
die($request);
21+
}
22+
}
23+
$client = new TestSoapClient(NULL,array("location"=>"test://","uri"=>"http://soapinterop.org/","trace"=>1,"exceptions"=>0));
24+
25+
foreach ([$test1, $test2] as $test) {
26+
try {
27+
$client->__soapCall("echoStructArray", array($test), array("soapaction"=>"http://soapinterop.org/","uri"=>"http://soapinterop.org/"));
28+
} catch (ValueError $e) {
29+
echo $e->getMessage(), "\n";
30+
}
31+
}
32+
33+
?>
34+
--EXPECT--
35+
Recursive array cannot be encoded
36+
Recursive array cannot be encoded

0 commit comments

Comments
 (0)