]> granicus.if.org Git - php/commitdiff
Fix persistent XML memory leaks in SOAP
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 27 Jun 2019 08:57:49 +0000 (10:57 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 27 Jun 2019 12:20:10 +0000 (14:20 +0200)
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
ext/soap/php_sdl.c
ext/soap/soap.c

index e88012af525ae293c17bf4d2552c7caf8ee1986d..7e8a5da935634d9583b8d25b56122d1f88263b89 100644 (file)
@@ -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);
                                        }
index 510d03c551e15965581234791c23031f19c72987..82fbd3bb20a7651a676a5d87c777759c64378d63 100644 (file)
@@ -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);
index 61f98e93251305aebd0016445f1874d018fad97b..5f8e28d535ed550042fff6dbbf08c5fc53a23996 100644 (file)
@@ -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, &params, &soap_version, &soap_headers);
+
+       zend_try {
+               function = deserialize_function_call(service->sdl, doc_request, service->actor, &function_name, &num_params, &params, &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;
 }
 /* }}} */