summaryrefslogtreecommitdiffstats
path: root/bug71587.patch
blob: cd1c16b282e4e6089f91cc5c422fce8ba8a6d06a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
Backported from 5.5 for 5.4 by Remi Collet
Backported from 5.5 for 5.4 by Remi Collet

From b1bd4119bcafab6f9a8f84d92cd65eec3afeface Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <stas@php.net>
Date: Sun, 14 Feb 2016 22:34:39 -0800
Subject: [PATCH] Fixed bug #71587 - Use-After-Free / Double-Free in WDDX
 Deserialize

---
 ext/wddx/tests/bug71587.phpt | 43 +++++++++++++++++++++++++++++++++++++++++++
 ext/wddx/wddx.c              | 19 +++++++++++++++----
 2 files changed, 58 insertions(+), 4 deletions(-)
 create mode 100644 ext/wddx/tests/bug71587.phpt

diff --git a/ext/wddx/tests/bug71587.phpt b/ext/wddx/tests/bug71587.phpt
new file mode 100644
index 0000000..3fdfc35
--- /dev/null
+++ b/ext/wddx/tests/bug71587.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Bug #71587 (Use-After-Free / Double-Free in WDDX Deserialize)
+--SKIPIF--
+<?php
+if (!extension_loaded("wddx")) print "skip";
+?>
+--FILE--
+<?php
+
+$xml = <<<EOF
+<?xml version='1.0' ?>
+<!DOCTYPE wddxPacket SYSTEM 'wddx_0100.dtd'>
+<wddxPacket version='1.0'>
+    <array>
+         <var name='ML'></var>
+            <string>manhluat</string>
+         <var name='ML2'></var>
+         	<boolean value='a'/>
+         <boolean value='true'/>
+    </array>
+</wddxPacket>
+EOF;
+
+$wddx = wddx_deserialize($xml);
+var_dump($wddx);
+// Print mem leak
+foreach($wddx as $k=>$v)
+	printf("Key: %s\nValue: %s\n",bin2hex($k),bin2hex($v));
+
+?>
+DONE
+--EXPECTF--
+array(2) {
+  [0]=>
+  string(8) "manhluat"
+  [1]=>
+  bool(true)
+}
+Key: 30
+Value: 6d616e686c756174
+Key: 31
+Value: 31
+DONE
diff --git a/ext/wddx/wddx.c b/ext/wddx/wddx.c
index 7267ee1..da34246 100644
--- a/ext/wddx/wddx.c
+++ b/ext/wddx/wddx.c
@@ -936,6 +936,16 @@ static void php_wddx_pop_element(void *user_data, const XML_Char *name)
 		!strcmp(name, EL_DATETIME)) {
 		wddx_stack_top(stack, (void**)&ent1);
 
+		if (!ent1->data) {
+			if (stack->top > 1) {
+				stack->top--;
+			} else {
+				stack->done = 1;
+			}
+			efree(ent1);
+			return;
+		}
+
 		if (!strcmp(name, EL_BINARY)) {
 			int new_len=0;
 			unsigned char *new_str;
@@ -1032,6 +1042,7 @@ static void php_wddx_pop_element(void *user_data, const XML_Char *name)
 		}
 	} else if (!strcmp(name, EL_VAR) && stack->varname) {
 		efree(stack->varname);
+		stack->varname = NULL;
 	} else if (!strcmp(name, EL_FIELD)) {
 		st_entry *ent;
 		wddx_stack_top(stack, (void **)&ent);
@@ -1051,7 +1062,7 @@ static void php_wddx_process_data(void *user_data, const XML_Char *s, int len)
 
 	if (!wddx_stack_is_empty(stack) && !stack->done) {
 		wddx_stack_top(stack, (void**)&ent);
-		switch (Z_TYPE_P(ent)) {
+		switch (ent->type) {
 			case ST_STRING: 
 				if (Z_STRLEN_P(ent->data) == 0) {
 					STR_FREE(Z_STRVAL_P(ent->data));
@@ -1090,11 +1101,11 @@ static void php_wddx_process_data(void *user_data, const XML_Char *s, int len)
 				} else if (!strcmp(s, "false")) {
 					Z_LVAL_P(ent->data) = 0;
 				} else {
-					stack->top--;
 					zval_ptr_dtor(&ent->data);
-					if (ent->varname)
+					if (ent->varname) {
 						efree(ent->varname);
-					efree(ent);
+					}
+					ent->data = NULL;
 				}
 				break;