summaryrefslogtreecommitdiffstats
path: root/bug73174.patch
blob: d67e3d9211045d301ef5913988395e36b3e10038 (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
Backported from 5.6.27 by Remi.


From 29e2a204fb42af061e66a9f847ffbc8f1d13897a Mon Sep 17 00:00:00 2001
From: Stanislav Malyshev <stas@php.net>
Date: Wed, 28 Sep 2016 22:29:25 -0700
Subject: [PATCH] Fixed bug #73174 - heap overflow in php_pcre_replace_impl

---
 ext/pcre/php_pcre.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c
index 7589a78..2a8ff19 100644
--- a/ext/pcre/php_pcre.c
+++ b/ext/pcre/php_pcre.c
@@ -1040,8 +1040,8 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
 	char 			**subpat_names;		/* Array for named subpatterns */
 	int				 num_subpats;		/* Number of captured subpatterns */
 	int				 size_offsets;		/* Size of the offsets array */
-	int				 new_len;			/* Length of needed storage */
-	int				 alloc_len;			/* Actual allocated length */
+	size_t			 new_len;			/* Length of needed storage */
+	size_t			 alloc_len;			/* Actual allocated length */
 	int				 eval_result_len=0;	/* Length of the eval'ed or
 										   function-returned string */
 	int				 match_len;			/* Length of the current match */
@@ -1106,8 +1106,8 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
 
 	offsets = (int *)safe_emalloc(size_offsets, sizeof(int), 0);
 
-	alloc_len = 2 * subject_len + 1;
-	result = safe_emalloc(alloc_len, sizeof(char), 0);
+	result = safe_emalloc(subject_len, 2*sizeof(char), 1);
+	alloc_len = 2 * (size_t)subject_len + 1;
 
 	/* Initialize */
 	match = NULL;
@@ -1172,8 +1172,8 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
 			}
 
 			if (new_len + 1 > alloc_len) {
-				alloc_len = 1 + alloc_len + 2 * new_len;
-				new_buf = emalloc(alloc_len);
+				new_buf = safe_emalloc(2, new_len + 1, alloc_len);
+				alloc_len = 1 + alloc_len + 2 * (size_t)new_len;
 				memcpy(new_buf, result, *result_len);
 				efree(result);
 				result = new_buf;
@@ -1236,8 +1236,8 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
 			} else {
 				new_len = *result_len + subject_len - start_offset;
 				if (new_len + 1 > alloc_len) {
-					alloc_len = new_len + 1; /* now we know exactly how long it is */
-					new_buf = safe_emalloc(alloc_len, sizeof(char), 0);
+					new_buf = safe_emalloc(new_len, sizeof(char), 1);
+					alloc_len = (size_t)new_len + 1; /* now we know exactly how long it is */
 					memcpy(new_buf, result, *result_len);
 					efree(result);
 					result = new_buf;
@@ -1268,6 +1268,12 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
 	efree(offsets);
 	efree(subpat_names);
 
+	if(result && (size_t)(*result_len) > INT_MAX) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Result is too big, max is %d", INT_MAX);
+		efree(result);
+		result = NULL;
+	}
+
 	return result;
 }
 /* }}} */
-- 
2.1.4