From ecc23c3bc51ebb7696db691352381625c9a56908 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Tue, 10 Sep 2024 22:44:56 +0200 Subject: [PATCH] Fix bug #62900: Wrong namespace on xsd import error message The one error message indeed had a wrong namespace, and in general they weren't very descriptive, this also makes them more descriptive. Furthermore, two additional bugs were fixed: - Persistent memory leak of `location`. - UAF issues when printing the error message. --- ext/soap/php_schema.c | 27 ++++++++- ext/soap/tests/bugs/bug62900.phpt | 95 +++++++++++++++++++++++++++++++ ext/soap/tests/bugs/bug62900_run | 2 + 3 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 ext/soap/tests/bugs/bug62900.phpt create mode 100644 ext/soap/tests/bugs/bug62900_run diff --git a/ext/soap/php_schema.c b/ext/soap/php_schema.c index 17ece4fe770f8..423714545ae30 100644 --- a/ext/soap/php_schema.c +++ b/ext/soap/php_schema.c @@ -92,6 +92,13 @@ static encodePtr get_create_encoder(sdlPtr sdl, sdlTypePtr cur_type, const xmlCh return enc; } +/* Necessary for some error paths to avoid leaking persistent memory. */ +static void requestify_string(xmlChar **str) { + xmlChar *copy = (xmlChar *) estrdup((const char *) *str); + xmlFree(*str); + *str = copy; +} + static void schema_load_file(sdlCtx *ctx, xmlAttrPtr ns, xmlChar *location, xmlAttrPtr tns, int import) { if (location != NULL && !zend_hash_str_exists(&ctx->docs, (char*)location, xmlStrlen(location))) { @@ -104,22 +111,35 @@ static void schema_load_file(sdlCtx *ctx, xmlAttrPtr ns, xmlChar *location, xmlA sdl_restore_uri_credentials(ctx); if (doc == NULL) { + requestify_string(&location); soap_error1(E_ERROR, "Parsing Schema: can't import schema from '%s'", location); } schema = get_node(doc->children, "schema"); if (schema == NULL) { + requestify_string(&location); xmlFreeDoc(doc); soap_error1(E_ERROR, "Parsing Schema: can't import schema from '%s'", location); } new_tns = get_attribute(schema->properties, "targetNamespace"); if (import) { if (ns != NULL && (new_tns == NULL || xmlStrcmp(ns->children->content, new_tns->children->content) != 0)) { - xmlFreeDoc(doc); - soap_error2(E_ERROR, "Parsing Schema: can't import schema from '%s', unexpected 'targetNamespace'='%s'", location, ns->children->content); + requestify_string(&location); + if (new_tns == NULL) { + xmlFreeDoc(doc); + soap_error2(E_ERROR, "Parsing Schema: can't import schema from '%s', missing 'targetNamespace', expected '%s'", location, ns->children->content); + } else { + /* Have to make a copy to avoid a UAF after freeing `doc` */ + const char *target_ns_copy = estrdup((const char *) new_tns->children->content); + xmlFreeDoc(doc); + soap_error3(E_ERROR, "Parsing Schema: can't import schema from '%s', unexpected 'targetNamespace'='%s', expected '%s'", location, target_ns_copy, ns->children->content); + } } if (ns == NULL && new_tns != NULL) { + requestify_string(&location); + /* Have to make a copy to avoid a UAF after freeing `doc` */ + const char *target_ns_copy = estrdup((const char *) new_tns->children->content); xmlFreeDoc(doc); - soap_error2(E_ERROR, "Parsing Schema: can't import schema from '%s', unexpected 'targetNamespace'='%s'", location, new_tns->children->content); + soap_error2(E_ERROR, "Parsing Schema: can't import schema from '%s', unexpected 'targetNamespace'='%s', expected no 'targetNamespace'", location, target_ns_copy); } } else { new_tns = get_attribute(schema->properties, "targetNamespace"); @@ -128,6 +148,7 @@ static void schema_load_file(sdlCtx *ctx, xmlAttrPtr ns, xmlChar *location, xmlA xmlSetProp(schema, BAD_CAST("targetNamespace"), tns->children->content); } } else if (tns != NULL && xmlStrcmp(tns->children->content, new_tns->children->content) != 0) { + requestify_string(&location); xmlFreeDoc(doc); soap_error1(E_ERROR, "Parsing Schema: can't include schema from '%s', different 'targetNamespace'", location); } diff --git a/ext/soap/tests/bugs/bug62900.phpt b/ext/soap/tests/bugs/bug62900.phpt new file mode 100644 index 0000000000000..c78afda5304af --- /dev/null +++ b/ext/soap/tests/bugs/bug62900.phpt @@ -0,0 +1,95 @@ +--TEST-- +Bug #62900 (Wrong namespace on xsd import error message) +--EXTENSIONS-- +soap +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- + + + + + + + +XML; + +$wsdl_without_ns = << + + + + + + +XML; + +$xsd_with_wrong_ns = << + +XML; + +$xsd_without_ns = << + +XML; + +$combinations = [ + [$wsdl_with_ns, $xsd_with_wrong_ns], + [$wsdl_with_ns, $xsd_without_ns], + [$wsdl_without_ns, $xsd_with_wrong_ns], + [$wsdl_without_ns, $xsd_without_ns], +]; + +chdir(__DIR__); + +$args = ["-d", "display_startup_errors=0", "-d", "extension_dir=" . ini_get("extension_dir"), "-d", "extension=" . (substr(PHP_OS, 0, 3) == "WIN" ? "php_" : "") . "soap." . PHP_SHLIB_SUFFIX]; +if (php_ini_loaded_file()) { + // Necessary such that it works from a development directory in which case extension_dir might not be the real extension dir + $args[] = "-c"; + $args[] = php_ini_loaded_file(); +} + +foreach ($combinations as list($wsdl, $xsd)) { + file_put_contents(__DIR__."/bug62900.wsdl", $wsdl); + file_put_contents(__DIR__."/bug62900.xsd", $xsd); + + $proc = proc_open([PHP_BINARY, ...$args, __DIR__.'/bug62900_run'], [1 => ["pipe", "w"], 2 => ["pipe", "w"]], $pipes); + echo stream_get_contents($pipes[1]); + fclose($pipes[1]); + proc_close($proc); +} + +?> +--CLEAN-- + +--EXPECTF-- +Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing Schema: can't import schema from '%sbug62900.xsd', unexpected 'targetNamespace'='http://www.w3.org/XML/1998/namespacex', expected 'http://www.w3.org/XML/1998/namespace' in %s:%d +Stack trace: +#0 %s(%d): SoapClient->__construct(%s) +#1 {main} + thrown in %s on line %d + +Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing Schema: can't import schema from '%sbug62900.xsd', missing 'targetNamespace', expected 'http://www.w3.org/XML/1998/namespace' in %s:%d +Stack trace: +#0 %s(%d): SoapClient->__construct(%s) +#1 {main} + thrown in %s on line %d + +Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing Schema: can't import schema from '%sbug62900.xsd', unexpected 'targetNamespace'='http://www.w3.org/XML/1998/namespacex', expected no 'targetNamespace' in %s:%d +Stack trace: +#0 %s(%d): SoapClient->__construct(%s) +#1 {main} + thrown in %s on line %d + +Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Couldn't bind to service in %s:%d +Stack trace: +#0 %s(%d): SoapClient->__construct(%s) +#1 {main} + thrown in %s on line %d diff --git a/ext/soap/tests/bugs/bug62900_run b/ext/soap/tests/bugs/bug62900_run new file mode 100644 index 0000000000000..0b7f7a0f33a98 --- /dev/null +++ b/ext/soap/tests/bugs/bug62900_run @@ -0,0 +1,2 @@ +