summaryrefslogtreecommitdiff
path: root/ex_imp.c
diff options
context:
space:
mode:
Diffstat (limited to 'ex_imp.c')
-rw-r--r--ex_imp.c318
1 files changed, 318 insertions, 0 deletions
diff --git a/ex_imp.c b/ex_imp.c
new file mode 100644
index 0000000..fd940ce
--- /dev/null
+++ b/ex_imp.c
@@ -0,0 +1,318 @@
1/*
2 +----------------------------------------------------------------------+
3 | Suhosin Version 1 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2006-2007 The Hardened-PHP Project |
6 | Copyright (c) 2007-2016 SektionEins GmbH |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
16 | Authors: Stefan Esser <sesser@sektioneins.de> |
17 | Ben Fuhrmannek <ben.fuhrmannek@sektioneins.de> |
18 +----------------------------------------------------------------------+
19
20 Note: The following code is based on ext/standard/array.c from PHP 7.
21 | Copyright (c) 1997-2016 The PHP Group |
22 Original PHP Version 7 Authors:
23 | Andi Gutmans <andi@zend.com> |
24 | Zeev Suraski <zeev@zend.com> |
25 | Rasmus Lerdorf <rasmus@php.net> |
26 | Andrei Zmievski <andrei@php.net> |
27 | Stig Venaas <venaas@php.net> |
28 | Jason Greene <jason@php.net> |
29
30*/
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#include "php.h"
37#include "php_ini.h"
38#include "ext/standard/php_smart_string.h"
39#include "ext/standard/php_var.h"
40#include "php_suhosin7.h"
41
42
43#define EXTR_OVERWRITE 0
44#define EXTR_SKIP 1
45#define EXTR_PREFIX_SAME 2
46#define EXTR_PREFIX_ALL 3
47#define EXTR_PREFIX_INVALID 4
48#define EXTR_PREFIX_IF_EXISTS 5
49#define EXTR_IF_EXISTS 6
50
51#define EXTR_REFS 0x100
52
53
54static zend_always_inline int php_valid_var_name(char *var_name, size_t var_name_len) /* {{{ */
55{
56#if 1
57 /* first 256 bits for first character, and second 256 bits for the next */
58 static const uint32_t charset[16] = {
59 /* 31 0 63 32 95 64 127 96 */
60 0x00000000, 0x00000000, 0x87fffffe, 0x07fffffe,
61 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
62 /* 31 0 63 32 95 64 127 96 */
63 0x00000000, 0x03ff0000, 0x87fffffe, 0x07fffffe,
64 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
65 };
66#endif
67 size_t i;
68 uint32_t ch;
69
70 if (UNEXPECTED(!var_name_len)) {
71 return 0;
72 }
73
74 /* These are allowed as first char: [a-zA-Z_\x7f-\xff] */
75 ch = (uint32_t)((unsigned char *)var_name)[0];
76#if 1
77 if (UNEXPECTED(!(charset[ch >> 5] & (1 << (ch & 0x1f))))) {
78#else
79 if (var_name[0] != '_' &&
80 (ch < 65 /* A */ || /* Z */ ch > 90) &&
81 (ch < 97 /* a */ || /* z */ ch > 122) &&
82 (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
83 ) {
84#endif
85 return 0;
86 }
87
88 /* And these as the rest: [a-zA-Z0-9_\x7f-\xff] */
89 if (var_name_len > 1) {
90 i = 1;
91 do {
92 ch = (uint32_t)((unsigned char *)var_name)[i];
93#if 1
94 if (UNEXPECTED(!(charset[8 + (ch >> 5)] & (1 << (ch & 0x1f))))) {
95#else
96 if (var_name[i] != '_' &&
97 (ch < 48 /* 0 */ || /* 9 */ ch > 57) &&
98 (ch < 65 /* A */ || /* Z */ ch > 90) &&
99 (ch < 97 /* a */ || /* z */ ch > 122) &&
100 (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
101 ) {
102#endif
103 return 0;
104 }
105 } while (++i < var_name_len);
106 }
107
108 if (suhosin_is_protected_varname(var_name, var_name_len)) {
109 return 0;
110 }
111
112 return 1;
113}
114
115/* {{{ proto int extract(array var_array [, int extract_type [, string prefix]])
116 Imports variables into symbol table from an array */
117PHP_FUNCTION(suhosin_extract)
118{
119 zval *var_array_param, *prefix = NULL;
120 zend_long extract_type = EXTR_OVERWRITE;
121 zval *entry;
122 zend_string *var_name;
123 zend_ulong num_key;
124 int var_exists, count = 0;
125 int extract_refs = 0;
126 zend_array *symbol_table;
127 zval var_array;
128
129#ifndef FAST_ZPP
130 if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|lz/", &var_array_param, &extract_type, &prefix) == FAILURE) {
131 return;
132 }
133#else
134 ZEND_PARSE_PARAMETERS_START(1, 3)
135 Z_PARAM_ARRAY(var_array_param)
136 Z_PARAM_OPTIONAL
137 Z_PARAM_LONG(extract_type)
138 Z_PARAM_ZVAL_EX(prefix, 0, 1)
139 ZEND_PARSE_PARAMETERS_END();
140#endif
141
142 extract_refs = (extract_type & EXTR_REFS);
143 if (extract_refs) {
144 SEPARATE_ZVAL(var_array_param);
145 }
146 extract_type &= 0xff;
147
148 if (extract_type < EXTR_OVERWRITE || extract_type > EXTR_IF_EXISTS) {
149 php_error_docref(NULL, E_WARNING, "Invalid extract type");
150 return;
151 }
152
153 if (extract_type > EXTR_SKIP && extract_type <= EXTR_PREFIX_IF_EXISTS && ZEND_NUM_ARGS() < 3) {
154 php_error_docref(NULL, E_WARNING, "specified extract type requires the prefix parameter");
155 return;
156 }
157
158 if (prefix) {
159 convert_to_string(prefix);
160 if (Z_STRLEN_P(prefix) && !php_valid_var_name(Z_STRVAL_P(prefix), Z_STRLEN_P(prefix))) {
161 php_error_docref(NULL, E_WARNING, "prefix is not a valid identifier");
162 return;
163 }
164 }
165
166 symbol_table = zend_rebuild_symbol_table();
167#if 0
168 if (!symbol_table) {
169 php_error_docref(NULL, E_WARNING, "failed to build symbol table");
170 return;
171 }
172#endif
173
174 /* The array might be stored in a local variable that will be overwritten. To avoid losing the
175 * reference in that case we work on a copy. */
176 ZVAL_COPY(&var_array, var_array_param);
177
178 ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL(var_array), num_key, var_name, entry) {
179 zval final_name;
180
181 ZVAL_NULL(&final_name);
182 var_exists = 0;
183
184 if (var_name) {
185 var_exists = zend_hash_exists_ind(symbol_table, var_name);
186 } else if (extract_type == EXTR_PREFIX_ALL || extract_type == EXTR_PREFIX_INVALID) {
187 zend_string *str = zend_long_to_str(num_key);
188 php_prefix_varname(&final_name, prefix, ZSTR_VAL(str), ZSTR_LEN(str), 1);
189 zend_string_release(str);
190 } else {
191 continue;
192 }
193
194 switch (extract_type) {
195 case EXTR_IF_EXISTS:
196 if (!var_exists) break;
197 /* break omitted intentionally */
198
199 case EXTR_OVERWRITE:
200 /* GLOBALS protection */
201 if (var_exists && ZSTR_LEN(var_name) == sizeof("GLOBALS")-1 && !strcmp(ZSTR_VAL(var_name), "GLOBALS")) {
202 break;
203 }
204 if (var_exists && ZSTR_LEN(var_name) == sizeof("this")-1 && !strcmp(ZSTR_VAL(var_name), "this") && EG(scope) && ZSTR_LEN(EG(scope)->name) != 0) {
205 break;
206 }
207 ZVAL_STR_COPY(&final_name, var_name);
208 break;
209
210 case EXTR_PREFIX_IF_EXISTS:
211 if (var_exists) {
212 php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
213 }
214 break;
215
216 case EXTR_PREFIX_SAME:
217 if (!var_exists && ZSTR_LEN(var_name) != 0) {
218 ZVAL_STR_COPY(&final_name, var_name);
219 }
220 /* break omitted intentionally */
221
222 case EXTR_PREFIX_ALL:
223 if (Z_TYPE(final_name) == IS_NULL && ZSTR_LEN(var_name) != 0) {
224 php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
225 }
226 break;
227
228 case EXTR_PREFIX_INVALID:
229 if (Z_TYPE(final_name) == IS_NULL) {
230 if (!php_valid_var_name(ZSTR_VAL(var_name), ZSTR_LEN(var_name))) {
231 php_prefix_varname(&final_name, prefix, ZSTR_VAL(var_name), ZSTR_LEN(var_name), 1);
232 } else {
233 ZVAL_STR_COPY(&final_name, var_name);
234 }
235 }
236 break;
237
238 default:
239 if (!var_exists) {
240 ZVAL_STR_COPY(&final_name, var_name);
241 }
242 break;
243 }
244
245 if (Z_TYPE(final_name) == IS_STRING && php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
246 zval *orig_var;
247 if (extract_refs) {
248
249 ZVAL_MAKE_REF(entry);
250 Z_ADDREF_P(entry);
251
252 if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
253 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
254 orig_var = Z_INDIRECT_P(orig_var);
255 }
256 zval_ptr_dtor(orig_var);
257 ZVAL_COPY_VALUE(orig_var, entry);
258 } else {
259 zend_hash_update(symbol_table, Z_STR(final_name), entry);
260 }
261 } else {
262 ZVAL_DEREF(entry);
263 if (Z_REFCOUNTED_P(entry)) Z_ADDREF_P(entry);
264 if ((orig_var = zend_hash_find(symbol_table, Z_STR(final_name))) != NULL) {
265 if (Z_TYPE_P(orig_var) == IS_INDIRECT) {
266 orig_var = Z_INDIRECT_P(orig_var);
267 }
268 ZVAL_DEREF(orig_var);
269 zval_ptr_dtor(orig_var);
270 ZVAL_COPY_VALUE(orig_var, entry);
271 } else {
272 zend_hash_update(symbol_table, Z_STR(final_name), entry);
273 }
274 }
275 count++;
276 }
277 zval_dtor(&final_name);
278 } ZEND_HASH_FOREACH_END();
279 zval_ptr_dtor(&var_array);
280
281 RETURN_LONG(count);
282}
283/* }}} */
284
285
286
287
288ZEND_BEGIN_ARG_INFO_EX(suhosin_arginfo_extract, 0, 0, 1)
289 ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, arg) /* ARRAY_INFO(0, arg, 0) */
290 ZEND_ARG_INFO(0, extract_type)
291 ZEND_ARG_INFO(0, prefix)
292ZEND_END_ARG_INFO()
293
294
295/* {{{ suhosin_ex_imp_functions[]
296 */
297zend_function_entry suhosin_ex_imp_functions[] = {
298 PHP_NAMED_FE(extract, PHP_FN(suhosin_extract), suhosin_arginfo_extract)
299 {NULL, NULL, NULL}
300};
301/* }}} */
302
303void suhosin_hook_ex_imp()
304{
305 /* replace the extract and import_request_variables functions */
306 zend_hash_str_del(CG(function_table), ZEND_STRL("extract"));
307 zend_register_functions(NULL, suhosin_ex_imp_functions, NULL, MODULE_PERSISTENT);
308}
309
310
311/*
312 * Local variables:
313 * tab-width: 4
314 * c-basic-offset: 4
315 * End:
316 * vim600: noet sw=4 ts=4 fdm=marker
317 * vim<600: noet sw=4 ts=4
318 */