summaryrefslogtreecommitdiff
path: root/execute.c
diff options
context:
space:
mode:
authorStefan Esser2010-02-21 11:44:54 +0100
committerStefan Esser2010-02-21 11:44:54 +0100
commit36dbfacbe64697d959f524e537b15b73c090d898 (patch)
treef1c7ce1409b0e7765fc72d550546967fcf0f9717 /execute.c
Inital commit
Diffstat (limited to 'execute.c')
-rw-r--r--execute.c1750
1 files changed, 1750 insertions, 0 deletions
diff --git a/execute.c b/execute.c
new file mode 100644
index 0000000..aaa672b
--- /dev/null
+++ b/execute.c
@@ -0,0 +1,1750 @@
1/*
2 +----------------------------------------------------------------------+
3 | Suhosin Version 1 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2006-2007 The Hardened-PHP Project |
6 | Copyright (c) 2007 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 | Author: Stefan Esser <sesser@sektioneins.de> |
17 +----------------------------------------------------------------------+
18*/
19
20/* $Id: execute.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ */
21
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include "php.h"
27#include "php_ini.h"
28#include "zend_hash.h"
29#include "zend_extensions.h"
30#include "ext/standard/info.h"
31#include "ext/standard/php_rand.h"
32#include "php_suhosin.h"
33#include "zend_compile.h"
34#include "zend_llist.h"
35#include "SAPI.h"
36
37#include "sha256.h"
38
39
40static void (*old_execute)(zend_op_array *op_array TSRMLS_DC);
41static void suhosin_execute(zend_op_array *op_array TSRMLS_DC);
42static void (*old_execute_ZO)(zend_op_array *op_array, long dummy TSRMLS_DC);
43static void suhosin_execute_ZO(zend_op_array *op_array, long dummy TSRMLS_DC);
44static void *(*zo_set_oe_ex)(void *ptr) = NULL;
45
46/*STATIC zend_op_array* (*old_compile_file)(zend_file_handle* file_handle, int type TSRMLS_DC);
47 STATIC zend_op_array* suhosin_compile_file(zend_file_handle*, int TSRMLS_DC);*/
48
49static void suhosin_execute_internal(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC);
50static void (*old_execute_internal)(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC);
51
52extern zend_extension suhosin_zend_extension_entry;
53
54/* {{{ suhosin_strcasestr */
55static char *suhosin_strcasestr(char *haystack, char *needle)
56{
57 unsigned char *t, *h, *n;
58 h = (unsigned char *) haystack;
59conts:
60 while (*h) {
61 n = (unsigned char *) needle;
62 if (toupper(*h++) == toupper(*n++)) {
63 for (t=h; *n; t++, n++) {
64 if (toupper(*t) != toupper(*n)) goto conts;
65 }
66 return ((char*)h-1);
67 }
68 }
69
70 return (NULL);
71}
72/* }}} */
73
74
75#define SUHOSIN_CODE_TYPE_UNKNOWN 0
76#define SUHOSIN_CODE_TYPE_COMMANDLINE 1
77#define SUHOSIN_CODE_TYPE_EVAL 2
78#define SUHOSIN_CODE_TYPE_REGEXP 3
79#define SUHOSIN_CODE_TYPE_ASSERT 4
80#define SUHOSIN_CODE_TYPE_CFUNC 5
81#define SUHOSIN_CODE_TYPE_SUHOSIN 6
82#define SUHOSIN_CODE_TYPE_UPLOADED 7
83#define SUHOSIN_CODE_TYPE_0FILE 8
84#define SUHOSIN_CODE_TYPE_BLACKURL 9
85#define SUHOSIN_CODE_TYPE_BADURL 10
86#define SUHOSIN_CODE_TYPE_GOODFILE 11
87#define SUHOSIN_CODE_TYPE_BADFILE 12
88#define SUHOSIN_CODE_TYPE_LONGNAME 13
89#define SUHOSIN_CODE_TYPE_MANYDOTS 14
90#define SUHOSIN_CODE_TYPE_WRITABLE 15
91
92static int suhosin_check_filename(char *s, int len TSRMLS_DC)
93{
94 char fname[MAXPATHLEN+1];
95 char *t, *h, *h2, *index, *e;
96 int tlen, i, count=0;
97 uint indexlen;
98 ulong numindex;
99 zend_bool isOk;
100
101 /* check if filename is too long */
102 if (len > MAXPATHLEN) {
103 return SUHOSIN_CODE_TYPE_LONGNAME;
104 }
105 memcpy(fname, s, len);
106 fname[len] = 0;
107 s = (char *)&fname;
108 e = s + len;
109
110 /* check if ASCIIZ attack -> not working yet (and cannot work in PHP4 + ZO) */
111 if (len != strlen(s)) {
112 return SUHOSIN_CODE_TYPE_0FILE;
113 }
114
115 /* disallow uploaded files */
116 if (SG(rfc1867_uploaded_files)) {
117 if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) s, e-s+1)) {
118 return SUHOSIN_CODE_TYPE_UPLOADED;
119 }
120 }
121
122 /* count number of directory traversals */
123 for (i=0; i < len-3; i++) {
124 if (s[i] == '.' && s[i+1] == '.' && (s[i+2] == '/' || s[i+2] == '\\')) {
125 count++;
126 i+=2;
127 }
128 }
129 if (SUHOSIN_G(executor_include_max_traversal) && SUHOSIN_G(executor_include_max_traversal)<=count) {
130 return SUHOSIN_CODE_TYPE_MANYDOTS;
131 }
132
133SDEBUG("xxx %08x %08x",SUHOSIN_G(include_whitelist),SUHOSIN_G(include_blacklist));
134 /* no black or whitelist then disallow all */
135 if (SUHOSIN_G(include_whitelist)==NULL && SUHOSIN_G(include_blacklist)==NULL) {
136 /* disallow all URLs */
137 if (strstr(s, "://") != NULL || suhosin_strcasestr(s, "data:") != NULL) {
138 return SUHOSIN_CODE_TYPE_BADURL;
139 }
140 } else
141 /* whitelist is stronger than blacklist */
142 if (SUHOSIN_G(include_whitelist)) {
143
144 do {
145 isOk = 0;
146
147 h = strstr(s, "://");
148 h2 = suhosin_strcasestr(s, "data:");
149 h2 = h2 == NULL ? NULL : h2 + 4;
150 t = h = (h == NULL) ? h2 : ( (h2 == NULL) ? h : ( (h < h2) ? h : h2 ) );
151 if (h == NULL) break;
152
153 while (t > s && (isalnum(t[-1]) || t[-1]=='_')) {
154 t--;
155 }
156
157 tlen = e-t;
158
159 zend_hash_internal_pointer_reset(SUHOSIN_G(include_whitelist));
160 do {
161 int r = zend_hash_get_current_key_ex(SUHOSIN_G(include_whitelist), &index, &indexlen, &numindex, 0, NULL);
162
163 if (r==HASH_KEY_NON_EXISTANT) {
164 break;
165 }
166 if (r==HASH_KEY_IS_STRING) {
167 if (h-t <= indexlen-1 && tlen>=indexlen-1) {
168 if (strncasecmp(t, index, indexlen-1)==0) {
169 isOk = 1;
170 break;
171 }
172 }
173 }
174
175 zend_hash_move_forward(SUHOSIN_G(include_whitelist));
176 } while (1);
177
178 /* not found in whitelist */
179 if (!isOk) {
180 return SUHOSIN_CODE_TYPE_BADURL;
181 }
182
183 s = h + 1;
184 } while (1);
185 } else {
186
187 do {
188 int tlen;
189
190 h = strstr(s, "://");
191 h2 = suhosin_strcasestr(s, "data:");
192 h2 = h2 == NULL ? NULL : h2 + 4;
193 t = h = (h == NULL) ? h2 : ( (h2 == NULL) ? h : ( (h < h2) ? h : h2 ) );
194 if (h == NULL) break;
195
196 while (t > s && (isalnum(t[-1]) || t[-1]=='_')) {
197 t--;
198 }
199
200 tlen = e-t;
201
202 zend_hash_internal_pointer_reset(SUHOSIN_G(include_blacklist));
203 do {
204 int r = zend_hash_get_current_key_ex(SUHOSIN_G(include_blacklist), &index, &indexlen, &numindex, 0, NULL);
205
206 if (r==HASH_KEY_NON_EXISTANT) {
207 break;
208 }
209 if (r==HASH_KEY_IS_STRING) {
210 if (h-t <= indexlen-1 && tlen>=indexlen-1) {
211 if (strncasecmp(t, index, indexlen-1)==0) {
212 return SUHOSIN_CODE_TYPE_BLACKURL;
213 }
214 }
215 }
216
217 zend_hash_move_forward(SUHOSIN_G(include_blacklist));
218 } while (1);
219
220 s = h + 1;
221 } while (1);
222 }
223
224 /* disallow writable files */
225 if (!SUHOSIN_G(executor_include_allow_writable_files)) {
226 /* protection against *REMOTE* attacks, potential
227 race condition of access() is irrelevant */
228 if (access(s, W_OK) == 0) {
229 return SUHOSIN_CODE_TYPE_WRITABLE;
230 }
231 }
232
233 return SUHOSIN_CODE_TYPE_GOODFILE;
234}
235
236
237#ifdef ZEND_ENGINE_2
238static int (*old_zend_stream_open)(const char *filename, zend_file_handle *fh TSRMLS_DC);
239#else
240static zend_bool (*old_zend_open)(const char *filename, zend_file_handle *fh);
241#endif
242
243#ifdef ZEND_ENGINE_2
244static int suhosin_zend_stream_open(const char *filename, zend_file_handle *fh TSRMLS_DC)
245{
246 zend_execute_data *exd;
247#else
248static zend_bool suhosin_zend_open(const char *filename, zend_file_handle *fh)
249{
250 zend_execute_data *exd;
251 TSRMLS_FETCH();
252#endif
253 exd=EG(current_execute_data);
254 if (EG(in_execution) && (exd!=NULL) && (exd->opline != NULL) && (exd->opline->opcode == ZEND_INCLUDE_OR_EVAL)) {
255 int filetype = suhosin_check_filename((char *)filename, strlen(filename) TSRMLS_CC);
256
257 switch (filetype) {
258 case SUHOSIN_CODE_TYPE_LONGNAME:
259 suhosin_log(S_INCLUDE, "Include filename ('%s') is too long", filename);
260 suhosin_bailout(TSRMLS_C);
261 break;
262
263 case SUHOSIN_CODE_TYPE_UPLOADED:
264 suhosin_log(S_INCLUDE, "Include filename is an uploaded file");
265 suhosin_bailout(TSRMLS_C);
266 break;
267
268 case SUHOSIN_CODE_TYPE_0FILE:
269 suhosin_log(S_INCLUDE, "Include filename contains an ASCIIZ character");
270 suhosin_bailout(TSRMLS_C);
271 break;
272
273 case SUHOSIN_CODE_TYPE_WRITABLE:
274 suhosin_log(S_INCLUDE, "Include filename ('%s') is writable by PHP process", filename);
275 suhosin_bailout(TSRMLS_C);
276 break;
277
278 case SUHOSIN_CODE_TYPE_BLACKURL:
279 suhosin_log(S_INCLUDE, "Include filename ('%s') is an URL that is forbidden by the blacklist", filename);
280 suhosin_bailout(TSRMLS_C);
281 break;
282
283 case SUHOSIN_CODE_TYPE_BADURL:
284 suhosin_log(S_INCLUDE, "Include filename ('%s') is an URL that is not allowed", filename);
285 suhosin_bailout(TSRMLS_C);
286 break;
287
288 case SUHOSIN_CODE_TYPE_MANYDOTS:
289 suhosin_log(S_INCLUDE, "Include filename ('%s') contains too many '../'", filename);
290 suhosin_bailout(TSRMLS_C);
291 break;
292 }
293 }
294#ifdef ZEND_ENGINE_2
295 return old_zend_stream_open(filename, fh TSRMLS_CC);
296#else
297 return old_zend_open(filename, fh);
298#endif
299}
300
301
302static int suhosin_detect_codetype(zend_op_array *op_array TSRMLS_DC)
303{
304 char *s;
305 int r;
306
307 s = op_array->filename;
308
309 /* eval, assert, create_function, preg_replace */
310 if (op_array->type == ZEND_EVAL_CODE) {
311
312 if (s == NULL) {
313 return SUHOSIN_CODE_TYPE_UNKNOWN;
314 }
315
316 if (strstr(s, "eval()'d code") != NULL) {
317 return SUHOSIN_CODE_TYPE_EVAL;
318 }
319
320 if (strstr(s, "regexp code") != NULL) {
321 return SUHOSIN_CODE_TYPE_REGEXP;
322 }
323
324 if (strstr(s, "assert code") != NULL) {
325 return SUHOSIN_CODE_TYPE_ASSERT;
326 }
327
328 if (strstr(s, "runtime-created function") != NULL) {
329 return SUHOSIN_CODE_TYPE_CFUNC;
330 }
331
332 if (strstr(s, "Command line code") != NULL) {
333 return SUHOSIN_CODE_TYPE_COMMANDLINE;
334 }
335
336 if (strstr(s, "suhosin internal code") != NULL) {
337 return SUHOSIN_CODE_TYPE_SUHOSIN;
338 }
339
340 } else {
341
342 r = suhosin_check_filename(s, strlen(s) TSRMLS_CC);
343/* switch (r) {
344 case SUHOSIN_CODE_TYPE_GOODFILE:
345 break;
346 } */
347 return r;
348
349 }
350
351 return SUHOSIN_CODE_TYPE_UNKNOWN;
352}
353
354/* {{{ void suhosin_execute_ex(zend_op_array *op_array TSRMLS_DC)
355 * This function provides a hook for execution */
356static void suhosin_execute_ex(zend_op_array *op_array, int zo, long dummy TSRMLS_DC)
357{
358 zend_op_array *new_op_array;
359 int op_array_type, len;
360 char *fn;
361 zval cs;
362 zend_uint orig_code_type;
363 unsigned long *suhosin_flags = NULL;
364
365 if (SUHOSIN_G(abort_request) && !SUHOSIN_G(simulation) && SUHOSIN_G(filter_action)) {
366
367 char *action = SUHOSIN_G(filter_action);
368 long code = -1;
369
370 SUHOSIN_G(abort_request) = 0; /* we do not want to endlessloop */
371
372 while (*action == ' ' || *action == '\t') action++;
373
374 if (*action >= '0' && *action <= '9') {
375 char *end = action;
376 while (*end && *end != ',' && *end != ';') end++;
377 code = zend_atoi(action, end-action);
378 action = end;
379 }
380
381 while (*action == ' ' || *action == '\t' || *action == ',' || *action == ';') action++;
382
383 if (*action) {
384
385 if (strncmp("http://", action, sizeof("http://")-1)==0) {
386 sapi_header_line ctr = {0};
387
388 if (code == -1) {
389 code = 302;
390 }
391
392 ctr.line_len = spprintf(&ctr.line, 0, "Location: %s", action);
393 ctr.response_code = code;
394 sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC);
395 efree(ctr.line);
396 } else {
397 zend_file_handle file_handle;
398 zend_op_array *new_op_array;
399 zval *result = NULL;
400
401 if (code == -1) {
402 code = 200;
403 }
404
405#ifdef ZEND_ENGINE_2
406 if (zend_stream_open(action, &file_handle TSRMLS_CC) == SUCCESS) {
407#else
408 if (zend_open(action, &file_handle) == SUCCESS && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) {
409 file_handle.filename = action;
410 file_handle.free_filename = 0;
411#endif
412 if (!file_handle.opened_path) {
413 file_handle.opened_path = estrndup(action, strlen(action));
414 }
415 new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC);
416 zend_destroy_file_handle(&file_handle TSRMLS_CC);
417 if (new_op_array) {
418 EG(return_value_ptr_ptr) = &result;
419 EG(active_op_array) = new_op_array;
420 zend_execute(new_op_array TSRMLS_CC);
421#ifdef ZEND_ENGINE_2
422 destroy_op_array(new_op_array TSRMLS_CC);
423#else
424 destroy_op_array(new_op_array);
425#endif
426 efree(new_op_array);
427#ifdef ZEND_ENGINE_2
428 if (!EG(exception))
429#endif
430 {
431 if (EG(return_value_ptr_ptr)) {
432 zval_ptr_dtor(EG(return_value_ptr_ptr));
433 EG(return_value_ptr_ptr) = NULL;
434 }
435 }
436 } else {
437 code = 500;
438 }
439 } else {
440 code = 500;
441 }
442 }
443 }
444
445 sapi_header_op(SAPI_HEADER_SET_STATUS, (void *)code TSRMLS_CC);
446 zend_bailout();
447 }
448
449 SDEBUG("%s %s", op_array->filename, op_array->function_name);
450
451 SUHOSIN_G(execution_depth)++;
452
453 if (SUHOSIN_G(max_execution_depth) && SUHOSIN_G(execution_depth) > SUHOSIN_G(max_execution_depth)) {
454 suhosin_log(S_EXECUTOR, "maximum execution depth reached - script terminated");
455 suhosin_bailout(TSRMLS_C);
456 }
457
458 fn = op_array->filename;
459 len = strlen(fn);
460
461 orig_code_type = SUHOSIN_G(in_code_type);
462 if (op_array->type == ZEND_EVAL_CODE) {
463 SUHOSIN_G(in_code_type) = SUHOSIN_EVAL;
464 } else {
465 if (suhosin_zend_extension_entry.resource_number != -1) {
466 suhosin_flags = (unsigned long *) &op_array->reserved[suhosin_zend_extension_entry.resource_number];
467 SDEBUG("suhosin flags: %08x", *suhosin_flags);
468
469 if (*suhosin_flags & SUHOSIN_FLAG_CREATED_BY_EVAL) {
470 SUHOSIN_G(in_code_type) = SUHOSIN_EVAL;
471 }
472 if (*suhosin_flags & SUHOSIN_FLAG_NOT_EVALED_CODE) {
473 goto not_evaled_code;
474 }
475 }
476
477 if (strstr(op_array->filename, "eval()'d code")) {
478 SUHOSIN_G(in_code_type) = SUHOSIN_EVAL;
479 } else {
480 if (suhosin_flags) {
481 *suhosin_flags |= SUHOSIN_FLAG_NOT_EVALED_CODE;
482 }
483 }
484 }
485not_evaled_code:
486 SDEBUG("code type %u", SUHOSIN_G(in_code_type));
487 if (op_array->function_name) {
488 goto continue_execution;
489 }
490
491/* if (SUHOSIN_G(deactivate)) {
492 goto continue_execution;
493 }
494*/
495
496 op_array_type = suhosin_detect_codetype(op_array TSRMLS_CC);
497
498 switch (op_array_type) {
499 case SUHOSIN_CODE_TYPE_EVAL:
500 if (SUHOSIN_G(executor_disable_eval)) {
501 suhosin_log(S_EXECUTOR, "use of eval is forbidden by configuration");
502 if (!SUHOSIN_G(simulation)) {
503 zend_error(E_ERROR, "SUHOSIN - Use of eval is forbidden by configuration");
504 }
505 }
506 break;
507
508 case SUHOSIN_CODE_TYPE_REGEXP:
509 if (SUHOSIN_G(executor_disable_emod)) {
510 suhosin_log(S_EXECUTOR, "use of preg_replace() with /e modifier is forbidden by configuration");
511 if (!SUHOSIN_G(simulation)) {
512 zend_error(E_ERROR, "SUHOSIN - Use of preg_replace() with /e modifier is forbidden by configuration");
513 }
514 }
515 break;
516
517 case SUHOSIN_CODE_TYPE_ASSERT:
518 break;
519
520 case SUHOSIN_CODE_TYPE_CFUNC:
521 break;
522
523 case SUHOSIN_CODE_TYPE_LONGNAME:
524 suhosin_log(S_INCLUDE, "Include filename ('%s') is too long", op_array->filename);
525 suhosin_bailout(TSRMLS_C);
526 break;
527
528 case SUHOSIN_CODE_TYPE_MANYDOTS:
529 suhosin_log(S_INCLUDE, "Include filename ('%s') contains too many '../'", op_array->filename);
530 suhosin_bailout(TSRMLS_C);
531 break;
532
533 case SUHOSIN_CODE_TYPE_UPLOADED:
534 suhosin_log(S_INCLUDE, "Include filename is an uploaded file");
535 suhosin_bailout(TSRMLS_C);
536 break;
537
538 case SUHOSIN_CODE_TYPE_0FILE:
539 suhosin_log(S_INCLUDE, "Include filename contains an ASCIIZ character");
540 suhosin_bailout(TSRMLS_C);
541 break;
542
543 case SUHOSIN_CODE_TYPE_WRITABLE:
544 suhosin_log(S_INCLUDE, "Include filename ('%s') is writable by PHP process", op_array->filename);
545 suhosin_bailout(TSRMLS_C);
546 break;
547
548 case SUHOSIN_CODE_TYPE_BLACKURL:
549 suhosin_log(S_INCLUDE, "Include filename ('%s') is an URL that is forbidden by the blacklist", op_array->filename);
550 suhosin_bailout(TSRMLS_C);
551 break;
552
553 case SUHOSIN_CODE_TYPE_BADURL:
554 suhosin_log(S_INCLUDE, "Include filename ('%s') is an URL that is not allowed", op_array->filename);
555 suhosin_bailout(TSRMLS_C);
556 break;
557
558 case SUHOSIN_CODE_TYPE_BADFILE:
559 cs.type = IS_STRING;
560#define DIE_WITH_MSG "die('disallowed_file'.chr(10).chr(10));"
561 cs.value.str.val = estrndup(DIE_WITH_MSG, sizeof(DIE_WITH_MSG)-1);
562 cs.value.str.len = sizeof(DIE_WITH_MSG)-1;
563 new_op_array = compile_string(&cs, "suhosin internal code" TSRMLS_CC);
564 if (new_op_array) {
565 op_array = new_op_array;
566 goto continue_execution;
567 }
568 suhosin_bailout(TSRMLS_C);
569 break;
570
571 case SUHOSIN_CODE_TYPE_COMMANDLINE:
572 case SUHOSIN_CODE_TYPE_SUHOSIN:
573 case SUHOSIN_CODE_TYPE_UNKNOWN:
574 case SUHOSIN_CODE_TYPE_GOODFILE:
575 goto continue_execution;
576 break;
577 }
578
579continue_execution:
580 if (zo) {
581 old_execute_ZO (op_array, dummy TSRMLS_CC);
582 } else {
583 old_execute (op_array TSRMLS_CC);
584 }
585 /* nothing to do */
586 SUHOSIN_G(in_code_type) = orig_code_type;
587 SUHOSIN_G(execution_depth)--;
588}
589/* }}} */
590
591/* {{{ void suhosin_execute(zend_op_array *op_array TSRMLS_DC)
592 * This function provides a hook for execution */
593static void suhosin_execute(zend_op_array *op_array TSRMLS_DC)
594{
595 suhosin_execute_ex(op_array, 0, 0 TSRMLS_CC);
596}
597
598/* {{{ void suhosin_execute(zend_op_array *op_array, long dummy TSRMLS_DC)
599 * This function provides a hook for execution */
600static void suhosin_execute_ZO(zend_op_array *op_array, long dummy TSRMLS_DC)
601{
602 suhosin_execute_ex(op_array, 1, dummy TSRMLS_CC);
603}
604/* }}} */
605
606
607#define IH_HANDLER_PARAMS_REST zend_execute_data *execute_data_ptr, int return_value_used, int ht, zval *return_value TSRMLS_DC
608#define IH_HANDLER_PARAMS internal_function_handler *ih, IH_HANDLER_PARAMS_REST
609#define IH_HANDLER_PARAM_PASSTHRU ih, execute_data_ptr, return_value_used, ht, return_value TSRMLS_CC
610
611HashTable ihandler_table;
612
613typedef struct _internal_function_handler {
614
615 char *name;
616 int (*handler)(struct _internal_function_handler *ih, IH_HANDLER_PARAMS_REST);
617 void *arg1;
618 void *arg2;
619 void *arg3;
620
621} internal_function_handler;
622
623int ih_preg_replace(IH_HANDLER_PARAMS)
624{
625 zval **regex,
626 **replace,
627 **subject,
628 **limit;
629
630 if (ZEND_NUM_ARGS() < 3 || zend_get_parameters_ex(3, &regex, &replace, &subject, &limit) == FAILURE) {
631 return (0);
632 }
633
634 if (Z_TYPE_PP(regex) == IS_ARRAY) {
635 zval **regex_entry;
636
637 zend_hash_internal_pointer_reset(Z_ARRVAL_PP(regex));
638 /* For each entry in the regex array, get the entry */
639 while (zend_hash_get_current_data(Z_ARRVAL_PP(regex), (void **)&regex_entry) == SUCCESS) {
640
641 if (Z_TYPE_PP(regex_entry) == IS_STRING) {
642 if (strlen(Z_STRVAL_PP(regex_entry)) != Z_STRLEN_PP(regex_entry)) {
643 suhosin_log(S_EXECUTOR, "string termination attack on first preg_replace parameter detected");
644 if (!SUHOSIN_G(simulation)) {
645 RETVAL_FALSE;
646 return (1);
647 }
648 }
649 }
650
651 zend_hash_move_forward(Z_ARRVAL_PP(regex));
652
653 }
654
655 } else if (Z_TYPE_PP(regex) == IS_STRING) {
656 if (strlen(Z_STRVAL_PP(regex)) != Z_STRLEN_PP(regex)) {
657 suhosin_log(S_EXECUTOR, "string termination attack on first preg_replace parameter detected");
658 if (!SUHOSIN_G(simulation)) {
659 RETVAL_FALSE;
660 return (1);
661 }
662 }
663 }
664
665 return (0);
666}
667
668int ih_symlink(IH_HANDLER_PARAMS)
669{
670 if (SUHOSIN_G(executor_allow_symlink)) {
671 return (0);
672 }
673
674 if (PG(open_basedir) && PG(open_basedir)[0]) {
675 suhosin_log(S_EXECUTOR, "symlink called during open_basedir");
676 if (!SUHOSIN_G(simulation)) {
677 RETVAL_FALSE;
678 return (1);
679 }
680 }
681
682 return (0);
683}
684
685int ih_mail(IH_HANDLER_PARAMS)
686{
687 char *to=NULL, *message=NULL, *headers=NULL;
688 char *subject=NULL, *extra_cmd=NULL;
689 char *tmp;
690 int to_len, message_len, headers_len;
691 int subject_len, extra_cmd_len;
692
693 if (SUHOSIN_G(mailprotect) == 0) {
694 return (0);
695 }
696
697 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|ss",
698 &to, &to_len,
699 &subject, &subject_len,
700 &message, &message_len,
701 &headers, &headers_len,
702 &extra_cmd, &extra_cmd_len
703 ) == FAILURE) {
704 RETVAL_FALSE;
705 return (1);
706 }
707
708 if (headers_len > 0 && headers && (strstr(headers,"\n\n") || strstr(headers,"\r\n\r\n")) ) {
709 suhosin_log(S_MAIL, "mail() - double newline in headers, possible injection, mail dropped");
710 if (!SUHOSIN_G(simulation)) {
711 RETVAL_FALSE;
712 return (1);
713 }
714 }
715
716 /* check for spam attempts with buggy webforms */
717 if (to_len > 0 && to) {
718 do {
719 tmp = strchr(to, '\n');
720 tmp = tmp == NULL ? strchr(to, '\r') : tmp;
721 if (tmp == NULL) break;
722 to = tmp+1;
723 if (isspace(*to)) continue;
724 } while (1);
725 if (tmp != NULL) {
726 suhosin_log(S_MAIL, "mail() - newline in to header, possible injection, mail dropped");
727 if (!SUHOSIN_G(simulation)) {
728 RETVAL_FALSE;
729 return (1);
730 }
731 }
732 }
733
734 if (subject_len > 0 && subject) {
735 do {
736 tmp = strchr(subject, '\n');
737 tmp = tmp == NULL ? strchr(subject, '\r') : tmp;
738 if (tmp == NULL) break;
739 subject = tmp+1;
740 if (isspace(*subject)) continue;
741 } while (1);
742 if (tmp != NULL) {
743 suhosin_log(S_MAIL, "mail() - newline in subject header, possible injection, mail dropped");
744 if (!SUHOSIN_G(simulation)) {
745 RETVAL_FALSE;
746 return (1);
747 }
748 }
749 }
750
751 if (SUHOSIN_G(mailprotect) > 1) {
752 /* search for to, cc or bcc headers */
753 if (headers_len > 0 && headers != NULL) {
754 if (strncasecmp(headers, "to:", sizeof("to:") - 1) == 0 || suhosin_strcasestr(headers, "\nto:")) {
755 suhosin_log(S_MAIL, "mail() - To: headers aren't allowed in the headers parameter.");
756 if (!SUHOSIN_G(simulation)) {
757 RETVAL_FALSE;
758 return (1);
759 }
760 }
761
762 if (strncasecmp(headers, "cc:", sizeof("cc:") - 1) == 0 || suhosin_strcasestr(headers, "\ncc:")) {
763 suhosin_log(S_MAIL, "mail() - CC: headers aren't allowed in the headers parameter.");
764 if (!SUHOSIN_G(simulation)) {
765 RETVAL_FALSE;
766 return (1);
767 }
768 }
769
770 if (strncasecmp(headers, "bcc:", sizeof("bcc:") - 1) == 0 || suhosin_strcasestr(headers, "\nbcc:")) {
771 suhosin_log(S_MAIL, "mail() - BCC: headers aren't allowed in the headers parameter.");
772 if (!SUHOSIN_G(simulation)) {
773 RETVAL_FALSE;
774 return (1);
775 }
776 }
777 }
778 }
779
780 return (0);
781}
782
783#define SQLSTATE_SQL 0
784#define SQLSTATE_IDENTIFIER 1
785#define SQLSTATE_STRING 2
786#define SQLSTATE_COMMENT 3
787#define SQLSTATE_MLCOMMENT 4
788
789int ih_querycheck(IH_HANDLER_PARAMS)
790{
791#ifdef PHP_ATLEAST_5_3
792 void **p = zend_vm_stack_top(TSRMLS_C) - 1;
793#else
794 void **p = EG(argument_stack).top_element-2;
795#endif
796 unsigned long arg_count;
797 zval **arg;
798 char *query, *s, *e;
799 zval *backup;
800 int len;
801 char quote;
802 int state = SQLSTATE_SQL;
803 int cnt_union = 0, cnt_select = 0, cnt_comment = 0, cnt_opencomment = 0;
804 int mysql_extension = 0;
805
806
807 SDEBUG("function: %s", ih->name);
808 arg_count = (unsigned long) *p;
809
810 if (ht < (long) ih->arg1) {
811 return (0);
812 }
813
814 if ((long) ih->arg1) {
815 mysql_extension = 1;
816 }
817
818 arg = (zval **) p - (arg_count - (long) ih->arg1 + 1); /* count from 0 */
819
820 backup = *arg;
821 if (Z_TYPE_P(backup) != IS_STRING) {
822 return (0);
823 }
824 len = Z_STRLEN_P(backup);
825 query = Z_STRVAL_P(backup);
826
827 s = query;
828 e = s+len;
829
830 while (s < e) {
831 switch (state)
832 {
833 case SQLSTATE_SQL:
834 switch (s[0])
835 {
836 case '`':
837 state = SQLSTATE_IDENTIFIER;
838 quote = '`';
839 break;
840 case '\'':
841 case '"':
842 state = SQLSTATE_STRING;
843 quote = *s;
844 break;
845 case '/':
846 if (s[1]=='*') {
847 if (mysql_extension == 1 && s[2] == '!') {
848 s += 2;
849 break;
850 }
851 s++;
852 state = SQLSTATE_MLCOMMENT;
853 cnt_comment++;
854 }
855 break;
856 case '-':
857 if (s[1]=='-') {
858 s++;
859 state = SQLSTATE_COMMENT;
860 cnt_comment++;
861 }
862 break;
863 case '#':
864 state = SQLSTATE_COMMENT;
865 cnt_comment++;
866 break;
867 case 'u':
868 case 'U':
869 if (strncasecmp("union", s, 5)==0) {
870 s += 4;
871 cnt_union++;
872 }
873 break;
874 case 's':
875 case 'S':
876 if (strncasecmp("select", s, 6)==0) {
877 s += 5;
878 cnt_select++;
879 }
880 break;
881 }
882 break;
883 case SQLSTATE_STRING:
884 case SQLSTATE_IDENTIFIER:
885 if (s[0] == quote) {
886 if (s[1] == quote) {
887 s++;
888 } else {
889 state = SQLSTATE_SQL;
890 }
891 }
892 if (s[0] == '\\') {
893 s++;
894 }
895 break;
896 case SQLSTATE_COMMENT:
897 while (s[0] && s[0] != '\n') {
898 s++;
899 }
900 state = SQLSTATE_SQL;
901 break;
902 case SQLSTATE_MLCOMMENT:
903 while (s[0] && (s[0] != '*' || s[1] != '/')) {
904 s++;
905 }
906 if (s[0]) {
907 state = SQLSTATE_SQL;
908 }
909 break;
910 }
911 s++;
912 }
913 if (state == SQLSTATE_MLCOMMENT) {
914 cnt_opencomment = 1;
915 }
916
917 if (cnt_opencomment && SUHOSIN_G(sql_opencomment)>0) {
918 suhosin_log(S_SQL, "Open comment in SQL query: '%*s'", len, query);
919 if (SUHOSIN_G(sql_opencomment)>1) {
920 suhosin_bailout(TSRMLS_C);
921 }
922 }
923
924 if (cnt_comment && SUHOSIN_G(sql_comment)>0) {
925 suhosin_log(S_SQL, "Comment in SQL query: '%*s'", len, query);
926 if (SUHOSIN_G(sql_comment)>1) {
927 suhosin_bailout(TSRMLS_C);
928 }
929 }
930
931 if (cnt_union && SUHOSIN_G(sql_union)>0) {
932 suhosin_log(S_SQL, "UNION in SQL query: '%*s'", len, query);
933 if (SUHOSIN_G(sql_union)>1) {
934 suhosin_bailout(TSRMLS_C);
935 }
936 }
937
938 if (cnt_select>1 && SUHOSIN_G(sql_mselect)>0) {
939 suhosin_log(S_SQL, "Multiple SELECT in SQL query: '%*s'", len, query);
940 if (SUHOSIN_G(sql_mselect)>1) {
941 suhosin_bailout(TSRMLS_C);
942 }
943 }
944
945 return (0);
946}
947
948
949int ih_fixusername(IH_HANDLER_PARAMS)
950{
951#ifdef PHP_ATLEAST_5_3
952 void **p = zend_vm_stack_top(TSRMLS_C) - 1;
953#else
954 void **p = EG(argument_stack).top_element-2;
955#endif
956 unsigned long arg_count;
957 zval **arg;char *prefix, *postfix, *user;
958 zval *backup, *my_user;
959 int prefix_len, postfix_len, len;
960
961 SDEBUG("function: %s", ih->name);
962
963 prefix = SUHOSIN_G(sql_user_prefix);
964 postfix = SUHOSIN_G(sql_user_postfix);
965
966 if ((prefix == NULL || prefix[0] == 0)&&
967 (postfix == NULL || postfix[0] == 0)) {
968 return (0);
969 }
970
971 if (prefix == NULL) {
972 prefix = "";
973 }
974 if (postfix == NULL) {
975 postfix = "";
976 }
977
978 prefix_len = strlen(prefix);
979 postfix_len = strlen(postfix);
980
981 arg_count = (unsigned long) *p;
982
983 if (ht < (long) ih->arg1) {
984 return (0);
985 }
986
987 arg = (zval **) p - (arg_count - (long) ih->arg1 + 1); /* count from 0 */
988
989 backup = *arg;
990 if (Z_TYPE_P(backup) != IS_STRING) {
991 user = "";
992 len = 0;
993 } else {
994 len = Z_STRLEN_P(backup);
995 user = Z_STRVAL_P(backup);
996 }
997
998 if (prefix_len && prefix_len <= len) {
999 if (strncmp(prefix, user, prefix_len)==0) {
1000 prefix = "";
1001 len -= prefix_len;
1002 }
1003 }
1004
1005 if (postfix_len && postfix_len <= len) {
1006 if (strncmp(postfix, user+len-postfix_len, postfix_len)==0) {
1007 postfix = "";
1008 }
1009 }
1010
1011 MAKE_STD_ZVAL(my_user);
1012 my_user->type = IS_STRING;
1013 my_user->value.str.len = spprintf(&my_user->value.str.val, 0, "%s%s%s", prefix, user, postfix);
1014
1015 /* XXX: memory_leak? */
1016 *arg = my_user;
1017
1018 SDEBUG("function: %s - user: %s", ih->name, user);
1019
1020 return (0);
1021}
1022
1023static int suhosin_php_body_write(const char *str, uint str_length TSRMLS_DC)
1024{
1025#define P_META_ROBOTS "<meta name=\"ROBOTS\" content=\"NOINDEX,NOFOLLOW,NOARCHIVE\" />"
1026#define S_META_ROBOTS "<meta name=\"ROBOTS\" content=\"NOINDEX,FOLLOW,NOARCHIVE\" />"
1027
1028 SDEBUG("bw: %s", str);
1029
1030 if ((str_length == sizeof("</head>\n")-1) && (strcmp(str, "</head>\n")==0)) {
1031 SUHOSIN_G(old_php_body_write)(S_META_ROBOTS, sizeof(S_META_ROBOTS)-1 TSRMLS_CC);
1032 OG(php_body_write) = SUHOSIN_G(old_php_body_write);
1033 return SUHOSIN_G(old_php_body_write)(str, str_length TSRMLS_CC);
1034 } else if ((str_length == sizeof(P_META_ROBOTS)-1) && (strcmp(str, P_META_ROBOTS)==0)) {
1035 return str_length;
1036 }
1037 return SUHOSIN_G(old_php_body_write)(str, str_length TSRMLS_CC);
1038}
1039
1040static int ih_phpinfo(IH_HANDLER_PARAMS)
1041{
1042 int argc = ZEND_NUM_ARGS();
1043 long flag;
1044
1045 if (zend_parse_parameters(argc TSRMLS_CC, "|l", &flag) == FAILURE) {
1046 RETVAL_FALSE;
1047 return (1);
1048 }
1049
1050 if(!argc) {
1051 flag = PHP_INFO_ALL;
1052 }
1053
1054 /* Andale! Andale! Yee-Hah! */
1055 php_start_ob_buffer(NULL, 4096, 0 TSRMLS_CC);
1056 if (!sapi_module.phpinfo_as_text) {
1057 SUHOSIN_G(old_php_body_write) = OG(php_body_write);
1058 OG(php_body_write) = suhosin_php_body_write;
1059 }
1060 php_print_info(flag TSRMLS_CC);
1061 php_end_ob_buffer(1, 0 TSRMLS_CC);
1062
1063 RETVAL_TRUE;
1064 return (1);
1065}
1066
1067
1068static int ih_function_exists(IH_HANDLER_PARAMS)
1069{
1070 zval **function_name;
1071 zend_function *func;
1072 char *lcname;
1073 zend_bool retval;
1074 int func_name_len;
1075
1076 if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &function_name)==FAILURE) {
1077 ZEND_WRONG_PARAM_COUNT();
1078 }
1079 convert_to_string_ex(function_name);
1080 func_name_len = Z_STRLEN_PP(function_name);
1081 lcname = estrndup(Z_STRVAL_PP(function_name), func_name_len);
1082 zend_str_tolower(lcname, func_name_len);
1083
1084 retval = (zend_hash_find(EG(function_table), lcname, func_name_len+1, (void **)&func) == SUCCESS);
1085
1086 efree(lcname);
1087
1088 /*
1089 * A bit of a hack, but not a bad one: we see if the handler of the function
1090 * is actually one that displays "function is disabled" message.
1091 */
1092 if (retval && func->type == ZEND_INTERNAL_FUNCTION &&
1093 func->internal_function.handler == zif_display_disabled_function) {
1094 retval = 0;
1095 }
1096
1097 /* Now check if function is forbidden by Suhosin */
1098 if (SUHOSIN_G(in_code_type) == SUHOSIN_EVAL) {
1099 if (SUHOSIN_G(eval_whitelist) != NULL) {
1100 if (!zend_hash_exists(SUHOSIN_G(eval_whitelist), lcname, func_name_len+1)) {
1101 retval = 0;
1102 }
1103 } else if (SUHOSIN_G(eval_blacklist) != NULL) {
1104 if (zend_hash_exists(SUHOSIN_G(eval_blacklist), lcname, func_name_len+1)) {
1105 retval = 0;
1106 }
1107 }
1108 }
1109
1110 if (SUHOSIN_G(func_whitelist) != NULL) {
1111 if (!zend_hash_exists(SUHOSIN_G(func_whitelist), lcname, func_name_len+1)) {
1112 retval = 0;
1113 }
1114 } else if (SUHOSIN_G(func_blacklist) != NULL) {
1115 if (zend_hash_exists(SUHOSIN_G(func_blacklist), lcname, func_name_len+1)) {
1116 retval = 0;
1117 }
1118 }
1119
1120 RETVAL_BOOL(retval);
1121 return (1);
1122}
1123
1124/* MT RAND FUNCTIONS */
1125
1126/*
1127 The following php_mt_...() functions are based on a C++ class MTRand by
1128 Richard J. Wagner. For more information see the web page at
1129 http://www-personal.engin.umich.edu/~wagnerr/MersenneTwister.html
1130
1131 Mersenne Twister random number generator -- a C++ class MTRand
1132 Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus
1133 Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com
1134
1135 The Mersenne Twister is an algorithm for generating random numbers. It
1136 was designed with consideration of the flaws in various other generators.
1137 The period, 2^19937-1, and the order of equidistribution, 623 dimensions,
1138 are far greater. The generator is also fast; it avoids multiplication and
1139 division, and it benefits from caches and pipelines. For more information
1140 see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html
1141
1142 Reference
1143 M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally
1144 Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on
1145 Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30.
1146
1147 Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
1148 Copyright (C) 2000 - 2003, Richard J. Wagner
1149 All rights reserved.
1150
1151 Redistribution and use in source and binary forms, with or without
1152 modification, are permitted provided that the following conditions
1153 are met:
1154
1155 1. Redistributions of source code must retain the above copyright
1156 notice, this list of conditions and the following disclaimer.
1157
1158 2. Redistributions in binary form must reproduce the above copyright
1159 notice, this list of conditions and the following disclaimer in the
1160 documentation and/or other materials provided with the distribution.
1161
1162 3. The names of its contributors may not be used to endorse or promote
1163 products derived from this software without specific prior written
1164 permission.
1165
1166 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1167 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1168 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1169 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
1170 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
1171 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1172 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1173 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
1174 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
1175 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1176 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1177
1178 The original code included the following notice:
1179
1180 When you use this, send an email to: matumoto@math.keio.ac.jp
1181 with an appropriate reference to your work.
1182
1183 It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu
1184 when you write.
1185*/
1186
1187#define N 624 /* length of state vector */
1188#define M (397) /* a period parameter */
1189#define hiBit(u) ((u) & 0x80000000U) /* mask all but highest bit of u */
1190#define loBit(u) ((u) & 0x00000001U) /* mask all but lowest bit of u */
1191#define loBits(u) ((u) & 0x7FFFFFFFU) /* mask the highest bit of u */
1192#define mixBits(u, v) (hiBit(u)|loBits(v)) /* move hi bit of u to hi bit of v */
1193
1194#define twist(m,u,v) (m ^ (mixBits(u,v)>>1) ^ ((php_uint32)(-(php_int32)(loBit(u))) & 0x9908b0dfU))
1195
1196/* {{{ php_mt_initialize
1197 */
1198static inline void suhosin_mt_initialize(php_uint32 seed, php_uint32 *state)
1199{
1200 /* Initialize generator state with seed
1201 See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
1202 In previous versions, most significant bits (MSBs) of the seed affect
1203 only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto. */
1204
1205 register php_uint32 *s = state;
1206 register php_uint32 *r = state;
1207 register int i = 1;
1208
1209 *s++ = seed & 0xffffffffU;
1210 for( ; i < N; ++i ) {
1211 *s++ = ( 1812433253U * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffU;
1212 r++;
1213 }
1214}
1215/* }}} */
1216
1217static inline void suhosin_mt_init_by_array(php_uint32 *key, int keylen, php_uint32 *state)
1218{
1219 int i, j, k;
1220 suhosin_mt_initialize(19650218U, state);
1221 i = 1; j = 0;
1222 k = (N > keylen ? N : keylen);
1223 for (; k; k--) {
1224 state[i] = (state[i] ^ ((state[i-1] ^ (state[i-1] >> 30)) * 1664525U)) + key[j] + j;
1225 i++; j = (j+1) % keylen;
1226 if (i >= N) { state[0] = state[N-1]; i=1; }
1227 }
1228 for (k=N-1; k; k--) {
1229 state[i] = (state[i] ^ ((state[i-1] ^ (state[i-1] >> 30)) * 1566083941U)) - i;
1230 i++;
1231 if (i >= N) { state[0] = state[N-1]; i=1; }
1232 }
1233 state[0] = 0x80000000U;
1234}
1235/* }}} */
1236
1237
1238/* {{{ suhosin_mt_reload
1239 */
1240static inline void suhosin_mt_reload(php_uint32 *state, php_uint32 **next, int *left)
1241{
1242 /* Generate N new values in state
1243 Made clearer and faster by Matthew Bellew (matthew.bellew@home.com) */
1244
1245 register php_uint32 *p = state;
1246 register int i;
1247
1248 for (i = N - M; i--; ++p)
1249 *p = twist(p[M], p[0], p[1]);
1250 for (i = M; --i; ++p)
1251 *p = twist(p[M-N], p[0], p[1]);
1252 *p = twist(p[M-N], p[0], state[0]);
1253 *left = N;
1254 *next = state;
1255}
1256/* }}} */
1257
1258/* {{{ suhosin_mt_srand
1259 */
1260static void suhosin_mt_srand(php_uint32 seed TSRMLS_DC)
1261{
1262 /* Seed the generator with a simple uint32 */
1263 suhosin_mt_initialize(seed, SUHOSIN_G(mt_state));
1264 suhosin_mt_reload(SUHOSIN_G(mt_state), &SUHOSIN_G(mt_next), &SUHOSIN_G(mt_left));
1265
1266 /* Seed only once */
1267 SUHOSIN_G(mt_is_seeded) = 1;
1268}
1269/* }}} */
1270
1271/* {{{ suhosin_mt_rand
1272 */
1273static php_uint32 suhosin_mt_rand(TSRMLS_D)
1274{
1275 /* Pull a 32-bit integer from the generator state
1276 Every other access function simply transforms the numbers extracted here */
1277
1278 register php_uint32 s1;
1279
1280 if (SUHOSIN_G(mt_left) == 0) {
1281 suhosin_mt_reload(SUHOSIN_G(mt_state), &SUHOSIN_G(mt_next), &SUHOSIN_G(mt_left));
1282 }
1283 --SUHOSIN_G(mt_left);
1284
1285 s1 = *SUHOSIN_G(mt_next)++;
1286 s1 ^= (s1 >> 11);
1287 s1 ^= (s1 << 7) & 0x9d2c5680U;
1288 s1 ^= (s1 << 15) & 0xefc60000U;
1289 return ( s1 ^ (s1 >> 18) );
1290}
1291/* }}} */
1292
1293/* {{{ suhosin_gen_entropy
1294 */
1295static void suhosin_gen_entropy(php_uint32 *seedbuf TSRMLS_DC)
1296{
1297 /* On a modern OS code, stack and heap base are randomized */
1298 unsigned long code_value = (unsigned long)suhosin_gen_entropy;
1299 unsigned long stack_value = (unsigned long)&code_value;
1300 unsigned long heap_value = (unsigned long)SUHOSIN_G(r_state);
1301 suhosin_SHA256_CTX context;
1302
1303 code_value ^= code_value >> 32;
1304 stack_value ^= stack_value >> 32;
1305 heap_value ^= heap_value >> 32;
1306
1307 seedbuf[0] = code_value;
1308 seedbuf[1] = stack_value;
1309 seedbuf[2] = heap_value;
1310 seedbuf[3] = time(0);
1311#ifdef PHP_WIN32
1312 seedbuf[4] = GetCurrentProcessId();
1313#else
1314 seedbuf[4] = getpid();
1315#endif
1316 seedbuf[5] = (php_uint32) 0x7fffffff * php_combined_lcg(TSRMLS_C);
1317
1318 suhosin_SHA256Init(&context);
1319 suhosin_SHA256Update(&context, (void *) seedbuf, sizeof(php_uint32) * 6);
1320 suhosin_SHA256Final(seedbuf, &context);
1321}
1322/* }}} */
1323
1324
1325/* {{{ suhosin_srand_auto
1326 */
1327static void suhosin_srand_auto(TSRMLS_D)
1328{
1329 php_uint32 seed[8];
1330 suhosin_gen_entropy(&seed[0] TSRMLS_CC);
1331
1332 suhosin_mt_init_by_array(seed, 8, SUHOSIN_G(r_state));
1333 suhosin_mt_reload(SUHOSIN_G(r_state), &SUHOSIN_G(r_next), &SUHOSIN_G(r_left));
1334
1335 /* Seed only once */
1336 SUHOSIN_G(r_is_seeded) = 1;
1337}
1338/* }}} */
1339
1340/* {{{ suhosin_mt_srand_auto
1341 */
1342static void suhosin_mt_srand_auto(TSRMLS_D)
1343{
1344 php_uint32 seed[8];
1345 suhosin_gen_entropy(&seed[0] TSRMLS_CC);
1346
1347 suhosin_mt_init_by_array(seed, 8, SUHOSIN_G(mt_state));
1348 suhosin_mt_reload(SUHOSIN_G(mt_state), &SUHOSIN_G(mt_next), &SUHOSIN_G(mt_left));
1349
1350 /* Seed only once */
1351 SUHOSIN_G(mt_is_seeded) = 1;
1352}
1353/* }}} */
1354
1355
1356/* {{{ suhosin_srand
1357 */
1358static void suhosin_srand(php_uint32 seed TSRMLS_DC)
1359{
1360 /* Seed the generator with a simple uint32 */
1361 suhosin_mt_initialize(seed+0x12345, SUHOSIN_G(r_state));
1362 suhosin_mt_reload(SUHOSIN_G(r_state), &SUHOSIN_G(r_next), &SUHOSIN_G(r_left));
1363
1364 /* Seed only once */
1365 SUHOSIN_G(r_is_seeded) = 1;
1366}
1367/* }}} */
1368
1369/* {{{ suhosin_mt_rand
1370 */
1371static php_uint32 suhosin_rand(TSRMLS_D)
1372{
1373 /* Pull a 32-bit integer from the generator state
1374 Every other access function simply transforms the numbers extracted here */
1375
1376 register php_uint32 s1;
1377
1378 if (SUHOSIN_G(r_left) == 0) {
1379 suhosin_mt_reload(SUHOSIN_G(r_state), &SUHOSIN_G(r_next), &SUHOSIN_G(r_left));
1380 }
1381 --SUHOSIN_G(r_left);
1382
1383 s1 = *SUHOSIN_G(r_next)++;
1384 s1 ^= (s1 >> 11);
1385 s1 ^= (s1 << 7) & 0x9d2c5680U;
1386 s1 ^= (s1 << 15) & 0xefc60000U;
1387 return ( s1 ^ (s1 >> 18) );
1388}
1389/* }}} */
1390
1391static int ih_srand(IH_HANDLER_PARAMS)
1392{
1393 int argc = ZEND_NUM_ARGS();
1394 long seed;
1395
1396 if (zend_parse_parameters(argc TSRMLS_CC, "|l", &seed) == FAILURE || SUHOSIN_G(srand_ignore)) {
1397 RETVAL_FALSE;
1398 return (1);
1399 }
1400
1401 if (argc == 0) {
1402 suhosin_srand_auto(TSRMLS_C);
1403 } else {
1404 suhosin_srand(seed TSRMLS_CC);
1405 }
1406 RETVAL_TRUE;
1407 return (1);
1408}
1409
1410static int ih_mt_srand(IH_HANDLER_PARAMS)
1411{
1412 int argc = ZEND_NUM_ARGS();
1413 long seed;
1414
1415 if (zend_parse_parameters(argc TSRMLS_CC, "|l", &seed) == FAILURE || SUHOSIN_G(mt_srand_ignore)) {
1416 RETVAL_FALSE;
1417 return (1);
1418 }
1419
1420 if (argc == 0) {
1421 suhosin_mt_srand_auto(TSRMLS_C);
1422 } else {
1423 suhosin_mt_srand(seed TSRMLS_CC);
1424 }
1425 RETVAL_TRUE;
1426 return (1);
1427}
1428
1429static int ih_mt_rand(IH_HANDLER_PARAMS)
1430{
1431 int argc = ZEND_NUM_ARGS();
1432 long min;
1433 long max;
1434 long number;
1435
1436 if (argc != 0 && zend_parse_parameters(argc TSRMLS_CC, "ll", &min, &max) == FAILURE) {
1437 return (1);
1438 }
1439
1440 if (!SUHOSIN_G(mt_is_seeded)) {
1441 suhosin_mt_srand_auto(TSRMLS_C);
1442 }
1443
1444 number = (long) (suhosin_mt_rand(TSRMLS_C) >> 1);
1445 if (argc == 2) {
1446 RAND_RANGE(number, min, max, PHP_MT_RAND_MAX);
1447 }
1448
1449 RETURN_LONG(number);
1450}
1451
1452static int ih_rand(IH_HANDLER_PARAMS)
1453{
1454 int argc = ZEND_NUM_ARGS();
1455 long min;
1456 long max;
1457 long number;
1458
1459 if (argc != 0 && zend_parse_parameters(argc TSRMLS_CC, "ll", &min, &max) == FAILURE) {
1460 return (1);
1461 }
1462
1463 if (!SUHOSIN_G(r_is_seeded)) {
1464 suhosin_srand_auto(TSRMLS_C);
1465 }
1466
1467 number = (long) (suhosin_rand(TSRMLS_C) >> 1);
1468 if (argc == 2) {
1469 RAND_RANGE(number, min, max, PHP_MT_RAND_MAX);
1470 }
1471
1472 RETURN_LONG(number);
1473}
1474
1475static int ih_getrandmax(IH_HANDLER_PARAMS)
1476{
1477 int argc = ZEND_NUM_ARGS();
1478
1479 if (argc != 0) {
1480 ZEND_WRONG_PARAM_COUNT();
1481 }
1482
1483 RETVAL_LONG(PHP_MT_RAND_MAX);
1484 return (1);
1485}
1486
1487internal_function_handler ihandlers[] = {
1488 { "preg_replace", ih_preg_replace, NULL, NULL, NULL },
1489 { "mail", ih_mail, NULL, NULL, NULL },
1490 { "symlink", ih_symlink, NULL, NULL, NULL },
1491 { "phpinfo", ih_phpinfo, NULL, NULL, NULL },
1492
1493 { "srand", ih_srand, NULL, NULL, NULL },
1494 { "mt_srand", ih_mt_srand, NULL, NULL, NULL },
1495 { "rand", ih_rand, NULL, NULL, NULL },
1496 { "mt_rand", ih_mt_rand, NULL, NULL, NULL },
1497 { "getrandmax", ih_getrandmax, NULL, NULL, NULL },
1498 { "mt_getrandmax", ih_getrandmax, NULL, NULL, NULL },
1499
1500 { "ocilogon", ih_fixusername, (void *)1, NULL, NULL },
1501 { "ociplogon", ih_fixusername, (void *)1, NULL, NULL },
1502 { "ocinlogon", ih_fixusername, (void *)1, NULL, NULL },
1503 { "oci_connect", ih_fixusername, (void *)1, NULL, NULL },
1504 { "oci_pconnect", ih_fixusername, (void *)1, NULL, NULL },
1505 { "oci_new_connect", ih_fixusername, (void *)1, NULL, NULL },
1506
1507 { "fbsql_change_user", ih_fixusername, (void *)1, NULL, NULL },
1508 { "fbsql_connect", ih_fixusername, (void *)2, NULL, NULL },
1509 { "fbsql_pconnect", ih_fixusername, (void *)2, NULL, NULL },
1510
1511 { "function_exists", ih_function_exists, NULL, NULL, NULL },
1512
1513 { "ifx_connect", ih_fixusername, (void *)2, NULL, NULL },
1514 { "ifx_pconnect", ih_fixusername, (void *)2, NULL, NULL },
1515
1516 { "ibase_connect", ih_fixusername, (void *)2, NULL, NULL },
1517 { "ibase_pconnect", ih_fixusername, (void *)2, NULL, NULL },
1518
1519 { "maxdb", ih_fixusername, (void *)2, NULL, NULL },
1520 { "maxdb_change_user", ih_fixusername, (void *)2, NULL, NULL },
1521 { "maxdb_connect", ih_fixusername, (void *)2, NULL, NULL },
1522 { "maxdb_pconnect", ih_fixusername, (void *)2, NULL, NULL },
1523 { "maxdb_real_connect", ih_fixusername, (void *)3, NULL, NULL },
1524
1525 { "mssql_connect", ih_fixusername, (void *)2, NULL, NULL },
1526 { "mssql_pconnect", ih_fixusername, (void *)2, NULL, NULL },
1527
1528 { "mysql_query", ih_querycheck, (void *)1, (void *)1, NULL },
1529 { "mysql_db_query", ih_querycheck, (void *)2, (void *)1, NULL },
1530 { "mysql_unbuffered_query", ih_querycheck, (void *)1, (void *)1, NULL },
1531 { "mysqli_query", ih_querycheck, (void *)2, (void *)1, NULL },
1532 { "mysqli_real_query", ih_querycheck, (void *)2, (void *)1, NULL },
1533 { "mysqli_send_query", ih_querycheck, (void *)2, (void *)1, NULL },
1534 { "mysqli_master_query", ih_querycheck, (void *)2, (void *)1, NULL },
1535 { "mysqli_slave_query", ih_querycheck, (void *)2, (void *)1, NULL },
1536
1537 { "mysqli", ih_fixusername, (void *)2, NULL, NULL },
1538 { "mysql_connect", ih_fixusername, (void *)2, NULL, NULL },
1539 { "mysql_pconnect", ih_fixusername, (void *)2, NULL, NULL },
1540 { "mysqli_change_user", ih_fixusername, (void *)2, NULL, NULL },
1541 { "mysql_real_connect", ih_fixusername, (void *)3, NULL, NULL },
1542 { NULL, NULL, NULL, NULL, NULL }
1543};
1544
1545#define FUNCTION_WARNING() zend_error(E_WARNING, "%s() has been disabled for security reasons", get_active_function_name(TSRMLS_C));
1546
1547/* {{{ void suhosin_execute_internal(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC)
1548 * This function provides a hook for internal execution */
1549static void suhosin_execute_internal(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC)
1550{
1551 char *lcname;
1552 int function_name_strlen, free_lcname = 0;
1553 zval *return_value;
1554 zend_class_entry *ce = NULL;
1555 int ht;
1556 internal_function_handler *ih;
1557
1558#ifdef ZEND_ENGINE_2
1559 ce = ((zend_internal_function *) execute_data_ptr->function_state.function)->scope;
1560#endif
1561 lcname = ((zend_internal_function *) execute_data_ptr->function_state.function)->function_name;
1562 function_name_strlen = strlen(lcname);
1563
1564 /* handle methodcalls correctly */
1565 if (ce != NULL) {
1566 char *tmp = (char *) emalloc(function_name_strlen + 2 + ce->name_length + 1);
1567 memcpy(tmp, ce->name, ce->name_length);
1568 memcpy(tmp+ce->name_length, "::", 2);
1569 memcpy(tmp+ce->name_length+2, lcname, function_name_strlen);
1570 lcname = tmp;
1571 free_lcname = 1;
1572 function_name_strlen += ce->name_length + 2;
1573 lcname[function_name_strlen] = 0;
1574 zend_str_tolower(lcname, function_name_strlen);
1575 }
1576
1577#ifdef ZEND_ENGINE_2
1578 return_value = (*(temp_variable *)((char *) execute_data_ptr->Ts + execute_data_ptr->opline->result.u.var)).var.ptr;
1579#else
1580 return_value = execute_data_ptr->Ts[execute_data_ptr->opline->result.u.var].var.ptr;
1581#endif
1582 ht = execute_data_ptr->opline->extended_value;
1583
1584 SDEBUG("function: %s", lcname);
1585
1586 if (SUHOSIN_G(in_code_type) == SUHOSIN_EVAL) {
1587
1588 if (SUHOSIN_G(eval_whitelist) != NULL) {
1589 if (!zend_hash_exists(SUHOSIN_G(eval_whitelist), lcname, function_name_strlen+1)) {
1590 suhosin_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", lcname);
1591 goto execute_internal_bailout;
1592 }
1593 } else if (SUHOSIN_G(eval_blacklist) != NULL) {
1594 if (zend_hash_exists(SUHOSIN_G(eval_blacklist), lcname, function_name_strlen+1)) {
1595 suhosin_log(S_EXECUTOR, "function within eval blacklist called: %s()", lcname);
1596 goto execute_internal_bailout;
1597 }
1598 }
1599 }
1600
1601 if (SUHOSIN_G(func_whitelist) != NULL) {
1602 if (!zend_hash_exists(SUHOSIN_G(func_whitelist), lcname, function_name_strlen+1)) {
1603 suhosin_log(S_EXECUTOR, "function outside of whitelist called: %s()", lcname);
1604 goto execute_internal_bailout;
1605 }
1606 } else if (SUHOSIN_G(func_blacklist) != NULL) {
1607 if (zend_hash_exists(SUHOSIN_G(func_blacklist), lcname, function_name_strlen+1)) {
1608 suhosin_log(S_EXECUTOR, "function within blacklist called: %s()", lcname);
1609 goto execute_internal_bailout;
1610 }
1611 }
1612
1613 if (zend_hash_find(&ihandler_table, lcname, function_name_strlen+1, (void **)&ih) == SUCCESS) {
1614
1615 int retval = 0;
1616 void *handler = ((zend_internal_function *) execute_data_ptr->function_state.function)->handler;
1617
1618 if (handler != ZEND_FN(display_disabled_function)) {
1619 retval = ih->handler(IH_HANDLER_PARAM_PASSTHRU);
1620 }
1621
1622 if (retval == 0) {
1623 old_execute_internal(execute_data_ptr, return_value_used TSRMLS_CC);
1624 }
1625 } else {
1626 old_execute_internal(execute_data_ptr, return_value_used TSRMLS_CC);
1627 }
1628 if (free_lcname == 1) {
1629 efree(lcname);
1630 }
1631 return;
1632execute_internal_bailout:
1633 if (free_lcname == 1) {
1634 efree(lcname);
1635 }
1636 FUNCTION_WARNING()
1637 suhosin_bailout(TSRMLS_C);
1638}
1639/* }}} */
1640
1641
1642/* {{{ int function_lookup(zend_extension *extension)
1643 */
1644static int function_lookup(zend_extension *extension)
1645{
1646 if (zo_set_oe_ex != NULL) {
1647 return ZEND_HASH_APPLY_STOP;
1648 }
1649
1650 if (extension->handle != NULL) {
1651
1652 zo_set_oe_ex = (void *)DL_FETCH_SYMBOL(extension->handle, "zend_optimizer_set_oe_ex");
1653
1654 }
1655
1656 return 0;
1657}
1658/* }}} */
1659
1660
1661/* {{{ void suhosin_hook_execute()
1662 */
1663void suhosin_hook_execute(TSRMLS_D)
1664{
1665 internal_function_handler *ih;
1666
1667 old_execute = zend_execute;
1668 zend_execute = suhosin_execute;
1669
1670/* old_compile_file = zend_compile_file;
1671 zend_compile_file = suhosin_compile_file; */
1672
1673 if (zo_set_oe_ex == NULL) {
1674 zo_set_oe_ex = (void *)DL_FETCH_SYMBOL(NULL, "zend_optimizer_set_oe_ex");
1675 }
1676 if (zo_set_oe_ex == NULL) {
1677 zend_llist_apply(&zend_extensions, (llist_apply_func_t)function_lookup TSRMLS_CC);
1678 }
1679
1680 if (zo_set_oe_ex != NULL) {
1681 old_execute_ZO = zo_set_oe_ex(suhosin_execute_ZO);
1682 }
1683
1684 old_execute_internal = zend_execute_internal;
1685 if (old_execute_internal == NULL) {
1686 old_execute_internal = execute_internal;
1687 }
1688 zend_execute_internal = suhosin_execute_internal;
1689 /* register internal function handlers */
1690 zend_hash_init(&ihandler_table, 16, NULL, NULL, 1);
1691 ih = &ihandlers[0];
1692 while (ih->name) {
1693 zend_hash_add(&ihandler_table, ih->name, strlen(ih->name)+1, ih, sizeof(internal_function_handler), NULL);
1694 ih++;
1695 }
1696
1697
1698 /* Add additional protection layer, that SHOULD
1699 catch ZEND_INCLUDE_OR_EVAL *before* the engine tries
1700 to execute */
1701#ifdef ZEND_ENGINE_2
1702 old_zend_stream_open = zend_stream_open_function;
1703 zend_stream_open_function = suhosin_zend_stream_open;
1704#else
1705 old_zend_open = zend_open;
1706 zend_open = suhosin_zend_open;
1707#endif
1708
1709}
1710/* }}} */
1711
1712
1713/* {{{ void suhosin_unhook_execute()
1714 */
1715void suhosin_unhook_execute()
1716{
1717 if (zo_set_oe_ex) {
1718 zo_set_oe_ex(old_execute_ZO);
1719 }
1720
1721 zend_execute = old_execute;
1722
1723/* zend_compile_file = old_compile_file; */
1724
1725 if (old_execute_internal == execute_internal) {
1726 old_execute_internal = NULL;
1727 }
1728 zend_execute_internal = old_execute_internal;
1729 zend_hash_clean(&ihandler_table);
1730
1731 /* remove zend_open protection */
1732#ifdef ZEND_ENGINE_2
1733 zend_stream_open_function = old_zend_stream_open;
1734#else
1735 zend_open = old_zend_open;
1736#endif
1737
1738}
1739/* }}} */
1740
1741
1742
1743/*
1744 * Local variables:
1745 * tab-width: 4
1746 * c-basic-offset: 4
1747 * End:
1748 * vim600: noet sw=4 ts=4 fdm=marker
1749 * vim<600: noet sw=4 ts=4
1750 */