diff --git a/NEWS b/NEWS index 1cc265f02e8d..f747e7723264 100644 --- a/NEWS +++ b/NEWS @@ -97,6 +97,8 @@ PHP NEWS fails to initialize). (Lazizbek Ergashev) . Fixed WSDL cache corruption when a soap:header defines headerfaults. (Ilia Alshanetsky) + . Fixed stack overflow when parsing a WSDL with self-referential schema + groups or attributeGroups. (Ilia Alshanetsky) - Standard: . Fixed a segfault when a stream filter callback unsets StreamBucket::$data diff --git a/ext/soap/php_schema.c b/ext/soap/php_schema.c index a4911c659842..90d175a02535 100644 --- a/ext/soap/php_schema.c +++ b/ext/soap/php_schema.c @@ -2161,6 +2161,10 @@ static void schema_attributegroup_fixup(sdlCtx *ctx, sdlAttributePtr attr, HashT if (ctx->attributeGroups != NULL) { tmp = (sdlTypePtr)schema_find_by_ref(ctx->attributeGroups, attr->ref); if (tmp) { + if (zend_hash_index_find_ptr(&ctx->fixupInProgress, (zend_ulong)tmp) != NULL) { + soap_error1(E_ERROR, "Parsing Schema: recursive attributeGroup 'ref' attribute '%s'", attr->ref); + } + zend_hash_index_add_ptr(&ctx->fixupInProgress, (zend_ulong)tmp, tmp); if (tmp->attributes) { zend_hash_internal_pointer_reset(tmp->attributes); 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 } } } + zend_hash_index_del(&ctx->fixupInProgress, (zend_ulong)tmp); } } efree(attr->ref); @@ -2210,6 +2215,9 @@ static void schema_content_model_fixup(sdlCtx *ctx, sdlContentModelPtr model) sdlTypePtr tmp; if (ctx->sdl->groups && (tmp = zend_hash_str_find_ptr(ctx->sdl->groups, model->u.group_ref, strlen(model->u.group_ref))) != NULL) { + if (zend_hash_index_find_ptr(&ctx->fixupInProgress, (zend_ulong)tmp) != NULL) { + soap_error1(E_ERROR, "Parsing Schema: recursive group 'ref' attribute '%s'", model->u.group_ref); + } schema_type_fixup(ctx, tmp); efree(model->u.group_ref); model->kind = XSD_CONTENT_GROUP; @@ -2253,6 +2261,8 @@ static void schema_type_fixup(sdlCtx *ctx, sdlTypePtr type) sdlTypePtr tmp; sdlAttributePtr attr; + zend_hash_index_add_ptr(&ctx->fixupInProgress, (zend_ulong)type, type); + if (type->ref != NULL) { if (ctx->sdl->elements != NULL) { tmp = (sdlTypePtr)schema_find_by_ref(ctx->sdl->elements, type->ref); @@ -2305,6 +2315,7 @@ static void schema_type_fixup(sdlCtx *ctx, sdlTypePtr type) } } } + zend_hash_index_del(&ctx->fixupInProgress, (zend_ulong)type); } void schema_pass2(sdlCtx *ctx) @@ -2313,6 +2324,8 @@ void schema_pass2(sdlCtx *ctx) sdlAttributePtr attr; sdlTypePtr type; + zend_hash_init(&ctx->fixupInProgress, 0, NULL, NULL, 0); + if (ctx->attributes) { ZEND_HASH_FOREACH_PTR(ctx->attributes, attr) { schema_attribute_fixup(ctx, attr); @@ -2346,6 +2359,8 @@ void schema_pass2(sdlCtx *ctx) zend_hash_destroy(ctx->attributeGroups); efree(ctx->attributeGroups); } + + zend_hash_destroy(&ctx->fixupInProgress); } void delete_model(zval *zv) diff --git a/ext/soap/php_sdl.h b/ext/soap/php_sdl.h index 3df4fbdca015..843b13141cc0 100644 --- a/ext/soap/php_sdl.h +++ b/ext/soap/php_sdl.h @@ -73,6 +73,7 @@ typedef struct sdlCtx { HashTable *attributes; /* array of sdlAttributePtr */ HashTable *attributeGroups; /* array of sdlTypesPtr */ + HashTable fixupInProgress; php_stream_context *context; zval old_header; } sdlCtx; diff --git a/ext/soap/tests/schema-selfref-attrgroup.phpt b/ext/soap/tests/schema-selfref-attrgroup.phpt new file mode 100644 index 000000000000..668826ea6c39 --- /dev/null +++ b/ext/soap/tests/schema-selfref-attrgroup.phpt @@ -0,0 +1,44 @@ +--TEST-- +SOAP XML Schema: self-referential attributeGroup fix-up recursion is rejected +--EXTENSIONS-- +soap +--FILE-- + + + + + + + + + + + + + + + + + + + +'; +$file = __DIR__ . '/schema-selfref-attrgroup.wsdl'; +file_put_contents($file, $wsdl); +try { + $c = new SoapClient($file, ['exceptions' => true, 'cache_wsdl' => WSDL_CACHE_NONE]); + echo "parsed ok\n"; +} catch (Throwable $e) { + echo $e::class, ": ", substr($e->getMessage(), 0, 120), "\n"; +} +echo "done\n"; +?> +--CLEAN-- + +--EXPECTF-- +SoapFault: SOAP-ERROR: Parsing Schema: recursive attributeGroup 'ref' attribute '%s' +done diff --git a/ext/soap/tests/schema-selfref-group.phpt b/ext/soap/tests/schema-selfref-group.phpt new file mode 100644 index 000000000000..be9d7df524f9 --- /dev/null +++ b/ext/soap/tests/schema-selfref-group.phpt @@ -0,0 +1,46 @@ +--TEST-- +SOAP XML Schema: self-referential group fix-up recursion is rejected +--EXTENSIONS-- +soap +--FILE-- + + + + + + + + + + + + + + + + + + + + + +'; +$file = __DIR__ . '/schema-selfref-group.wsdl'; +file_put_contents($file, $wsdl); +try { + $c = new SoapClient($file, ['exceptions' => true, 'cache_wsdl' => WSDL_CACHE_NONE]); + echo "parsed ok\n"; +} catch (Throwable $e) { + echo $e::class, ": ", substr($e->getMessage(), 0, 120), "\n"; +} +echo "done\n"; +?> +--CLEAN-- + +--EXPECTF-- +SoapFault: SOAP-ERROR: Parsing Schema: recursive group 'ref' attribute '%s' +done