From 552e8b2b4c5708cb90faf148bd99e3f67fa926b5 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov <dmitry@zend.com> Date: Tue, 10 Dec 2013 17:57:05 +0400 Subject: [PATCH] Fixed bug #66112 (Use after free condition in SOAP extension). (martin dot koegler at brz dot gv dot at) --- NEWS | 4 + ext/soap/soap.c | 197 ++++++++++++++++-------------- ext/soap/tests/bugs/bug66112.phpt | 35 ++++++ ext/soap/tests/bugs/bug66112.wsdl | 42 +++++++ 4 files changed, 184 insertions(+), 94 deletions(-) create mode 100644 ext/soap/tests/bugs/bug66112.phpt create mode 100644 ext/soap/tests/bugs/bug66112.wsdl diff --git a/NEWS b/NEWS index 0d6edf25c7..1e7ce53148 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,10 @@ PHP NEWS - Filter: . Fixed bug #66229 (128.0.0.0/16 isn't reserved any longer). (Adam) +- SOAP + . Fixed bug #66112 (Use after free condition in SOAP extension). + (martin dot koegler at brz dot gv dot at) + - Sockets: . Fixed bug #65923 (ext/socket assumes AI_V4MAPPED is defined). (Felipe) diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 0404096774..3448df4ea7 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -2694,124 +2694,133 @@ static void do_soap_call(zval* this_ptr, SOAP_GLOBAL(features) = 0; } - if (sdl != NULL) { - fn = get_function(sdl, function); - if (fn != NULL) { - sdlBindingPtr binding = fn->binding; - int one_way = 0; - - if (fn->responseName == NULL && - fn->responseParameters == NULL && - soap_headers == NULL) { - one_way = 1; - } + zend_try { + if (sdl != NULL) { + fn = get_function(sdl, function); + if (fn != NULL) { + sdlBindingPtr binding = fn->binding; + int one_way = 0; + + if (fn->responseName == NULL && + fn->responseParameters == NULL && + soap_headers == NULL) { + one_way = 1; + } - if (location == NULL) { - location = binding->location; - } - if (binding->bindingType == BINDING_SOAP) { - sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)fn->bindingAttributes; - request = serialize_function_call(this_ptr, fn, NULL, fnb->input.ns, real_args, arg_count, soap_version, soap_headers TSRMLS_CC); - ret = do_request(this_ptr, request, location, fnb->soapAction, soap_version, one_way, &response TSRMLS_CC); - } else { - request = serialize_function_call(this_ptr, fn, NULL, sdl->target_ns, real_args, arg_count, soap_version, soap_headers TSRMLS_CC); - ret = do_request(this_ptr, request, location, NULL, soap_version, one_way, &response TSRMLS_CC); - } - - xmlFreeDoc(request); - - if (ret && Z_TYPE(response) == IS_STRING) { - encode_reset_ns(); - ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), fn, NULL, return_value, output_headers TSRMLS_CC); - encode_finish(); - } + if (location == NULL) { + location = binding->location; + } + if (binding->bindingType == BINDING_SOAP) { + sdlSoapBindingFunctionPtr fnb = (sdlSoapBindingFunctionPtr)fn->bindingAttributes; + request = serialize_function_call(this_ptr, fn, NULL, fnb->input.ns, real_args, arg_count, soap_version, soap_headers TSRMLS_CC); + ret = do_request(this_ptr, request, location, fnb->soapAction, soap_version, one_way, &response TSRMLS_CC); + } else { + request = serialize_function_call(this_ptr, fn, NULL, sdl->target_ns, real_args, arg_count, soap_version, soap_headers TSRMLS_CC); + ret = do_request(this_ptr, request, location, NULL, soap_version, one_way, &response TSRMLS_CC); + } + + xmlFreeDoc(request); + + if (ret && Z_TYPE(response) == IS_STRING) { + encode_reset_ns(); + ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), fn, NULL, return_value, output_headers TSRMLS_CC); + encode_finish(); + } - zval_dtor(&response); + zval_dtor(&response); - } else { - smart_str error = {0}; - smart_str_appends(&error,"Function (\""); - smart_str_appends(&error,function); - smart_str_appends(&error,"\") is not a valid method for this service"); - smart_str_0(&error); - add_soap_fault(this_ptr, "Client", error.c, NULL, NULL TSRMLS_CC); - smart_str_free(&error); - } - } else { - zval **uri; - smart_str action = {0}; - - if (zend_hash_find(Z_OBJPROP_P(this_ptr), "uri", sizeof("uri"), (void *)&uri) == FAILURE) { - add_soap_fault(this_ptr, "Client", "Error finding \"uri\" property", NULL, NULL TSRMLS_CC); - } else if (location == NULL) { - add_soap_fault(this_ptr, "Client", "Error could not find \"location\" property", NULL, NULL TSRMLS_CC); - } else { - if (call_uri == NULL) { - call_uri = Z_STRVAL_PP(uri); + } else { + smart_str error = {0}; + smart_str_appends(&error,"Function (\""); + smart_str_appends(&error,function); + smart_str_appends(&error,"\") is not a valid method for this service"); + smart_str_0(&error); + add_soap_fault(this_ptr, "Client", error.c, NULL, NULL TSRMLS_CC); + smart_str_free(&error); } - request = serialize_function_call(this_ptr, NULL, function, call_uri, real_args, arg_count, soap_version, soap_headers TSRMLS_CC); + } else { + zval **uri; + smart_str action = {0}; - if (soap_action == NULL) { - smart_str_appends(&action, call_uri); - smart_str_appendc(&action, '#'); - smart_str_appends(&action, function); + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "uri", sizeof("uri"), (void *)&uri) == FAILURE) { + add_soap_fault(this_ptr, "Client", "Error finding \"uri\" property", NULL, NULL TSRMLS_CC); + } else if (location == NULL) { + add_soap_fault(this_ptr, "Client", "Error could not find \"location\" property", NULL, NULL TSRMLS_CC); } else { - smart_str_appends(&action, soap_action); - } - smart_str_0(&action); + if (call_uri == NULL) { + call_uri = Z_STRVAL_PP(uri); + } + request = serialize_function_call(this_ptr, NULL, function, call_uri, real_args, arg_count, soap_version, soap_headers TSRMLS_CC); - ret = do_request(this_ptr, request, location, action.c, soap_version, 0, &response TSRMLS_CC); + if (soap_action == NULL) { + smart_str_appends(&action, call_uri); + smart_str_appendc(&action, '#'); + smart_str_appends(&action, function); + } else { + smart_str_appends(&action, soap_action); + } + smart_str_0(&action); - smart_str_free(&action); - xmlFreeDoc(request); + ret = do_request(this_ptr, request, location, action.c, soap_version, 0, &response TSRMLS_CC); - if (ret && Z_TYPE(response) == IS_STRING) { - encode_reset_ns(); - ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), NULL, function, return_value, output_headers TSRMLS_CC); - encode_finish(); - } + smart_str_free(&action); + xmlFreeDoc(request); - zval_dtor(&response); - } - } + if (ret && Z_TYPE(response) == IS_STRING) { + encode_reset_ns(); + ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), NULL, function, return_value, output_headers TSRMLS_CC); + encode_finish(); + } - if (!ret) { - zval** fault; - if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault"), (void **) &fault) == SUCCESS) { - *return_value = **fault; - zval_copy_ctor(return_value); + zval_dtor(&response); + } + } + + if (!ret) { + zval** fault; + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault"), (void **) &fault) == SUCCESS) { + *return_value = **fault; + zval_copy_ctor(return_value); + } else { + *return_value = *add_soap_fault(this_ptr, "Client", "Unknown Error", NULL, NULL TSRMLS_CC); + zval_copy_ctor(return_value); + } } else { - *return_value = *add_soap_fault(this_ptr, "Client", "Unknown Error", NULL, NULL TSRMLS_CC); - zval_copy_ctor(return_value); - } - } else { - zval** fault; - if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault"), (void **) &fault) == SUCCESS) { - *return_value = **fault; - zval_copy_ctor(return_value); + zval** fault; + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault"), (void **) &fault) == SUCCESS) { + *return_value = **fault; + zval_copy_ctor(return_value); + } } - } - if (!EG(exception) && - Z_TYPE_P(return_value) == IS_OBJECT && - instanceof_function(Z_OBJCE_P(return_value), soap_fault_class_entry TSRMLS_CC) && - (zend_hash_find(Z_OBJPROP_P(this_ptr), "_exceptions", sizeof("_exceptions"), (void **) &tmp) != SUCCESS || - Z_TYPE_PP(tmp) != IS_BOOL || Z_LVAL_PP(tmp) != 0)) { - zval *exception; + if (!EG(exception) && + Z_TYPE_P(return_value) == IS_OBJECT && + instanceof_function(Z_OBJCE_P(return_value), soap_fault_class_entry TSRMLS_CC) && + (zend_hash_find(Z_OBJPROP_P(this_ptr), "_exceptions", sizeof("_exceptions"), (void **) &tmp) != SUCCESS || + Z_TYPE_PP(tmp) != IS_BOOL || Z_LVAL_PP(tmp) != 0)) { + zval *exception; - MAKE_STD_ZVAL(exception); - MAKE_COPY_ZVAL(&return_value, exception); - zend_throw_exception_object(exception TSRMLS_CC); - } + MAKE_STD_ZVAL(exception); + MAKE_COPY_ZVAL(&return_value, exception); + zend_throw_exception_object(exception TSRMLS_CC); + } + } zend_catch { + _bailout = 1; + } zend_end_try(); + if (SOAP_GLOBAL(encoding) != NULL) { xmlCharEncCloseFunc(SOAP_GLOBAL(encoding)); } + SOAP_GLOBAL(features) = old_features; SOAP_GLOBAL(typemap) = old_typemap; SOAP_GLOBAL(class_map) = old_class_map; SOAP_GLOBAL(encoding) = old_encoding; SOAP_GLOBAL(sdl) = old_sdl; + if (_bailout) { + zend_bailout(); + } SOAP_CLIENT_END_CODE(); } diff --git a/ext/soap/tests/bugs/bug66112.phpt b/ext/soap/tests/bugs/bug66112.phpt new file mode 100644 index 0000000000..6df3a4eedf --- /dev/null +++ b/ext/soap/tests/bugs/bug66112.phpt @@ -0,0 +1,35 @@ +--TEST-- +Bug #66112 (Use after free condition in SOAP extension) +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--INI-- +soap.wsdl_cache_enabled=0 +--FILE-- +<?php +define('WSDL', dirname(__FILE__)."/bug66112.wsdl"); +function Mist($p) { + $client=new soapclient(WSDL, array('typemap'=>array(array("type_ns"=>"uri:mist", "type_name"=>"A")))); + try{ + $client->Mist(array("XX"=>"xx")); + }catch(SoapFault $x){ + } + return array("A"=>"ABC","B"=>"sss"); +} +$s = new SoapServer(WSDL, array('typemap'=>array(array("type_ns"=>"uri:mist", "type_name"=>"A")))); +$s->addFunction("Mist"); +$_SERVER["REQUEST_METHOD"] = "POST"; +$HTTP_RAW_POST_DATA=<<<EOF +<?xml version="1.0" encoding="UTF-8"?> +<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:uri="uri:mist"> + <soapenv:Header/> + <soapenv:Body> + <uri:Request><uri:A>XXX</uri:A><uri:B>yyy</uri:B></uri:Request> + </soapenv:Body> +</soapenv:Envelope> +EOF; +echo "OK\n"; +$s->handle($HTTP_RAW_POST_DATA); +echo "BUG\n"; +?> +--EXPECT-- +OK diff --git a/ext/soap/tests/bugs/bug66112.wsdl b/ext/soap/tests/bugs/bug66112.wsdl new file mode 100644 index 0000000000..8589a46bf2 --- /dev/null +++ b/ext/soap/tests/bugs/bug66112.wsdl @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<wsdl:definitions xmlns:tns="uri:mist" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="test" targetNamespace="uri:mist"> + <wsdl:types> + <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="uri:mist"> + <xs:complexType name="T1"> + <xs:sequence> + <xs:element name="A" type="xsd:string"/><xs:element name="B" type="xsd:string"/> + </xs:sequence> + </xs:complexType> + <xs:element name="Request" type="tns:T1"/><xs:element name="Response" type="tns:T1"/> + </xs:schema> + </wsdl:types> + <wsdl:message name="Request"> + <wsdl:part name="Request" element="tns:Request"/> + </wsdl:message> + <wsdl:message name="Response"> + <wsdl:part name="Response" element="tns:Response"/> + </wsdl:message> + <wsdl:portType name="test"> + <wsdl:operation name="Mist"> + <wsdl:input message="tns:Request"/> + <wsdl:output message="tns:Response"/> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="test" type="tns:test"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> + <wsdl:operation name="Mist"> + <soap:operation soapAction="Mist"/> + <wsdl:input> + <soap:body use="literal"/> + </wsdl:input> + <wsdl:output> + <soap:body use="literal"/> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:service name="test"> + <wsdl:port name="test" binding="tns:test"> + <soap:address location="http://127.0.0.1:81/mist.php"/> + </wsdl:port> + </wsdl:service> +</wsdl:definitions> -- 2.40.0