summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/php_snuffleupagus.h3
-rw-r--r--src/snuffleupagus.c9
-rw-r--r--src/sp_config.c1
-rw-r--r--src/sp_config.h12
-rw-r--r--src/sp_config_keywords.c19
-rw-r--r--src/sp_config_keywords.h1
-rw-r--r--src/sp_disabled_functions.c40
-rw-r--r--src/sp_execute.c3
-rw-r--r--src/sp_harden_rand.c9
-rw-r--r--src/sp_unserialize.c2
-rw-r--r--src/tests/config/eval_backlist.ini1
-rw-r--r--src/tests/config/eval_backlist_list.ini1
-rw-r--r--src/tests/config/eval_backlist_simulation.ini1
-rw-r--r--src/tests/eval_backlist.phpt16
-rw-r--r--src/tests/eval_backlist_list.phpt16
-rw-r--r--src/tests/eval_backlist_simulation.phpt17
-rw-r--r--src/tests/nested_eval_blacklist.phpt28
17 files changed, 171 insertions, 8 deletions
diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h
index d7c3e27..fb90d1c 100644
--- a/src/php_snuffleupagus.h
+++ b/src/php_snuffleupagus.h
@@ -58,10 +58,12 @@ extern zend_module_entry snuffleupagus_module_entry;
58#endif 58#endif
59 59
60ZEND_BEGIN_MODULE_GLOBALS(snuffleupagus) 60ZEND_BEGIN_MODULE_GLOBALS(snuffleupagus)
61bool in_eval;
61sp_config config; 62sp_config config;
62bool is_config_valid; 63bool is_config_valid;
63HashTable *disabled_functions_hook; 64HashTable *disabled_functions_hook;
64HashTable *sp_internal_functions_hook; 65HashTable *sp_internal_functions_hook;
66HashTable *sp_eval_filter_functions_hook;
65ZEND_END_MODULE_GLOBALS(snuffleupagus) 67ZEND_END_MODULE_GLOBALS(snuffleupagus)
66 68
67#define SNUFFLEUPAGUS_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(snuffleupagus, v) 69#define SNUFFLEUPAGUS_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(snuffleupagus, v)
@@ -83,6 +85,7 @@ ZEND_TSRMLS_CACHE_EXTERN()
83#endif 85#endif
84 86
85PHP_FUNCTION(check_disabled_function); 87PHP_FUNCTION(check_disabled_function);
88PHP_FUNCTION(eval_filter_callback);
86 89
87static inline void sp_terminate() { zend_bailout(); } 90static inline void sp_terminate() { zend_bailout(); }
88 91
diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c
index dd2d941..a3a2fa8 100644
--- a/src/snuffleupagus.c
+++ b/src/snuffleupagus.c
@@ -53,6 +53,8 @@ ZEND_DLEXPORT zend_extension zend_extension_entry = {
53 STANDARD_ZEND_EXTENSION_PROPERTIES}; 53 STANDARD_ZEND_EXTENSION_PROPERTIES};
54 54
55PHP_GINIT_FUNCTION(snuffleupagus) { 55PHP_GINIT_FUNCTION(snuffleupagus) {
56 snuffleupagus_globals->in_eval = false;
57
56#define SP_INIT(F) F = pecalloc(sizeof(*F), 1, 1); 58#define SP_INIT(F) F = pecalloc(sizeof(*F), 1, 1);
57#define SP_INIT_HT(F) \ 59#define SP_INIT_HT(F) \
58 F = pemalloc(sizeof(*F), 1); \ 60 F = pemalloc(sizeof(*F), 1); \
@@ -60,6 +62,7 @@ PHP_GINIT_FUNCTION(snuffleupagus) {
60 62
61 SP_INIT_HT(snuffleupagus_globals->disabled_functions_hook); 63 SP_INIT_HT(snuffleupagus_globals->disabled_functions_hook);
62 SP_INIT_HT(snuffleupagus_globals->sp_internal_functions_hook); 64 SP_INIT_HT(snuffleupagus_globals->sp_internal_functions_hook);
65 SP_INIT_HT(snuffleupagus_globals->sp_eval_filter_functions_hook);
63 66
64 SP_INIT(snuffleupagus_globals->config.config_unserialize); 67 SP_INIT(snuffleupagus_globals->config.config_unserialize);
65 SP_INIT(snuffleupagus_globals->config.config_random); 68 SP_INIT(snuffleupagus_globals->config.config_random);
@@ -73,6 +76,7 @@ PHP_GINIT_FUNCTION(snuffleupagus) {
73 SP_INIT(snuffleupagus_globals->config.config_disabled_functions_ret); 76 SP_INIT(snuffleupagus_globals->config.config_disabled_functions_ret);
74 SP_INIT(snuffleupagus_globals->config.config_cookie); 77 SP_INIT(snuffleupagus_globals->config.config_cookie);
75 SP_INIT(snuffleupagus_globals->config.config_disabled_constructs); 78 SP_INIT(snuffleupagus_globals->config.config_disabled_constructs);
79 SP_INIT(snuffleupagus_globals->config.config_eval);
76 80
77 snuffleupagus_globals->config.config_disabled_constructs->construct_include = 81 snuffleupagus_globals->config.config_disabled_constructs->construct_include =
78 sp_list_new(); 82 sp_list_new();
@@ -83,6 +87,8 @@ PHP_GINIT_FUNCTION(snuffleupagus) {
83 snuffleupagus_globals->config.config_disabled_functions_ret 87 snuffleupagus_globals->config.config_disabled_functions_ret
84 ->disabled_functions = sp_list_new(); 88 ->disabled_functions = sp_list_new();
85 snuffleupagus_globals->config.config_cookie->cookies = sp_list_new(); 89 snuffleupagus_globals->config.config_cookie->cookies = sp_list_new();
90 snuffleupagus_globals->config.config_eval->blacklist = sp_list_new();
91 snuffleupagus_globals->config.config_eval->whitelist = sp_list_new();
86 92
87#undef SP_INIT 93#undef SP_INIT
88#undef SP_INIT_HT 94#undef SP_INIT_HT
@@ -100,6 +106,7 @@ PHP_MSHUTDOWN_FUNCTION(snuffleupagus) {
100 pefree(SNUFFLEUPAGUS_G(F), 1); 106 pefree(SNUFFLEUPAGUS_G(F), 1);
101 107
102 FREE_HT(disabled_functions_hook); 108 FREE_HT(disabled_functions_hook);
109 FREE_HT(sp_eval_filter_functions_hook);
103 110
104#undef FREE_HT 111#undef FREE_HT
105 112
@@ -124,6 +131,8 @@ PHP_MSHUTDOWN_FUNCTION(snuffleupagus) {
124 FREE_LST_DISABLE(config.config_disabled_constructs->construct_include); 131 FREE_LST_DISABLE(config.config_disabled_constructs->construct_include);
125 FREE_LST_DISABLE(config.config_disabled_constructs->construct_eval); 132 FREE_LST_DISABLE(config.config_disabled_constructs->construct_eval);
126 sp_list_free(SNUFFLEUPAGUS_G(config).config_cookie->cookies); 133 sp_list_free(SNUFFLEUPAGUS_G(config).config_cookie->cookies);
134 sp_list_free(SNUFFLEUPAGUS_G(config).config_eval->blacklist);
135 sp_list_free(SNUFFLEUPAGUS_G(config).config_eval->whitelist);
127 136
128#undef FREE_LST_DISABLE 137#undef FREE_LST_DISABLE
129 138
diff --git a/src/sp_config.c b/src/sp_config.c
index 4d95062..dc5aae9 100644
--- a/src/sp_config.c
+++ b/src/sp_config.c
@@ -19,6 +19,7 @@ sp_config_tokens const sp_func[] = {
19 {.func = parse_global, .token = SP_TOKEN_GLOBAL}, 19 {.func = parse_global, .token = SP_TOKEN_GLOBAL},
20 {.func = parse_auto_cookie_secure, .token = SP_TOKEN_AUTO_COOKIE_SECURE}, 20 {.func = parse_auto_cookie_secure, .token = SP_TOKEN_AUTO_COOKIE_SECURE},
21 {.func = parse_disable_xxe, .token = SP_TOKEN_DISABLE_XXE}, 21 {.func = parse_disable_xxe, .token = SP_TOKEN_DISABLE_XXE},
22 {.func = parse_eval_filter, .token = SP_TOKEN_EVAL},
22 {NULL, NULL}}; 23 {NULL, NULL}};
23 24
24/* Top level keyword parsing */ 25/* Top level keyword parsing */
diff --git a/src/sp_config.h b/src/sp_config.h
index 2417cf9..a4a4f10 100644
--- a/src/sp_config.h
+++ b/src/sp_config.h
@@ -112,6 +112,12 @@ typedef struct {
112} sp_disabled_function; 112} sp_disabled_function;
113 113
114typedef struct { 114typedef struct {
115 sp_list_node *blacklist;
116 sp_list_node *whitelist;
117 bool simulation;
118} sp_config_eval;
119
120typedef struct {
115 sp_list_node *disabled_functions; // list of sp_disabled_function 121 sp_list_node *disabled_functions; // list of sp_disabled_function
116} sp_config_disabled_functions; 122} sp_config_disabled_functions;
117 123
@@ -145,6 +151,7 @@ typedef struct {
145 sp_config_global_strict *config_global_strict; 151 sp_config_global_strict *config_global_strict;
146 sp_config_disable_xxe *config_disable_xxe; 152 sp_config_disable_xxe *config_disable_xxe;
147 sp_config_disabled_constructs *config_disabled_constructs; 153 sp_config_disabled_constructs *config_disabled_constructs;
154 sp_config_eval *config_eval;
148} sp_config; 155} sp_config;
149 156
150typedef struct { 157typedef struct {
@@ -170,6 +177,7 @@ typedef struct {
170#define SP_TOKEN_UNSERIALIZE_HMAC ".unserialize_hmac" 177#define SP_TOKEN_UNSERIALIZE_HMAC ".unserialize_hmac"
171#define SP_TOKEN_UPLOAD_VALIDATION ".upload_validation" 178#define SP_TOKEN_UPLOAD_VALIDATION ".upload_validation"
172#define SP_TOKEN_DISABLE_XXE ".disable_xxe" 179#define SP_TOKEN_DISABLE_XXE ".disable_xxe"
180#define SP_TOKEN_EVAL ".eval_filter"
173 181
174// common tokens 182// common tokens
175#define SP_TOKEN_ENABLE ".enable(" 183#define SP_TOKEN_ENABLE ".enable("
@@ -222,6 +230,10 @@ typedef struct {
222// upload_validator 230// upload_validator
223#define SP_TOKEN_UPLOAD_SCRIPT ".script(" 231#define SP_TOKEN_UPLOAD_SCRIPT ".script("
224 232
233// eval blacklist
234#define SP_TOKEN_EVAL_BLACKLIST ".blacklist("
235#define SP_TOKEN_EVAL_WHITELIST ".whitelist("
236
225int sp_parse_config(const char *); 237int sp_parse_config(const char *);
226int parse_array(sp_disabled_function *); 238int parse_array(sp_disabled_function *);
227 239
diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c
index 998b692..85e04ab 100644
--- a/src/sp_config_keywords.c
+++ b/src/sp_config_keywords.c
@@ -102,6 +102,25 @@ int parse_global(char *line) {
102 return parse_keywords(sp_config_funcs_global, line); 102 return parse_keywords(sp_config_funcs_global, line);
103} 103}
104 104
105int parse_eval_filter(char *line) {
106 char *token;
107 char *rest;
108 sp_config_functions sp_config_funcs[] = {
109 {parse_str, SP_TOKEN_EVAL_BLACKLIST, &rest},
110 {parse_empty, SP_TOKEN_SIMULATION,
111 &(SNUFFLEUPAGUS_G(config).config_eval->simulation)},
112 {0}};
113 int ret = parse_keywords(sp_config_funcs, line);
114 if (0 != ret) {
115 return ret;
116 }
117
118 while ((token = strtok_r(rest, ",", &rest))) {
119 sp_list_insert(SNUFFLEUPAGUS_G(config).config_eval->blacklist, token);
120 }
121 return SUCCESS;
122}
123
105int parse_cookie(char *line) { 124int parse_cookie(char *line) {
106 int ret = 0; 125 int ret = 0;
107 char *samesite = NULL; 126 char *samesite = NULL;
diff --git a/src/sp_config_keywords.h b/src/sp_config_keywords.h
index 8286997..d7ea36a 100644
--- a/src/sp_config_keywords.h
+++ b/src/sp_config_keywords.h
@@ -12,5 +12,6 @@ int parse_unserialize(char *line);
12int parse_readonly_exec(char *line); 12int parse_readonly_exec(char *line);
13int parse_disabled_functions(char *line); 13int parse_disabled_functions(char *line);
14int parse_upload_validation(char *line); 14int parse_upload_validation(char *line);
15int parse_eval_filter(char *line);
15 16
16#endif // __SP_CONFIG_KEYWORDS_H 17#endif // __SP_CONFIG_KEYWORDS_H
diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c
index 829f938..45b8954 100644
--- a/src/sp_disabled_functions.c
+++ b/src/sp_disabled_functions.c
@@ -431,8 +431,8 @@ ZEND_FUNCTION(check_disabled_function) {
431 } 431 }
432 432
433 orig_handler = zend_hash_str_find_ptr( 433 orig_handler = zend_hash_str_find_ptr(
434 SNUFFLEUPAGUS_G(disabled_functions_hook), current_function_name, 434 SNUFFLEUPAGUS_G(disabled_functions_hook), current_function_name,
435 strlen(current_function_name)); 435 strlen(current_function_name));
436 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); 436 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
437 if (true == should_drop_on_ret(return_value, execute_data)) { 437 if (true == should_drop_on_ret(return_value, execute_data)) {
438 sp_terminate(); 438 sp_terminate();
@@ -460,6 +460,31 @@ static int hook_functions(const sp_list_node* config) {
460 return SUCCESS; 460 return SUCCESS;
461} 461}
462 462
463ZEND_FUNCTION(eval_filter_callback) {
464 void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS);
465 const char* current_function_name = get_active_function_name(TSRMLS_C);
466
467 if (SNUFFLEUPAGUS_G(in_eval) == true) {
468 const char* filename = get_eval_filename(zend_get_executed_filename());
469 const int line_number = zend_get_executed_lineno(TSRMLS_C);
470 if (1 == SNUFFLEUPAGUS_G(config).config_eval->simulation) {
471 sp_log_msg("eval", SP_LOG_SIMULATION,
472 "A call to %s was tried in eval, in %s:%d, dropping it.",
473 current_function_name, filename, line_number);
474 } else {
475 sp_log_msg("eval", SP_LOG_DROP,
476 "A call to %s was tried in eval, in %s:%d, dropping it.",
477 current_function_name, filename, line_number);
478 sp_terminate();
479 }
480 }
481
482 orig_handler = zend_hash_str_find_ptr(
483 SNUFFLEUPAGUS_G(sp_eval_filter_functions_hook), current_function_name,
484 strlen(current_function_name));
485 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
486}
487
463int hook_disabled_functions(void) { 488int hook_disabled_functions(void) {
464 TSRMLS_FETCH(); 489 TSRMLS_FETCH();
465 490
@@ -470,5 +495,16 @@ int hook_disabled_functions(void) {
470 ret |= hook_functions(SNUFFLEUPAGUS_G(config) 495 ret |= hook_functions(SNUFFLEUPAGUS_G(config)
471 .config_disabled_functions_ret->disabled_functions); 496 .config_disabled_functions_ret->disabled_functions);
472 497
498 if (NULL != SNUFFLEUPAGUS_G(config).config_eval->blacklist->data) {
499 sp_list_node* it = SNUFFLEUPAGUS_G(config).config_eval->blacklist;
500
501 while (it) {
502 hook_function((char*)it->data,
503 SNUFFLEUPAGUS_G(sp_eval_filter_functions_hook),
504 PHP_FN(eval_filter_callback), false);
505 it = it->next;
506 }
507 }
508
473 return ret; 509 return ret;
474} 510}
diff --git a/src/sp_execute.c b/src/sp_execute.c
index 7dd0798..a50bfd5 100644
--- a/src/sp_execute.c
+++ b/src/sp_execute.c
@@ -68,6 +68,7 @@ static void sp_execute_ex(zend_execute_data *execute_data) {
68 } 68 }
69 69
70 if (execute_data->func->op_array.type == ZEND_EVAL_CODE) { 70 if (execute_data->func->op_array.type == ZEND_EVAL_CODE) {
71 SNUFFLEUPAGUS_G(in_eval) = true;
71 sp_list_node *config = 72 sp_list_node *config =
72 SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval; 73 SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval;
73 char *filename = get_eval_filename((char *)zend_get_executed_filename()); 74 char *filename = get_eval_filename((char *)zend_get_executed_filename());
@@ -86,6 +87,8 @@ static void sp_execute_ex(zend_execute_data *execute_data) {
86 if (true == should_drop_on_ret(execute_data->return_value, execute_data)) { 87 if (true == should_drop_on_ret(execute_data->return_value, execute_data)) {
87 sp_terminate(); 88 sp_terminate();
88 } 89 }
90
91 SNUFFLEUPAGUS_G(in_eval) = false;
89} 92}
90 93
91static int sp_stream_open(const char *filename, zend_file_handle *handle) { 94static int sp_stream_open(const char *filename, zend_file_handle *handle) {
diff --git a/src/sp_harden_rand.c b/src/sp_harden_rand.c
index 3727bef..cb57591 100644
--- a/src/sp_harden_rand.c
+++ b/src/sp_harden_rand.c
@@ -56,9 +56,8 @@ PHP_FUNCTION(sp_rand) {
56 56
57 /* call the original `rand` function, 57 /* call the original `rand` function,
58 * since we might no be the only ones to hook it*/ 58 * since we might no be the only ones to hook it*/
59 orig_handler = 59 orig_handler = zend_hash_str_find_ptr(
60 zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), 60 SNUFFLEUPAGUS_G(sp_internal_functions_hook), "rand", strlen("rand"));
61 "rand", strlen("rand"));
62 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); 61 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
63 62
64 random_int_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU); 63 random_int_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU);
@@ -70,8 +69,8 @@ PHP_FUNCTION(sp_mt_rand) {
70 /* call the original `mt_rand` function, 69 /* call the original `mt_rand` function,
71 * since we might no be the only ones to hook it*/ 70 * since we might no be the only ones to hook it*/
72 orig_handler = 71 orig_handler =
73 zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), 72 zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook),
74 "mt_rand", strlen("mt_rand")); 73 "mt_rand", strlen("mt_rand"));
75 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); 74 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
76 75
77 random_int_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU); 76 random_int_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU);
diff --git a/src/sp_unserialize.c b/src/sp_unserialize.c
index 476bebc..f78b046 100644
--- a/src/sp_unserialize.c
+++ b/src/sp_unserialize.c
@@ -7,7 +7,7 @@ PHP_FUNCTION(sp_serialize) {
7 7
8 /* Call the original `serialize` function. */ 8 /* Call the original `serialize` function. */
9 orig_handler = zend_hash_str_find_ptr( 9 orig_handler = zend_hash_str_find_ptr(
10 SNUFFLEUPAGUS_G(sp_internal_functions_hook), "serialize", 9); 10 SNUFFLEUPAGUS_G(sp_internal_functions_hook), "serialize", 9);
11 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); 11 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
12 12
13 /* Compute the HMAC of the textual representation of the serialized data*/ 13 /* Compute the HMAC of the textual representation of the serialized data*/
diff --git a/src/tests/config/eval_backlist.ini b/src/tests/config/eval_backlist.ini
new file mode 100644
index 0000000..1e34b5b
--- /dev/null
+++ b/src/tests/config/eval_backlist.ini
@@ -0,0 +1 @@
sp.eval_filter.blacklist("strlen");
diff --git a/src/tests/config/eval_backlist_list.ini b/src/tests/config/eval_backlist_list.ini
new file mode 100644
index 0000000..da5650d
--- /dev/null
+++ b/src/tests/config/eval_backlist_list.ini
@@ -0,0 +1 @@
sp.eval_filter.blacklist("strcmp,strlen");
diff --git a/src/tests/config/eval_backlist_simulation.ini b/src/tests/config/eval_backlist_simulation.ini
new file mode 100644
index 0000000..fafebd5
--- /dev/null
+++ b/src/tests/config/eval_backlist_simulation.ini
@@ -0,0 +1 @@
sp.eval_filter.blacklist("strlen").simulation();
diff --git a/src/tests/eval_backlist.phpt b/src/tests/eval_backlist.phpt
new file mode 100644
index 0000000..20b2c92
--- /dev/null
+++ b/src/tests/eval_backlist.phpt
@@ -0,0 +1,16 @@
1--TEST--
2Eval blacklist
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/eval_backlist.ini
7--FILE--
8<?php
9$a = strlen("1337 1337 1337");
10echo "Outside of eval: $a\n";
11eval('$a = strlen("1234");');
12echo "After eval: $a\n";
13?>
14--EXPECTF--
15Outside of eval: 14
16[snuffleupagus][0.0.0.0][eval][drop] A call to strlen was tried in eval, in%atests/eval_backlist.php:1, dropping it.
diff --git a/src/tests/eval_backlist_list.phpt b/src/tests/eval_backlist_list.phpt
new file mode 100644
index 0000000..b1c7bfd
--- /dev/null
+++ b/src/tests/eval_backlist_list.phpt
@@ -0,0 +1,16 @@
1--TEST--
2Eval blacklist - with a list of functions
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/eval_backlist_list.ini
7--FILE--
8<?php
9$a = strlen("1337 1337 1337");
10echo "Outside of eval: $a\n";
11eval('$a = strlen("1234");');
12echo "After eval: $a\n";
13?>
14--EXPECTF--
15Outside of eval: 14
16[snuffleupagus][0.0.0.0][eval][drop] A call to strlen was tried in eval, in %a/tests/eval_backlist_list.php:1, dropping it.
diff --git a/src/tests/eval_backlist_simulation.phpt b/src/tests/eval_backlist_simulation.phpt
new file mode 100644
index 0000000..ddeae60
--- /dev/null
+++ b/src/tests/eval_backlist_simulation.phpt
@@ -0,0 +1,17 @@
1--TEST--
2Eval blacklist
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/eval_backlist_simulation.ini
7--FILE--
8<?php
9$a = strlen("1337 1337 1337");
10echo "Outside of eval: $a\n";
11eval('$a = strlen("1234");');
12echo "After eval: $a\n";
13?>
14--EXPECTF--
15Outside of eval: 14
16[snuffleupagus][0.0.0.0][eval][simulation] A call to strlen was tried in eval, in %a/tests/eval_backlist_simulation.php:1, dropping it.
17After eval: 4
diff --git a/src/tests/nested_eval_blacklist.phpt b/src/tests/nested_eval_blacklist.phpt
new file mode 100644
index 0000000..b12bf93
--- /dev/null
+++ b/src/tests/nested_eval_blacklist.phpt
@@ -0,0 +1,28 @@
1--TEST--
2Eval blacklist - nested eval
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/eval_backlist.ini
7--FILE--
8<?php
9$a = strlen("1337 1337 1337");
10echo "Outside of eval: $a\n";
11eval(
12 "echo 'Inception lvl 1...\n';
13 eval(
14 'echo \"Inception lvl 2...\n\";
15 eval(
16 \"echo \'Inception lvl 3...\n\';
17 strlen(\'Limbo!\');
18 \");
19 ');
20");
21echo "After eval: $a\n";
22?>
23--EXPECTF--
24Outside of eval: 14
25Inception lvl 1...
26Inception lvl 2...
27Inception lvl 3...
28[snuffleupagus][0.0.0.0][eval][drop] A call to strlen was tried in eval, in %a/tests/nested_eval_blacklist.php(5) : eval()'d code(4) : eval()'d code:3, dropping it.