[php-src] PHP-8.6: Merge branch 'PHP-8.5' into PHP-8.6

From: Date: Thu, 01 Oct 2026 18:16:26 +0000
Subject: [php-src] PHP-8.6: Merge branch 'PHP-8.5' into PHP-8.6
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-141851@lists.php.net to get a copy of this message
Author: David Carlier (devnexen) Date: 2026-10-01T19:13:18+01:00 Commit: https://github.com/php/php-src/commit/58f680c81e490bf45cbfb6dd42a17ed430cf8f41 Raw diff: https://github.com/php/php-src/commit/58f680c81e490bf45cbfb6dd42a17ed430cf8f41.diff Merge branch 'PHP-8.5' into PHP-8.6 * PHP-8.5: ext/soap: to_xml_array() heap use-after-free with illegal iterator keys. Changed paths: A ext/soap/tests/bugs/gh22895.phpt M NEWS M Zend/zend_API.c M ext/soap/php_encoding.c Diff: diff --git a/NEWS b/NEWS index 47044f8d3e07..0277ee871e22 100644 --- a/NEWS +++ b/NEWS @@ -108,6 +108,10 @@ PHP NEWS . Fixed reconstructing a SimpleXMLElement freeing a child element that another variable still references. (Ilia Alshanetsky) +- SOAP: + . Fixed bug GH-22895 (Heap use-after-free while encoding a Traversable with + an illegal key). (David Carlier) + - Tidy: . Fixed a use-after-free when a tidyNode is used after its document is reparsed. (Ilia Alshanetsky) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 0665a65b5dae..739bc9d240ea 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2310,6 +2310,9 @@ ZEND_API zend_result array_set_zval_key(HashTable *ht, zval *key, zval *value) / break; case IS_RESOURCE: zend_use_resource_as_offset(key); + if (UNEXPECTED(EG(exception))) { + return FAILURE; + } result = zend_hash_index_update(ht, Z_RES_HANDLE_P(key), value); break; case IS_FALSE: @@ -2321,9 +2324,14 @@ ZEND_API zend_result array_set_zval_key(HashTable *ht, zval *key, zval *value) / case IS_LONG: result = zend_hash_index_update(ht, Z_LVAL_P(key), value); break; - case IS_DOUBLE: - result = zend_hash_index_update(ht, zend_dval_to_lval_safe(Z_DVAL_P(key)), value); + case IS_DOUBLE: { + zend_long lval = zend_dval_to_lval_safe(Z_DVAL_P(key)); + if (UNEXPECTED(EG(exception))) { + return FAILURE; + } + result = zend_hash_index_update(ht, lval, value); break; + } case IS_NULL: zend_error(E_DEPRECATED, "Using null as an array offset is deprecated, use an empty string instead"); if (UNEXPECTED(EG(exception))) { diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index 646dc688abfb..73589025ccc6 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -2302,13 +2302,15 @@ static xmlNodePtr to_xml_array(encodeTypePtr type, zval *data, int style, xmlNod if (EG(exception)) { goto iterator_done; } - array_set_zval_key(Z_ARRVAL(array_copy), &key, val); - zval_ptr_dtor(val); + zend_result status = array_set_zval_key(Z_ARRVAL(array_copy), &key, val); zval_ptr_dtor(&key); + if (status == FAILURE) { + goto iterator_done; + } } else { + Z_TRY_ADDREF_P(val); add_next_index_zval(&array_copy, val); } - Z_TRY_ADDREF_P(val); iter->funcs->move_forward(iter); if (EG(exception)) { diff --git a/ext/soap/tests/bugs/gh22895.phpt b/ext/soap/tests/bugs/gh22895.phpt new file mode 100644 index 000000000000..feed80065a46 --- /dev/null +++ b/ext/soap/tests/bugs/gh22895.phpt @@ -0,0 +1,97 @@ +--TEST-- +GH-22895 (Heap use-after-free while encoding a Traversable with an illegal key) +--CREDITS-- +Amorsec +--EXTENSIONS-- +soap +--FILE-- +<?php +class LocalSoapClient extends SoapClient +{ + public function __doRequest( + $request, + $location, + $action, + $version, + $one_way = false + ): ?string { + return ''; + } +} + +class ArrayKeyIterator implements Iterator +{ + private int $i = 0; + + public function current(): mixed + { + return new stdClass(); + } + + public function key(): mixed + { + return ['illegal', 'key']; + } + + public function next(): void + { + $this->i++; + } + + public function rewind(): void + { + $this->i = 0; + } + + public function valid(): bool + { + return $this->i < 2; + } +} + +$client = new LocalSoapClient(null, [ + 'location' => 'http://127.0.0.1/', + 'uri' => 'urn:audit', + 'trace' => 1, +]); + +$multiple = new MultipleIterator(); +$multiple->attachIterator(new ArrayIterator([0])); + +foreach ([$multiple, new ArrayKeyIterator()] as $iterator) { + try { + $client->__soapCall('audit', [new SoapVar($iterator, SOAP_ENC_ARRAY)]); + } catch (TypeError $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; + } +} + +function gen($key) { + yield $key => new stdClass(); + yield 2 => new stdClass(); +} + +set_error_handler(function ($errno, $errstr) { + throw new Exception($errstr); +}); +foreach ([1.5, STDIN, null] as $key) { + try { + $client->__soapCall('audit', [new SoapVar(gen($key), SOAP_ENC_ARRAY)]); + } catch (Exception $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; + } +} +restore_error_handler(); + +/* A key the encoder can use must still be serialized, without leaking. */ +$client->__soapCall('audit', [new SoapVar(new ArrayIterator(['a' => 1]), SOAP_ENC_ARRAY)]); +echo $client->__getLastRequest(); +?> +--EXPECTF-- +TypeError: Cannot access offset of type array on array +TypeError: Cannot access offset of type array on array +Exception: Implicit conversion from float 1.5 to int loses precision +Exception: Resource ID#%d used as offset, casting to integer (%d) +Exception: Using null as an array offset is deprecated, use an empty string instead +<?xml version="1.0" encoding="UTF-8"?> +<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:audit" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:audit><param0 SOAP-ENC:arrayType="xsd:int[1]" xsi:type="SOAP-ENC:Array"><item xsi:type="xsd:int">1</item></param0></ns1:audit></SOAP-ENV:Body></SOAP-ENV:Envelope>

« previous php.cvs (#141851) next »