Skip to content

ext/soap: to_xml_array() heap use-after-free with illegal iterator keys. - #22896

Closed
devnexen wants to merge 4 commits into
php:PHP-8.4from
devnexen:gh22895
Closed

devnexen wants to merge 4 commits into
php:PHP-8.4from
devnexen:gh22895

Conversation

@devnexen

Copy link
Copy Markdown
Member

Fix #22895

The return value of array_set_zval_key() was ignored, so when the key is not a legal array offset, e.g. MultipleIterator::key() returning an array, it threw and took no reference. The unconditional zval_ptr_dtor() then dropped the iterator's only reference to the borrowed value and the following Z_TRY_ADDREF_P() read freed memory.

Let array_set_zval_key() own its reference the way spl_iterator_to_array_apply() does, and stop iterating on failure.

Fix php#22895

The return value of array_set_zval_key() was ignored, so when the key is
not a legal array offset, e.g. MultipleIterator::key() returning an
array, it threw and took no reference. The unconditional zval_ptr_dtor()
then dropped the iterator's only reference to the borrowed value and the
following Z_TRY_ADDREF_P() read freed memory.

Let array_set_zval_key() own its reference the way
spl_iterator_to_array_apply() does, and stop iterating on failure.
@devnexen devnexen linked an issue Jul 27, 2026 that may be closed by this pull request
@devnexen
devnexen marked this pull request as ready for review July 27, 2026 05:14
Comment thread ext/soap/tests/bugs/gh22895.phpt Outdated
try {
$client->__soapCall('audit', [new SoapVar($iterator, SOAP_ENC_ARRAY)]);
} catch (TypeError $e) {
echo $e->getMessage(), PHP_EOL;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
echo $e->getMessage(), PHP_EOL;
echo $e::class, ': ', $e->getMessage(), PHP_EOL;

@iliaal

iliaal commented Oct 1, 2026

Copy link
Copy Markdown
Member

This misses one case: a key that inserts fine but raises a throwing diagnostic. With a 1.5 key and an error handler that throws, array_set_zval_key() returns SUCCESS with the exception pending, the loop calls move_forward(), and a generator resumed that way never terminates (on this branch it ends in "Allowed memory size exhausted"). Checking EG(exception) after the insert, as spl_iterator_to_array_apply() does, covers it:

set_error_handler(function ($errno, $errstr) { throw new Exception($errstr); });
function gen() { yield 1.5 => new stdClass(); yield 2 => new stdClass(); }
$client = new SoapClient(null, ['location' => 'test://', 'uri' => 'urn:test']);
$client->test(new SoapVar(gen(), SOAP_ENC_ARRAY));

@Girgias

Girgias commented Oct 1, 2026

Copy link
Copy Markdown
Member

array_set_zval_key

If this is caused by this function not behaving correctly then this should be fixed instead to return FAILURE when an exception is triggered.

@devnexen

devnexen commented Oct 1, 2026

Copy link
Copy Markdown
Member Author

array_set_zval_key

If this is caused by this function not behaving correctly then this should be fixed instead to return FAILURE when an exception is triggered.

sure !

Comment thread Zend/zend_API.c
case IS_STRING:
result = zend_symtable_update(ht, Z_STR_P(key), value);
break;
case IS_NULL:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably needs the same fix during up-merging due to null as array key deprecation.

@iliaal
iliaal self-requested a review October 1, 2026 12:41

@iliaal iliaal left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for the tweaks

@devnexen devnexen closed this in d044f28 Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ext/soap: heap use-after-free while encoding a MultipleIterator

4 participants