From 78375aa52f1f2ae79e2d014f24e15b48ef72bea7 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 27 Jun 2019 10:57:49 +0200 Subject: [PATCH] Fix persistent XML memory leaks in SOAP SOAP uses a horrible bailout based error handling approach -- avoid leaking persistent XML memory by catching bailouts in a number of places. --- ext/soap/php_encoding.c | 8 +++++++- ext/soap/php_sdl.c | 10 +++++++++- ext/soap/soap.c | 36 ++++++++++++++++++++++++++++++------ 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index e88012af52..7e8a5da935 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -1519,7 +1519,13 @@ static zval *to_zval_object_ex(zval *ret, encodeTypePtr type, xmlNodePtr data, z text = xmlNewText(BAD_CAST(str_val)); xmlAddChild(dummy, text); ZVAL_NULL(&data); - master_to_zval(&data, attr->encode, dummy); + /* TODO: There are other places using dummy nodes -- generalize? */ + zend_try { + master_to_zval(&data, attr->encode, dummy); + } zend_catch { + xmlFreeNode(dummy); + zend_bailout(); + } zend_end_try(); xmlFreeNode(dummy); set_zval_property(ret, attr->name, &data); } diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c index 510d03c551..82fbd3bb20 100644 --- a/ext/soap/php_sdl.c +++ b/ext/soap/php_sdl.c @@ -739,7 +739,9 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri) zend_hash_init(&ctx.portTypes, 0, NULL, NULL, 0); zend_hash_init(&ctx.services, 0, NULL, NULL, 0); - load_wsdl_ex(this_ptr, struri,&ctx, 0); + load_wsdl_ex(this_ptr, struri, &ctx, 0); + zend_try { + schema_pass2(&ctx); n = zend_hash_num_elements(&ctx.services); @@ -1166,6 +1168,12 @@ static sdlPtr load_wsdl(zval *this_ptr, char *struri) soap_error0(E_ERROR, "Parsing WSDL: Could not find any usable binding services in WSDL."); } + } zend_catch { + /* Avoid persistent memory leak. */ + zend_hash_destroy(&ctx.docs); + zend_bailout(); + } zend_end_try(); + zend_hash_destroy(&ctx.messages); zend_hash_destroy(&ctx.bindings); zend_hash_destroy(&ctx.portTypes); diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 61f98e9325..5f8e28d535 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -1643,7 +1643,15 @@ PHP_METHOD(SoapServer, handle) old_features = SOAP_GLOBAL(features); SOAP_GLOBAL(features) = service->features; old_soap_version = SOAP_GLOBAL(soap_version); - function = deserialize_function_call(service->sdl, doc_request, service->actor, &function_name, &num_params, ¶ms, &soap_version, &soap_headers); + + zend_try { + function = deserialize_function_call(service->sdl, doc_request, service->actor, &function_name, &num_params, ¶ms, &soap_version, &soap_headers); + } zend_catch { + /* Avoid leaking persistent memory */ + xmlFreeDoc(doc_request); + zend_bailout(); + } zend_end_try(); + xmlFreeDoc(doc_request); if (EG(exception)) { @@ -3821,6 +3829,8 @@ static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function encode_reset_ns(); doc = xmlNewDoc(BAD_CAST("1.0")); + zend_try { + doc->charset = XML_CHAR_ENCODING_UTF8; doc->encoding = xmlCharStrdup("UTF-8"); @@ -4162,6 +4172,12 @@ static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function encode_finish(); + } zend_catch { + /* Avoid persistent memory leak. */ + xmlFreeDoc(doc); + zend_bailout(); + } zend_end_try(); + if (function && function->responseName == NULL && body->children == NULL && head == NULL) { xmlFreeDoc(doc); @@ -4183,6 +4199,8 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function encode_reset_ns(); doc = xmlNewDoc(BAD_CAST("1.0")); + zend_try { + doc->encoding = xmlCharStrdup("UTF-8"); doc->charset = XML_CHAR_ENCODING_UTF8; if (version == SOAP_1_1) { @@ -4222,7 +4240,7 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function } } else { if ((zstyle = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "style", sizeof("style")-1)) != NULL && - Z_TYPE_P(zstyle) == IS_LONG) { + Z_TYPE_P(zstyle) == IS_LONG) { style = Z_LVAL_P(zstyle); } else { style = SOAP_RPC; @@ -4245,7 +4263,7 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function } if ((zuse = zend_hash_str_find(Z_OBJPROP_P(this_ptr), "use", sizeof("use")-1)) != NULL && - Z_TYPE_P(zuse) == IS_LONG && Z_LVAL_P(zuse) == SOAP_LITERAL) { + Z_TYPE_P(zuse) == IS_LONG && Z_LVAL_P(zuse) == SOAP_LITERAL) { use = SOAP_LITERAL; } else { use = SOAP_ENCODED; @@ -4307,9 +4325,9 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function ht = Z_OBJPROP_P(header); if ((name = zend_hash_str_find(ht, "name", sizeof("name")-1)) != NULL && - Z_TYPE_P(name) == IS_STRING && - (ns = zend_hash_str_find(ht, "namespace", sizeof("namespace")-1)) != NULL && - Z_TYPE_P(ns) == IS_STRING) { + Z_TYPE_P(name) == IS_STRING && + (ns = zend_hash_str_find(ht, "namespace", sizeof("namespace")-1)) != NULL && + Z_TYPE_P(ns) == IS_STRING) { xmlNodePtr h; xmlNsPtr nsptr; int hdr_use = SOAP_LITERAL; @@ -4362,6 +4380,12 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function encode_finish(); + } zend_catch { + /* Avoid persistent memory leak. */ + xmlFreeDoc(doc); + zend_bailout(); + } zend_end_try(); + return doc; } /* }}} */ -- 2.50.1