Skip to content

Commit 7e4a323

Browse files
committed
Fix GH-12392: Segmentation fault on SoapClient::__getTypes
There are two issues: - UAF because the hashmap resized while being iterated over, yet the local variables used internally in the macros are not updated. - The hashmap being iterated over is modified: entries are deleted after other entries have been added. This causes the deletion to fail sometimes because indices of buckets have shifted. Fix it by using a while loop iteration and HashPosition position tracker instead. Issue exists on PHP 8.1 too, but is much harder to trigger. The test file reproduces the issue reliably on PHP 8.2 and up. Closes GH-12409.
1 parent 71f1451 commit 7e4a323

File tree

4 files changed

+105
-6
lines changed

4 files changed

+105
-6
lines changed

NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ PHP NEWS
1010
. Fixed bug GH-8143 (Crashes in zend_accel_inheritance_cache_find since
1111
upgrading to 8.1.3 due to corrupt on-disk file cache). (turchanov)
1212

13+
- SOAP:
14+
. Fixed bug GH-12392 (Segmentation fault on SoapClient::__getTypes).
15+
(nielsdos)
16+
1317
26 Oct 2023, PHP 8.1.25
1418

1519
- Core:

ext/soap/php_schema.c

+12-6
Original file line numberDiff line numberDiff line change
@@ -2261,17 +2261,23 @@ static void schema_type_fixup(sdlCtx *ctx, sdlTypePtr type)
22612261
schema_content_model_fixup(ctx, type->model);
22622262
}
22632263
if (type->attributes) {
2264-
zend_string *str_key;
2265-
zend_ulong index;
2264+
HashPosition pos;
2265+
zend_hash_internal_pointer_reset_ex(type->attributes, &pos);
22662266

2267-
ZEND_HASH_FOREACH_KEY_PTR(type->attributes, index, str_key, attr) {
2268-
if (str_key) {
2267+
while ((attr = zend_hash_get_current_data_ptr_ex(type->attributes, &pos)) != NULL) {
2268+
zend_string *str_key;
2269+
zend_ulong index;
2270+
2271+
if (zend_hash_get_current_key_ex(type->attributes, &str_key, &index, &pos) == HASH_KEY_IS_STRING) {
22692272
schema_attribute_fixup(ctx, attr);
2273+
zend_result result = zend_hash_move_forward_ex(type->attributes, &pos);
2274+
ZEND_ASSERT(result == SUCCESS);
22702275
} else {
22712276
schema_attributegroup_fixup(ctx, attr, type->attributes);
2272-
zend_hash_index_del(type->attributes, index);
2277+
zend_result result = zend_hash_index_del(type->attributes, index);
2278+
ZEND_ASSERT(result == SUCCESS);
22732279
}
2274-
} ZEND_HASH_FOREACH_END();
2280+
}
22752281
}
22762282
}
22772283

ext/soap/tests/gh12392.phpt

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
GH-12392 (Segmentation fault on SoapClient::__getTypes)
3+
--EXTENSIONS--
4+
soap
5+
--FILE--
6+
<?php
7+
8+
$client = new SoapClient(__DIR__ . "/gh12392.wsdl", ['cache_wsdl' => WSDL_CACHE_NONE]);
9+
echo 'Client created!' . "\n";
10+
11+
$types = $client->__getTypes();
12+
echo 'Got types!' . "\n";
13+
14+
var_dump($types);
15+
16+
?>
17+
--EXPECT--
18+
Client created!
19+
Got types!
20+
array(1) {
21+
[0]=>
22+
string(62) "struct dummy {
23+
string foo;
24+
string a;
25+
string b;
26+
string c;
27+
}"
28+
}

ext/soap/tests/gh12392.wsdl

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<wsdl:definitions
3+
xmlns:xs="http://www.w3.org/2001/XMLSchema"
4+
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
5+
xmlns="http://schemas.xmlsoap.org/wsdl/"
6+
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
7+
targetNamespace="http://xoev.de/schemata/xzufi/2_2_0">
8+
<wsdl:types>
9+
<xs:schema xmlns:ns="http://php.net" targetNamespace="http://php.net">
10+
<xs:attributeGroup name="c">
11+
<xs:attribute name="c" type="string" />
12+
</xs:attributeGroup>
13+
14+
<xs:attributeGroup name="b">
15+
<xs:attribute name="b" type="string" />
16+
</xs:attributeGroup>
17+
18+
<xs:attributeGroup name="a">
19+
<xs:attribute name="a" type="string" />
20+
<xs:attributeGroup ref="ns:b" />
21+
</xs:attributeGroup>
22+
23+
<xs:complexType name="dummy">
24+
<xs:sequence>
25+
<xs:element name="foo" type="string" />
26+
</xs:sequence>
27+
<xs:attributeGroup ref="ns:a" />
28+
<xs:attributeGroup ref="ns:c" />
29+
</xs:complexType>
30+
</xs:schema>
31+
</wsdl:types>
32+
33+
<!-- Below is a shortened copy of the test.wsdl, doesn't matter, only the types matter -->
34+
35+
<message name="AddRequest">
36+
<part name="x" type="xs:double" />
37+
</message>
38+
39+
<portType name="TestServicePortType">
40+
<operation name="Add">
41+
<input message="tns:AddRequest" />
42+
</operation>
43+
</portType>
44+
45+
<binding name="TestServiceBinding" type="tns:TestServicePortType">
46+
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
47+
<operation name="Add">
48+
<soap:operation soapAction="Add" style="rpc" />
49+
<input>
50+
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
51+
</input>
52+
</operation>
53+
</binding>
54+
55+
<service name="TestService">
56+
<port name="TestServicePort" binding="tns:TestServiceBinding">
57+
<soap:address location="http://linuxsrv.home/~dmitry/soap/soap_server.php" />
58+
</port>
59+
</service>
60+
61+
</wsdl:definitions>

0 commit comments

Comments
 (0)