CVE-2016-7129: Improper Input Validation (CWE-20)
value: The php_wddx_process_data function in ext/wddx/wddx.c in PHP before 5.6.25 and 7.x before 7.0.10 allows remote attackers to cause a denial of service (segmentation fault) or possibly have unspecified other impact via an invalid ISO 8601 time value, as demonstrated by a wddx_deserialize call that mishandles a dateTime element in a wddxPacket XML document.
CWE description: The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
CVSS v3 base score: 9.8
Published: 2016-09-12T01:59Z
Repository: https://github.com/php/php-src
Language: C
Files changed: ext/wddx/tests/bug72749.phpt, ext/wddx/wddx.c
Commit date: 2016-08-16 22:55:19 -0700
Commit message: Fix bug #72749: wddx_deserialize allows illegal memory access

Diff: diff --git a/ext/wddx/tests/bug72749.phpt b/ext/wddx/tests/bug72749.phpt
new file mode 100644
index 00000000000..ee17d0f2295
--- /dev/null
+++ b/ext/wddx/tests/bug72749.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Bug #72749: wddx_deserialize allows illegal memory access
+--SKIPIF--
+<?php
+if (!extension_loaded('wddx')) {
+    die('skip. wddx not available');
+}
+?>
+--FILE--
+<?php
+$xml = <<<XML
+<?xml version='1.0'?>
+<!DOCTYPE wddxPacket SYSTEM 'wddx_0100.dtd'>
+<wddxPacket version='1.0'>
+<header/>
+        <data>
+                <struct>
+                     <var name='aDateTime3'>
+                         <dateTime>2\r2004-09-10T05:52:49+00</dateTime>
+                     </var>
+                 </struct>
+        </data>
+</wddxPacket>
+XML;
+
+$array = wddx_deserialize($xml);
+var_dump($array);
+?>
+--EXPECT--
+array(1) {
+  ["aDateTime3"]=>
+  string(24) "2
+2004-09-10T05:52:49+00"
+}
diff --git a/ext/wddx/wddx.c b/ext/wddx/wddx.c
index cde3e074064..faadbfe1dfe 100644
--- a/ext/wddx/wddx.c
+++ b/ext/wddx/wddx.c
@@ -1121,22 +1121,30 @@ static void php_wddx_process_data(void *user_data, const XML_Char *s, int len)
 				break;
 
 			case ST_DATETIME: {
 				char *tmp;
 
-				tmp = emalloc(len + 1);
-				memcpy(tmp, s, len);
+				if (Z_TYPE_P(ent->data) == IS_STRING) {
+					tmp = safe_emalloc(Z_STRLEN_P(ent->data), 1, (size_t)len + 1);
+					memcpy(tmp, Z_STRVAL_P(ent->data), Z_STRLEN_P(ent->data));
+					memcpy(tmp + Z_STRLEN_P(ent->data), s, len);
+					len += Z_STRLEN_P(ent->data);
+					efree(Z_STRVAL_P(ent->data));
+					Z_TYPE_P(ent->data) = IS_LONG;
+				} else {
+					tmp = emalloc(len + 1);
+					memcpy(tmp, s, len);
+				}
 				tmp[len] = '\0';
 
 				Z_LVAL_P(ent->data) = php_parse_date(tmp, NULL);
 				/* date out of range < 1969 or > 2038 */
 				if (Z_LVAL_P(ent->data) == -1) {
-					Z_TYPE_P(ent->data) = IS_STRING;
-					Z_STRLEN_P(ent->data) = len;
-					Z_STRVAL_P(ent->data) = estrndup(s, len);
+					ZVAL_STRINGL(ent->data, tmp, len, 0);
+				} else {
+					efree(tmp);
 				}
-				efree(tmp);
 			}
 				break;
 
 			default:
 				break;

Vulnerable code: 				tmp = emalloc(len + 1);
				memcpy(tmp, s, len);
					Z_TYPE_P(ent->data) = IS_STRING;
					Z_STRLEN_P(ent->data) = len;
					Z_STRVAL_P(ent->data) = estrndup(s, len);
				efree(tmp);
Fixed code: --TEST--
Bug #72749: wddx_deserialize allows illegal memory access
--SKIPIF--
<?php
if (!extension_loaded('wddx')) {
    die('skip. wddx not available');
}
?>
--FILE--
<?php
$xml = <<<XML
<?xml version='1.0'?>
<!DOCTYPE wddxPacket SYSTEM 'wddx_0100.dtd'>
<wddxPacket version='1.0'>
<header/>
        <data>
                <struct>
                     <var name='aDateTime3'>
                         <dateTime>2\r2004-09-10T05:52:49+00</dateTime>
                     </var>
                 </struct>
        </data>
</wddxPacket>
XML;

$array = wddx_deserialize($xml);
var_dump($array);
?>
--EXPECT--
array(1) {
  ["aDateTime3"]=>
  string(24) "2
2004-09-10T05:52:49+00"
}
				if (Z_TYPE_P(ent->data) == IS_STRING) {
					tmp = safe_emalloc(Z_STRLEN_P(ent->data), 1, (size_t)len + 1);
					memcpy(tmp, Z_STRVAL_P(ent->data), Z_STRLEN_P(ent->data));
					memcpy(tmp + Z_STRLEN_P(ent->data), s, len);
					len += Z_STRLEN_P(ent->data);
					efree(Z_STRVAL_P(ent->data));
					Z_TYPE_P(ent->data) = IS_LONG;
				} else {
					tmp = emalloc(len + 1);
					memcpy(tmp, s, len);
				}
					ZVAL_STRINGL(ent->data, tmp, len, 0);
				} else {
					efree(tmp);