summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStanislav Malyshev <stas@php.net>2015-08-31 21:06:03 -0700
committerStanislav Malyshev <stas@php.net>2015-08-31 21:06:03 -0700
commite201f01ac17243a1e5fb6a3911ed8e21b1619ac1 (patch)
tree5fc10af6c31d23073922129036b86d73f672cec7
parentf9c2bf73adb2ede0a486b0db466c264f2b27e0bb (diff)
downloadphp-git-e201f01ac17243a1e5fb6a3911ed8e21b1619ac1.tar.gz
Fix bug #70388 - SOAP serialize_function_call() type confusion
-rw-r--r--ext/soap/soap.c96
-rw-r--r--ext/soap/tests/bug70388.phpt17
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