components/php/php56/patches/CVE-2015-6836.patch
author Michael Nestler <Michael.Nestler@Oracle.COM>
Thu, 19 Nov 2015 22:52:15 -0800
changeset 5116 867d838118ad
permissions -rw-r--r--
22244227 problem in UTILITY/PHP 21577672 problem in UTILITY/PHP 22244239 problem in UTILITY/PHP 22244245 problem in UTILITY/PHP 22244247 problem in UTILITY/PHP 22244253 problem in UTILITY/PHP 22244256 problem in UTILITY/PHP 22244261 problem in UTILITY/PHP 22244265 problem in UTILITY/PHP 22244270 problem in UTILITY/PHP 22244277 problem in UTILITY/PHP 22244286 problem in UTILITY/PHP

# Source: upstream
# http://git.php.net/?p=php-src.git;a=commit;h=e201f01ac17243a1e5fb6a3911ed8e21b1619ac1
# https://bugs.php.net/bug.php?id=70388

From e201f01ac17243a1e5fb6a3911ed8e21b1619ac1 Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <[email protected]>
Date: Mon, 31 Aug 2015 21:06:03 -0700
Subject: [PATCH] Fix bug #70388 - SOAP serialize_function_call() type
 confusion

---
 ext/soap/soap.c              | 96 ++++++++++++++++++++++++--------------------
 ext/soap/tests/bug70388.phpt | 17 ++++++++
 2 files changed, 69 insertions(+), 44 deletions(-)
 create mode 100644 ext/soap/tests/bug70388.phpt

diff --git a/ext/soap/soap.c b/ext/soap/soap.c
index 1b8f545..a0e64a3 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 0000000..49a8efc
--- /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
-- 
2.1.4