Skip to content

Commit 183f99d

Browse files
committed
soap: reject self-referential schema group and attributeGroup fix-up
schema_content_model_fixup() and schema_attributegroup_fixup() followed a group ref back into schema_type_fixup() with nothing tracking the types already being fixed up, so a schema whose group references itself recursed until the C stack ran out. Track the in-progress types in the sdl context and raise a parse error when one is re-entered. Closes GH-23600
1 parent 979c827 commit 183f99d

5 files changed

Lines changed: 102 additions & 0 deletions

File tree

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ PHP NEWS
9797
fails to initialize). (Lazizbek Ergashev)
9898
. Fixed WSDL cache corruption when a soap:header defines headerfaults.
9999
(Ilia Alshanetsky)
100+
. Fixed stack overflow when parsing a WSDL with self-referential schema
101+
groups or attributeGroups. (Ilia Alshanetsky)
100102

101103
- Standard:
102104
. Fixed a segfault when a stream filter callback unsets StreamBucket::$data

ext/soap/php_schema.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2161,6 +2161,10 @@ static void schema_attributegroup_fixup(sdlCtx *ctx, sdlAttributePtr attr, HashT
21612161
if (ctx->attributeGroups != NULL) {
21622162
tmp = (sdlTypePtr)schema_find_by_ref(ctx->attributeGroups, attr->ref);
21632163
if (tmp) {
2164+
if (zend_hash_index_find_ptr(&ctx->fixupInProgress, (zend_ulong)tmp) != NULL) {
2165+
soap_error1(E_ERROR, "Parsing Schema: recursive attributeGroup 'ref' attribute '%s'", attr->ref);
2166+
}
2167+
zend_hash_index_add_ptr(&ctx->fixupInProgress, (zend_ulong)tmp, tmp);
21642168
if (tmp->attributes) {
21652169
zend_hash_internal_pointer_reset(tmp->attributes);
21662170
while ((tmp_attr = zend_hash_get_current_data_ptr(tmp->attributes)) != NULL) {
@@ -2196,6 +2200,7 @@ static void schema_attributegroup_fixup(sdlCtx *ctx, sdlAttributePtr attr, HashT
21962200
}
21972201
}
21982202
}
2203+
zend_hash_index_del(&ctx->fixupInProgress, (zend_ulong)tmp);
21992204
}
22002205
}
22012206
efree(attr->ref);
@@ -2210,6 +2215,9 @@ static void schema_content_model_fixup(sdlCtx *ctx, sdlContentModelPtr model)
22102215
sdlTypePtr tmp;
22112216

22122217
if (ctx->sdl->groups && (tmp = zend_hash_str_find_ptr(ctx->sdl->groups, model->u.group_ref, strlen(model->u.group_ref))) != NULL) {
2218+
if (zend_hash_index_find_ptr(&ctx->fixupInProgress, (zend_ulong)tmp) != NULL) {
2219+
soap_error1(E_ERROR, "Parsing Schema: recursive group 'ref' attribute '%s'", model->u.group_ref);
2220+
}
22132221
schema_type_fixup(ctx, tmp);
22142222
efree(model->u.group_ref);
22152223
model->kind = XSD_CONTENT_GROUP;
@@ -2253,6 +2261,8 @@ static void schema_type_fixup(sdlCtx *ctx, sdlTypePtr type)
22532261
sdlTypePtr tmp;
22542262
sdlAttributePtr attr;
22552263

2264+
zend_hash_index_add_ptr(&ctx->fixupInProgress, (zend_ulong)type, type);
2265+
22562266
if (type->ref != NULL) {
22572267
if (ctx->sdl->elements != NULL) {
22582268
tmp = (sdlTypePtr)schema_find_by_ref(ctx->sdl->elements, type->ref);
@@ -2305,6 +2315,7 @@ static void schema_type_fixup(sdlCtx *ctx, sdlTypePtr type)
23052315
}
23062316
}
23072317
}
2318+
zend_hash_index_del(&ctx->fixupInProgress, (zend_ulong)type);
23082319
}
23092320

23102321
void schema_pass2(sdlCtx *ctx)
@@ -2313,6 +2324,8 @@ void schema_pass2(sdlCtx *ctx)
23132324
sdlAttributePtr attr;
23142325
sdlTypePtr type;
23152326

2327+
zend_hash_init(&ctx->fixupInProgress, 0, NULL, NULL, 0);
2328+
23162329
if (ctx->attributes) {
23172330
ZEND_HASH_FOREACH_PTR(ctx->attributes, attr) {
23182331
schema_attribute_fixup(ctx, attr);
@@ -2346,6 +2359,8 @@ void schema_pass2(sdlCtx *ctx)
23462359
zend_hash_destroy(ctx->attributeGroups);
23472360
efree(ctx->attributeGroups);
23482361
}
2362+
2363+
zend_hash_destroy(&ctx->fixupInProgress);
23492364
}
23502365

