diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index 4eedbffc5a4b..d0911c863d89 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -380,6 +380,16 @@ static void soap_add_xml_ref(zval *data, xmlNodePtr node) } } +static void soap_add_xml_ref_holder(zval *data, xmlNodePtr node) +{ + if (SOAP_GLOBAL(ref_map)) { + zval holder; + + array_init(&holder); + zend_hash_index_update(SOAP_GLOBAL(ref_map), (zend_ulong)node, &holder); + } +} + static xmlNodePtr master_to_xml_int(encodePtr encode, zval *data, int style, xmlNodePtr parent, int check_class_map) { xmlNodePtr node = NULL; @@ -2536,6 +2546,9 @@ static zval *to_zval_array(zval *ret, encodeTypePtr type, xmlNodePtr data) ZVAL_NULL(ret); FIND_XML_NULL(data, ret); + if (soap_check_xml_ref(ret, data)) { + return ret; + } if (data && (attr = get_attribute(data->properties,"arrayType")) && @@ -2672,6 +2685,7 @@ static zval *to_zval_array(zval *ret, encodeTypePtr type, xmlNodePtr data) } array_init(ret); + soap_add_xml_ref_holder(ret, data); trav = data->children; while (trav) { if (trav->type == XML_ELEMENT_NODE) { @@ -2729,6 +2743,7 @@ static zval *to_zval_array(zval *ret, encodeTypePtr type, xmlNodePtr data) } efree(dims); efree(pos); + soap_add_xml_ref(ret, data); return ret; } @@ -2798,9 +2813,13 @@ static zval *to_zval_map(zval *ret, encodeTypePtr type, xmlNodePtr data) ZVAL_NULL(ret); FIND_XML_NULL(data, ret); + if (soap_check_xml_ref(ret, data)) { + return ret; + } if (data && data->children) { array_init(ret); + soap_add_xml_ref_holder(ret, data); trav = data->children; trav = data->children; @@ -2830,6 +2849,7 @@ static zval *to_zval_map(zval *ret, encodeTypePtr type, xmlNodePtr data) zval_ptr_dtor(&key); } ENDFOREACH(trav); + soap_add_xml_ref(ret, data); } else { ZVAL_NULL(ret); } diff --git a/ext/soap/tests/bugs/gh22984_1.phpt b/ext/soap/tests/bugs/gh22984_1.phpt new file mode 100644 index 000000000000..4257555e086c --- /dev/null +++ b/ext/soap/tests/bugs/gh22984_1.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-22984 (Native stack overflow while decoding a cyclic SOAP 1.1 href reference) +--EXTENSIONS-- +soap +--FILE-- + + + + + + + + + + +XML; + } +} + +$client = new TestSoapClient(null, ['location' => 'test://', 'uri' => 'http://testuri.org', 'soap_version' => SOAP_1_1]); +var_dump($client->__soapCall('probe', [])); +?> +--EXPECT-- +array(1) { + [0]=> + array(0) { + } +} diff --git a/ext/soap/tests/bugs/gh22984_2.phpt b/ext/soap/tests/bugs/gh22984_2.phpt new file mode 100644 index 000000000000..07fd190cf34a --- /dev/null +++ b/ext/soap/tests/bugs/gh22984_2.phpt @@ -0,0 +1,47 @@ +--TEST-- +GH-22984 (Native stack overflow while decoding a cyclic SOAP 1.2 enc:ref reference) +--EXTENSIONS-- +soap +--FILE-- + + + + + + + + + + + + + +XML; + } +} + +$client = new TestSoapClient(null, ['location' => 'test://', 'uri' => 'http://testuri.org', 'soap_version' => SOAP_1_2]); +var_dump($client->__soapCall('probe', [])); +?> +--EXPECT-- +array(2) { + ["ret"]=> + array(1) { + [0]=> + array(1) { + [0]=> + array(0) { + } + } + } + ["node"]=> + array(1) { + [0]=> + array(0) { + } + } +} diff --git a/ext/soap/tests/bugs/gh22984_3.phpt b/ext/soap/tests/bugs/gh22984_3.phpt new file mode 100644 index 000000000000..ebe0eb3d9d38 --- /dev/null +++ b/ext/soap/tests/bugs/gh22984_3.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-22984 (Native stack overflow while decoding a cyclic reference inside an apache Map) +--EXTENSIONS-- +soap +--FILE-- + + + + + + + self + + + + + + +XML; + } +} + +$client = new TestSoapClient(null, ['location' => 'test://', 'uri' => 'http://testuri.org', 'soap_version' => SOAP_1_1]); +var_dump($client->__soapCall('probe', [])); +?> +--EXPECT-- +array(1) { + ["self"]=> + array(0) { + } +} diff --git a/ext/soap/tests/bugs/gh22984_4.phpt b/ext/soap/tests/bugs/gh22984_4.phpt new file mode 100644 index 000000000000..41e2d3b11182 --- /dev/null +++ b/ext/soap/tests/bugs/gh22984_4.phpt @@ -0,0 +1,40 @@ +--TEST-- +GH-22984 (Native stack overflow while a SoapServer decodes a cyclic href reference) +--EXTENSIONS-- +soap +--FILE-- + + + + + + + + + + +XML; + +$server = new SoapServer(null, ['uri' => 'http://testuri.org']); +$server->addFunction('probe'); +$server->handle($request); +var_dump($decoded); +?> +--EXPECT-- + +1 +array(1) { + [0]=> + array(0) { + } +}