diff options
author | Stanislav Malyshev <stas@php.net> | 2015-08-31 21:06:03 -0700 |
---|---|---|
committer | Stanislav Malyshev <stas@php.net> | 2015-08-31 21:06:03 -0700 |
commit | e201f01ac17243a1e5fb6a3911ed8e21b1619ac1 (patch) | |
tree | 5fc10af6c31d23073922129036b86d73f672cec7 | |
parent | f9c2bf73adb2ede0a486b0db466c264f2b27e0bb (diff) | |
download | php-git-e201f01ac17243a1e5fb6a3911ed8e21b1619ac1.tar.gz |
Fix bug #70388 - SOAP serialize_function_call() type confusion
-rw-r--r-- | ext/soap/soap.c | 96 | ||||
-rw-r--r-- | ext/soap/tests/bug70388.phpt | 17 |
2 files changed, 69 insertions, 44 deletions
diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 1b8f545b85..a0e64a3900 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -989,7 +989,7 @@ static HashTable* soap_create_typemap(sdlPtr sdl, HashTable *ht TSRMLS_DC) HashTable *ht2; HashPosition pos1, pos2; HashTable *typemap = NULL; - + zend_hash_internal_pointer_reset_ex(ht, &pos1); while (zend_hash_get_current_data_ex(ht, (void**)&tmp, &pos1) == SUCCESS) { char *type_name = NULL; @@ -1033,7 +1033,7 @@ static HashTable* soap_create_typemap(sdlPtr sdl, HashTable *ht TSRMLS_DC) } } zend_hash_move_forward_ex(ht2, &pos2); - } + } if (type_name) { smart_str nscat = {0}; @@ -1063,7 +1063,7 @@ static HashTable* soap_create_typemap(sdlPtr sdl, HashTable *ht TSRMLS_DC) new_enc->to_xml = enc->to_xml; new_enc->to_zval = enc->to_zval; new_enc->details.map = emalloc(sizeof(soapMapping)); - memset(new_enc->details.map, 0, sizeof(soapMapping)); + memset(new_enc->details.map, 0, sizeof(soapMapping)); if (to_xml) { zval_add_ref(&to_xml); new_enc->details.map->to_xml = to_xml; @@ -1120,7 +1120,7 @@ PHP_METHOD(SoapServer, SoapServer) if (Z_TYPE_P(wsdl) != IS_STRING && Z_TYPE_P(wsdl) != IS_NULL) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid parameters"); } - + service = emalloc(sizeof(soapService)); memset(service, 0, sizeof(soapService)); service->send_errors = 1; @@ -1155,7 +1155,7 @@ PHP_METHOD(SoapServer, SoapServer) if (zend_hash_find(ht, "encoding", sizeof("encoding"), (void**)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) { xmlCharEncodingHandlerPtr encoding; - + encoding = xmlFindCharEncodingHandler(Z_STRVAL_PP(tmp)); if (encoding == NULL) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid 'encoding' option - '%s'", Z_STRVAL_PP(tmp)); @@ -1215,7 +1215,7 @@ PHP_METHOD(SoapServer, SoapServer) } } } - + if (typemap_ht) { service->typemap = soap_create_typemap(service->sdl, typemap_ht TSRMLS_CC); } @@ -1345,7 +1345,7 @@ PHP_METHOD(SoapServer, getFunctions) if (zend_parse_parameters_none() == FAILURE) { return; } - + FETCH_THIS_SERVICE(service); array_init(return_value); @@ -1505,7 +1505,7 @@ PHP_METHOD(SoapServer, handle) FETCH_THIS_SERVICE(service); SOAP_GLOBAL(soap_version) = service->version; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &arg, &arg_len) == FAILURE) { return; } @@ -1930,7 +1930,7 @@ PHP_METHOD(SoapServer, handle) if (size == 0) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Dump memory failed"); - } + } if (soap_version == SOAP_1_2) { sapi_add_header("Content-Type: application/soap+xml; charset=utf-8", sizeof("Content-Type: application/soap+xml; charset=utf-8")-1, 1); @@ -2147,10 +2147,10 @@ static void soap_error_handler(int error_num, const char *error_filename, const use_exceptions = 1; } - if ((error_num == E_USER_ERROR || - error_num == E_COMPILE_ERROR || + if ((error_num == E_USER_ERROR || + error_num == E_COMPILE_ERROR || error_num == E_CORE_ERROR || - error_num == E_ERROR || + error_num == E_ERROR || error_num == E_PARSE) && use_exceptions) { zval *fault, *exception; @@ -2219,10 +2219,10 @@ static void soap_error_handler(int error_num, const char *error_filename, const va_list argcopy; #endif - if (error_num == E_USER_ERROR || - error_num == E_COMPILE_ERROR || + if (error_num == E_USER_ERROR || + error_num == E_COMPILE_ERROR || error_num == E_CORE_ERROR || - error_num == E_ERROR || + error_num == E_ERROR || error_num == E_PARSE) { char* code = SOAP_GLOBAL(error_code); @@ -2452,13 +2452,13 @@ PHP_METHOD(SoapClient, SoapClient) if (zend_hash_find(ht, "encoding", sizeof("encoding"), (void**)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) { xmlCharEncodingHandlerPtr encoding; - + encoding = xmlFindCharEncodingHandler(Z_STRVAL_PP(tmp)); if (encoding == NULL) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid 'encoding' option - '%s'", Z_STRVAL_PP(tmp)); } else { xmlCharEncCloseFunc(encoding); - add_property_stringl(this_ptr, "_encoding", Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1); + add_property_stringl(this_ptr, "_encoding", Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1); } } if (zend_hash_find(ht, "classmap", sizeof("classmap"), (void**)&tmp) == SUCCESS && @@ -2493,7 +2493,7 @@ PHP_METHOD(SoapClient, SoapClient) if (context) { add_property_resource(this_ptr, "_stream_context", context->rsrc_id); } - + if (zend_hash_find(ht, "cache_wsdl", sizeof("cache_wsdl"), (void**)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_LONG) { cache_wsdl = Z_LVAL_PP(tmp); @@ -2503,7 +2503,7 @@ PHP_METHOD(SoapClient, SoapClient) Z_TYPE_PP(tmp) == IS_STRING) { add_property_stringl(this_ptr, "_user_agent", Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1); } - + if (zend_hash_find(ht, "keep_alive", sizeof("keep_alive"), (void**)&tmp) == SUCCESS && (Z_TYPE_PP(tmp) == IS_BOOL || Z_TYPE_PP(tmp) == IS_LONG) && Z_LVAL_PP(tmp) == 0) { add_property_long(this_ptr, "_keep_alive", 0); @@ -2606,7 +2606,7 @@ static int do_request(zval *this_ptr, xmlDoc *request, char *location, char *act xmlFree(buf); if (ret && zend_hash_find(Z_OBJPROP_P(this_ptr), "__soap_fault", sizeof("__soap_fault"), (void **) &fault) == SUCCESS) { return FALSE; - } + } return ret; } @@ -2903,8 +2903,10 @@ PHP_METHOD(SoapClient, __call) } zend_hash_internal_pointer_reset(default_headers); while (zend_hash_get_current_data(default_headers, (void**)&tmp) == SUCCESS) { - Z_ADDREF_PP(tmp); - zend_hash_next_index_insert(soap_headers, tmp, sizeof(zval *), NULL); + if(Z_TYPE_PP(tmp) == IS_OBJECT) { + Z_ADDREF_PP(tmp); + zend_hash_next_index_insert(soap_headers, tmp, sizeof(zval *), NULL); + } zend_hash_move_forward(default_headers); } } else { @@ -2912,7 +2914,7 @@ PHP_METHOD(SoapClient, __call) free_soap_headers = 0; } } - + arg_count = zend_hash_num_elements(Z_ARRVAL_P(args)); if (arg_count > 0) { @@ -2978,7 +2980,7 @@ PHP_METHOD(SoapClient, __getTypes) HashPosition pos; FETCH_THIS_SDL(sdl); - + if (zend_parse_parameters_none() == FAILURE) { return; } @@ -3007,7 +3009,7 @@ PHP_METHOD(SoapClient, __getTypes) PHP_METHOD(SoapClient, __getLastRequest) { zval **tmp; - + if (zend_parse_parameters_none() == FAILURE) { return; } @@ -3030,7 +3032,7 @@ PHP_METHOD(SoapClient, __getLastResponse) if (zend_parse_parameters_none() == FAILURE) { return; } - + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__last_response", sizeof("__last_response"), (void **)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) { RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1); @@ -3045,11 +3047,11 @@ PHP_METHOD(SoapClient, __getLastResponse) PHP_METHOD(SoapClient, __getLastRequestHeaders) { zval **tmp; - + if (zend_parse_parameters_none() == FAILURE) { return; } - + if (zend_hash_find(Z_OBJPROP_P(this_ptr), "__last_request_headers", sizeof("__last_request_headers"), (void **)&tmp) == SUCCESS && Z_TYPE_PP(tmp) == IS_STRING) { RETURN_STRINGL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), 1); @@ -3064,7 +3066,7 @@ PHP_METHOD(SoapClient, __getLastRequestHeaders) PHP_METHOD(SoapClient, __getLastResponseHeaders) { zval **tmp; - + if (zend_parse_parameters_none() == FAILURE) { return; } @@ -3209,10 +3211,10 @@ PHP_METHOD(SoapClient, __setSoapHeaders) /* {{{ proto string SoapClient::__setLocation([string new_location]) - Sets the location option (the endpoint URL that will be touched by the + Sets the location option (the endpoint URL that will be touched by the following SOAP requests). If new_location is not specified or null then SoapClient will use endpoint - from WSDL file. + from WSDL file. The function returns old value of location options. */ PHP_METHOD(SoapClient, __setLocation) { @@ -3261,10 +3263,10 @@ static void set_soap_fault(zval *obj, char *fault_code_ns, char *fault_code, cha if (Z_TYPE_P(obj) != IS_OBJECT) { object_init_ex(obj, soap_fault_class_entry); } - + add_property_string(obj, "faultstring", fault_string ? fault_string : "", 1); zend_update_property_string(zend_exception_get_default(TSRMLS_C), obj, "message", sizeof("message")-1, (fault_string ? fault_string : "") TSRMLS_CC); - + if (fault_code != NULL) { int soap_version = SOAP_GLOBAL(soap_version); @@ -3689,7 +3691,7 @@ ignore_header: func = func->children; } deserialize_parameters(func, function, num_params, parameters TSRMLS_CC); - + encode_finish(); return function; @@ -3971,8 +3973,8 @@ static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function } if (fault_ns == NULL && - fault && - fault->details && + fault && + fault->details && zend_hash_num_elements(fault->details) == 1) { sdlParamPtr sparam; @@ -3996,7 +3998,7 @@ static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function xmlChar *code = xmlBuildQName(BAD_CAST(str), nsptr->prefix, NULL, 0); xmlNodeSetContent(node, code); xmlFree(code); - } else { + } else { xmlNodeSetContentLen(node, BAD_CAST(str), (int)new_len); } efree(str); @@ -4022,7 +4024,7 @@ static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function xmlChar *code = xmlBuildQName(BAD_CAST(str), nsptr->prefix, NULL, 0); xmlNodeSetContent(node, code); xmlFree(code); - } else { + } else { xmlNodeSetContentLen(node, BAD_CAST(str), (int)new_len); } efree(str); @@ -4194,7 +4196,7 @@ static xmlDocPtr serialize_response_call(sdlFunctionPtr function, char *function encode_finish(); - if (function && function->responseName == NULL && + if (function && function->responseName == NULL && body->children == NULL && head == NULL) { xmlFreeDoc(doc); return NULL; @@ -4328,11 +4330,18 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function if (head) { zval** header; - zend_hash_internal_pointer_reset(soap_headers); - while (zend_hash_get_current_data(soap_headers,(void**)&header) == SUCCESS) { - HashTable *ht = Z_OBJPROP_PP(header); + for(zend_hash_internal_pointer_reset(soap_headers); + zend_hash_get_current_data(soap_headers,(void**)&header) == SUCCESS; + zend_hash_move_forward(soap_headers) + ) { + HashTable *ht; zval **name, **ns, **tmp; + if (Z_TYPE_PP(header) != IS_OBJECT) { + continue; + } + + ht = Z_OBJPROP_PP(header); if (zend_hash_find(ht, "name", sizeof("name"), (void**)&name) == SUCCESS && Z_TYPE_PP(name) == IS_STRING && zend_hash_find(ht, "namespace", sizeof("namespace"), (void**)&ns) == SUCCESS && @@ -4371,7 +4380,6 @@ static xmlDocPtr serialize_function_call(zval *this_ptr, sdlFunctionPtr function xmlSetNs(h, nsptr); set_soap_header_attributes(h, ht, version); } - zend_hash_move_forward(soap_headers); } } @@ -4482,7 +4490,7 @@ static sdlParamPtr get_param(sdlFunctionPtr function, char *param_name, int inde return *tmp; } else { HashPosition pos; - + zend_hash_internal_pointer_reset_ex(ht, &pos); while (zend_hash_get_current_data_ex(ht, (void **)&tmp, &pos) != FAILURE) { if ((*tmp)->paramName && strcmp(param_name, (*tmp)->paramName) == 0) { diff --git a/ext/soap/tests/bug70388.phpt b/ext/soap/tests/bug70388.phpt new file mode 100644 index 0000000000..49a8efc0ff --- /dev/null +++ b/ext/soap/tests/bug70388.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #70388 (SOAP serialize_function_call() type confusion / RCE) +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php +$dummy = unserialize('O:10:"SoapClient":3:{s:3:"uri";s:1:"X";s:8:"location";s:22:"http://localhost/a.xml";s:17:"__default_headers";a:1:{i:1;s:1337:"'.str_repeat("X", 1337).'";}}'); +try { + var_dump($dummy->notexisting()); +} catch(Exception $e) { + var_dump($e->getMessage()); + var_dump(get_class($e)); +} +?> +--EXPECTF-- +string(%d) "%s" +string(9) "SoapFault"
\ No newline at end of file |