Skip to content

Commit d1ab974

Browse files
committed
Fixed bug #72306 (Heap overflow through proc_open and $env parameter)
1 parent d3bdbe6 commit d1ab974

File tree

4 files changed

+48
-35
lines changed

4 files changed

+48
-35
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ PHP NEWS
33
?? ??? 2016 PHP 7.0.9
44

55

6+
- Standard:
7+
. Fixed bug #72306 (Heap overflow through proc_open and $env parameter).
8+
(Laruence)
69

710
23 Jun 2016 PHP 7.0.8
811

ext/standard/proc_open.c

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,13 @@ static php_process_env_t _php_array_to_envp(zval *environment, int is_persistent
7777
{
7878
zval *element;
7979
php_process_env_t env;
80-
zend_string *string_key;
80+
zend_string *key, *str;
8181
#ifndef PHP_WIN32
8282
char **ep;
8383
#endif
8484
char *p;
85-
size_t cnt, l, sizeenv=0;
86-
HashTable *target_hash;
85+
size_t cnt, l, sizeenv = 0;
86+
HashTable *env_hash;
8787

8888
memset(&env, 0, sizeof(env));
8989

@@ -101,28 +101,25 @@ static php_process_env_t _php_array_to_envp(zval *environment, int is_persistent
101101
return env;
102102
}
103103

104-
target_hash = Z_ARRVAL_P(environment);
105-
if (!target_hash) {
106-
return env;
107-
}
104+
ALLOC_HASHTABLE(env_hash);
105+
zend_hash_init(env_hash, cnt, NULL, NULL, 0);
108106

109107
/* first, we have to get the size of all the elements in the hash */
110-
ZEND_HASH_FOREACH_STR_KEY_VAL(target_hash, string_key, element) {
111-
zend_string *str = zval_get_string(element);
112-
size_t el_len = ZSTR_LEN(str);
113-
zend_string_release(str);
108+
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(environment), key, element) {
109+
str = zval_get_string(element);
114110

115-
if (el_len == 0) {
111+
if (ZSTR_LEN(str) == 0) {
112+
zend_string_release(str);
116113
continue;
117114
}
118115

119-
sizeenv += el_len + 1;
116+
sizeenv += ZSTR_LEN(str) + 1;
120117

121-
if (string_key) {
122-
if (ZSTR_LEN(string_key) == 0) {
123-
continue;
124-
}
125-
sizeenv += ZSTR_LEN(string_key) + 1;
118+
if (key && ZSTR_LEN(key)) {
119+
sizeenv += ZSTR_LEN(key) + 1;
120+
zend_hash_add_ptr(env_hash, key, str);
121+
} else {
122+
zend_hash_next_index_insert_ptr(env_hash, str);
126123
}
127124
} ZEND_HASH_FOREACH_END();
128125

@@ -131,20 +128,10 @@ static php_process_env_t _php_array_to_envp(zval *environment, int is_persistent
131128
#endif
132129
p = env.envp = (char *) pecalloc(sizeenv + 4, 1, is_persistent);
133130

134-
ZEND_HASH_FOREACH_STR_KEY_VAL(target_hash, string_key, element) {
135-
zend_string *str = zval_get_string(element);
136-
137-
if (ZSTR_LEN(str) == 0) {
138-
goto next_element;
139-
}
140-
141-
if (string_key) {
142-
if (ZSTR_LEN(string_key) == 0) {
143-
goto next_element;
144-
}
145-
146-
l = ZSTR_LEN(string_key) + ZSTR_LEN(str) + 2;
147-
memcpy(p, ZSTR_VAL(string_key), ZSTR_LEN(string_key));
131+
ZEND_HASH_FOREACH_STR_KEY_PTR(env_hash, key, str) {
132+
if (key) {
133+
l = ZSTR_LEN(key) + ZSTR_LEN(str) + 2;
134+
memcpy(p, ZSTR_VAL(key), ZSTR_LEN(key));
148135
strncat(p, "=", 1);
149136
strncat(p, ZSTR_VAL(str), ZSTR_LEN(str));
150137

@@ -161,12 +148,14 @@ static php_process_env_t _php_array_to_envp(zval *environment, int is_persistent
161148
#endif
162149
p += ZSTR_LEN(str) + 1;
163150
}
164-
next_element:
165151
zend_string_release(str);
166152
} ZEND_HASH_FOREACH_END();
167153

168154
assert((uint)(p - env.envp) <= sizeenv);
169155

156+
zend_hash_destroy(env_hash);
157+
FREE_HASHTABLE(env_hash);
158+
170159
return env;
171160
}
172161
/* }}} */
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
Bug #72306 (Heap overflow through proc_open and $env parameter)
3+
--FILE--
4+
<?php
5+
class moo {
6+
function __construct() { $this->a = 0; }
7+
function __toString() { return $this->a++ ? str_repeat("a", 0x8000) : "a"; }
8+
}
9+
10+
$env = array('some_option' => new moo());
11+
$pipes = array();
12+
$description = array(
13+
0 => array("pipe", "r"),
14+
1 => array("pipe", "w"),
15+
2 => array("pipe", "r")
16+
);
17+
18+
$process = proc_open('nothing', $description, $pipes, NULL, $env);
19+
20+
?>
21+
okey
22+
--EXPECT--
23+
okey

ext/standard/tests/streams/bug60602.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ if (is_resource($p)) {
4848
?>
4949
==DONE==
5050
--EXPECTF--
51-
Notice: Array to string conversion in %s on line %d
52-
5351
Notice: Array to string conversion in %s on line %d
5452
int(%d)
5553
int(0)

0 commit comments

Comments
 (0)