23512366
void delete_model(zval *zv)

ext/soap/php_sdl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ typedef struct sdlCtx {
7373

7474
HashTable *attributes; /* array of sdlAttributePtr */
7575
HashTable *attributeGroups; /* array of sdlTypesPtr */
76+
HashTable fixupInProgress;
7677
php_stream_context *context;
7778
zval old_header;
7879
} sdlCtx;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
SOAP XML Schema: self-referential attributeGroup fix-up recursion is rejected
3+
--EXTENSIONS--
4+
soap
5+
--FILE--
6+
<?php
7+
$wsdl = '<?xml version="1.0"?>
8+
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
9+
xmlns:tns="urn:test" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
10+
<types>
11+
<xsd:schema targetNamespace="urn:test" xmlns="http://www.w3.org/2001/XMLSchema">
12+
<attributeGroup name="A">
13+
<attribute name="a" type="string"/>
14+
<attributeGroup ref="tns:A"/>
15+
</attributeGroup>
16+
<element name="root">
17+
<complexType><attributeGroup ref="tns:A"/></complexType>
18+
</element>
19+
</xsd:schema>
20+
</types>
21+
<message name="m"><part name="p" element="tns:root"/></message>
22+
<portType name="pt"><operation name="op"><input message="tns:m"/></operation></portType>
23+
<binding name="b" type="tns:pt"><soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/>
24+
<operation name="op"><soap:operation soapAction="" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/><input><soap:body use="literal" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/></input></operation>
25+
</binding>
26+
<service name="s"><port name="p1" binding="tns:b"><soap:address location="http://localhost/x" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/></port></service>
27+
</definitions>';
28+
$file = sys_get_temp_dir() . '/selfref_attrgroup_' . getmypid() . '.wsdl';
29+
file_put_contents($file, $wsdl);
30+
try {
31+
$c = new SoapClient($file, ['exceptions' => true, 'cache_wsdl' => WSDL_CACHE_NONE]);
32+
echo "parsed ok\n";
33+
} catch (SoapFault $e) {
34+
echo "SoapFault: ", substr($e->getMessage(), 0, 120), "\n";
35+
}
36+
@unlink($file);
37+
echo "done\n";
38+
?>
39+
--EXPECTF--
40+
SoapFault: SOAP-ERROR: Parsing Schema: recursive attributeGroup 'ref' attribute '%s'
41+
done
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
--TEST--
2+
SOAP XML Schema: self-referential group fix-up recursion is rejected
3+
--EXTENSIONS--
4+
soap
5+
--FILE--
6+
<?php
7+
$wsdl = '<?xml version="1.0"?>
8+
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
9+
xmlns:tns="urn:test" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
10+
<types>
11+
<xsd:schema targetNamespace="urn:test" xmlns="http://www.w3.org/2001/XMLSchema">
12+
<group name="A">
13+
<sequence>
14+
<element name="a" type="string"/>
15+
<group ref="tns:A"/>
16+
</sequence>
17+
</group>
18+
<element name="root">
19+
<complexType><group ref="tns:A"/></complexType>
20+
</element>
21+
</xsd:schema>
22+
</types>
23+
<message name="m"><part name="p" element="tns:root"/></message>
24+
<portType name="pt"><operation name="op"><input message="tns:m"/></operation></portType>
25+
<binding name="b" type="tns:pt"><soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/>
26+
<operation name="op"><soap:operation soapAction="" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/><input><soap:body use="literal" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/></input></operation>
27+
</binding>
28+
<service name="s"><port name="p1" binding="tns:b"><soap:address location="http://localhost/x" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"/></port></service>
29+
</definitions>';
30+
$file = sys_get_temp_dir() . '/selfref_group_' . getmypid() . '.wsdl';
31+
file_put_contents($file, $wsdl);
32+
try {
33+
$c = new SoapClient($file, ['exceptions' => true, 'cache_wsdl' => WSDL_CACHE_NONE]);
34+
echo "parsed ok\n";
35+
} catch (SoapFault $e) {
36+
echo "SoapFault: ", substr($e->getMessage(), 0, 120), "\n";
37+
}
38+
@unlink($file);
39+
echo "done\n";
40+
?>
41+
--EXPECTF--
42+
SoapFault: SOAP-ERROR: Parsing Schema: recursive group 'ref' attribute '%s'
43+
done

0 commit comments

Comments
 (0)