summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjvoisin2017-11-29 11:36:57 +0100
committerGitHub2017-11-29 11:36:57 +0100
commit10437787b0e8ede80976de4a1c22775fc1282f36 (patch)
tree1ab911ab000989b98449475eda655a797e278049 /src
parent8df77884f38e7a7334b56aafe2f441567f175af8 (diff)
Implement eval hooking
It's not possible to hook the `eval` builtin like other functions.
Diffstat (limited to 'src')
-rw-r--r--src/snuffleupagus.c2
-rw-r--r--src/sp_config.h1
-rw-r--r--src/sp_config_keywords.c6
-rw-r--r--src/sp_disabled_functions.c153
-rw-r--r--src/sp_disabled_functions.h2
-rw-r--r--src/sp_execute.c79
-rw-r--r--src/sp_execute.h1
-rw-r--r--src/sp_utils.c2
-rw-r--r--src/tests/config/config_disabled_functions_eval_filename.ini1
-rw-r--r--src/tests/config/disabled_functions.ini1
-rw-r--r--src/tests/config/disabled_functions_eval.ini1
-rw-r--r--src/tests/config/disabled_functions_eval_simulation.ini1
-rw-r--r--src/tests/deny_writable_execution.phpt5
-rw-r--r--src/tests/disabled_functions_eval.phpt9
-rw-r--r--src/tests/disabled_functions_eval_filename.phpt14
-rw-r--r--src/tests/disabled_functions_eval_simulation.phpt15
-rw-r--r--src/tests/disabled_functions_require.phpt2
-rw-r--r--src/tests/disabled_functions_require_simulation.phpt2
18 files changed, 203 insertions, 94 deletions
diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c
index 9467a5d..bf18588 100644
--- a/src/snuffleupagus.c
+++ b/src/snuffleupagus.c
@@ -75,6 +75,7 @@ PHP_GINIT_FUNCTION(snuffleupagus) {
75 SP_INIT(snuffleupagus_globals->config.config_disabled_constructs); 75 SP_INIT(snuffleupagus_globals->config.config_disabled_constructs);
76 76
77 snuffleupagus_globals->config.config_disabled_constructs->construct_include = sp_list_new(); 77 snuffleupagus_globals->config.config_disabled_constructs->construct_include = sp_list_new();
78 snuffleupagus_globals->config.config_disabled_constructs->construct_eval = sp_list_new();
78 snuffleupagus_globals->config.config_disabled_functions->disabled_functions = sp_list_new(); 79 snuffleupagus_globals->config.config_disabled_functions->disabled_functions = sp_list_new();
79 snuffleupagus_globals->config.config_disabled_functions_ret->disabled_functions = sp_list_new(); 80 snuffleupagus_globals->config.config_disabled_functions_ret->disabled_functions = sp_list_new();
80 SP_INIT_HT(snuffleupagus_globals->config.config_cookie->cookies); 81 SP_INIT_HT(snuffleupagus_globals->config.config_cookie->cookies);
@@ -118,6 +119,7 @@ PHP_MSHUTDOWN_FUNCTION(snuffleupagus) {
118 FREE_LST(config.config_disabled_functions->disabled_functions); 119 FREE_LST(config.config_disabled_functions->disabled_functions);
119 FREE_LST(config.config_disabled_functions_ret->disabled_functions); 120 FREE_LST(config.config_disabled_functions_ret->disabled_functions);
120 FREE_LST(config.config_disabled_constructs->construct_include); 121 FREE_LST(config.config_disabled_constructs->construct_include);
122 FREE_LST(config.config_disabled_constructs->construct_eval);
121 123
122#undef FREE_LST 124#undef FREE_LST
123 125
diff --git a/src/sp_config.h b/src/sp_config.h
index 12f12e8..6d091ae 100644
--- a/src/sp_config.h
+++ b/src/sp_config.h
@@ -115,6 +115,7 @@ typedef struct {
115 115
116typedef struct { 116typedef struct {
117 sp_node_t *construct_include; // list of rules for `(include|require)_(once)?` 117 sp_node_t *construct_include; // list of rules for `(include|require)_(once)?`
118 sp_node_t *construct_eval;
118 sp_node_t *construct_echo; 119 sp_node_t *construct_echo;
119} sp_config_disabled_constructs; 120} sp_config_disabled_constructs;
120 121
diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c
index 077d78f..0e52846 100644
--- a/src/sp_config_keywords.c
+++ b/src/sp_config_keywords.c
@@ -24,6 +24,9 @@ static int get_construct_type(sp_disabled_function const *const df) {
24 .type = ZEND_STRLEN, 24 .type = ZEND_STRLEN,
25 .keys = {"strlen", NULL} 25 .keys = {"strlen", NULL}
26 },{ 26 },{
27 .type = ZEND_EVAL_CODE,
28 .keys = {"eval", NULL}
29 },{
27 .type = 0, 30 .type = 0,
28 .keys = {NULL} 31 .keys = {NULL}
29 } 32 }
@@ -299,6 +302,9 @@ int parse_disabled_functions(char *line) {
299 case ZEND_INCLUDE_OR_EVAL: 302 case ZEND_INCLUDE_OR_EVAL:
300 sp_list_insert(SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_include, df); 303 sp_list_insert(SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_include, df);
301 return ret; 304 return ret;
305 case ZEND_EVAL_CODE:
306 sp_list_insert(SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval, df);
307 return ret;
302 case ZEND_ECHO: 308 case ZEND_ECHO:
303 default: 309 default:
304 break; 310 break;
diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c
index 44a215c..e233259 100644
--- a/src/sp_disabled_functions.c
+++ b/src/sp_disabled_functions.c
@@ -101,16 +101,44 @@ static bool is_local_var_matching(zend_execute_data *execute_data, const sp_disa
101 return false; 101 return false;
102} 102}
103 103
104bool should_disable(zend_execute_data* execute_data) { 104static sp_node_t *get_config(const char *builtin_name) {
105 if (!builtin_name) {
106 return SNUFFLEUPAGUS_G(config).config_disabled_functions->disabled_functions;
107 }
108 if (!strcmp(builtin_name, "eval")) {
109 return SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval;
110 }
111 if (!strcmp(builtin_name, "include") ||
112 !strcmp(builtin_name, "include_once") ||
113 !strcmp(builtin_name, "require") ||
114 !strcmp(builtin_name, "require_once")) {
115 return SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_include;
116 }
117 return NULL;
118}
119
120bool should_disable(zend_execute_data* execute_data, const char *builtin_name, const char *builtin_param,
121 const char *builtin_param_name) {
105 char current_file_hash[SHA256_SIZE * 2 + 1] = {0}; 122 char current_file_hash[SHA256_SIZE * 2 + 1] = {0};
106 const char* current_filename = zend_get_executed_filename(TSRMLS_C); 123 const sp_node_t* config = get_config(builtin_name);
107 const sp_node_t* config = 124 char* complete_path_function = get_complete_function_path(execute_data);
108 SNUFFLEUPAGUS_G(config).config_disabled_functions->disabled_functions;
109 char* complete_path_function = get_complete_function_path(execute_data);;
110 char const* client_ip = sp_getenv("REMOTE_ADDR"); 125 char const* client_ip = sp_getenv("REMOTE_ADDR");
126 const char* current_filename;
111 127
128 if (builtin_name && !strcmp(builtin_name, "eval")) {
129 current_filename = get_eval_filename(zend_get_executed_filename());
130 }
131 else {
132 current_filename = zend_get_executed_filename();
133 }
134
112 if (!complete_path_function) { 135 if (!complete_path_function) {
113 return false; 136 if (builtin_name) {
137 complete_path_function = (char *)builtin_name;
138 }
139 else {
140 return false;
141 }
114 } 142 }
115 143
116 if (!config || !config->data) { 144 if (!config || !config->data) {
@@ -133,7 +161,7 @@ bool should_disable(zend_execute_data* execute_data) {
133 } 161 }
134 } else if (config_node->function) { /* Litteral match against the function name. */ 162 } else if (config_node->function) { /* Litteral match against the function name. */
135 if (0 != strcmp(config_node->function, complete_path_function)) { 163 if (0 != strcmp(config_node->function, complete_path_function)) {
136 goto next; 164 goto next;
137 } 165 }
138 } else if (config_node->r_function) { 166 } else if (config_node->r_function) {
139 if (false == 167 if (false ==
@@ -149,6 +177,7 @@ bool should_disable(zend_execute_data* execute_data) {
149 } 177 }
150 178
151 if (config_node->filename) { /* Check the current file name. */ 179 if (config_node->filename) { /* Check the current file name. */
180
152 if (0 != strcmp(current_filename, config_node->filename)) { 181 if (0 != strcmp(current_filename, config_node->filename)) {
153 goto next; 182 goto next;
154 } 183 }
@@ -199,58 +228,66 @@ bool should_disable(zend_execute_data* execute_data) {
199 } 228 }
200 } 229 }
201 230
202 for (; i < nb_param; i++) { 231 if (builtin_name) {
203 arg_matched = false; 232 // we are matching on a builtin param, but for PHP, it's not the same a function param
204 if (ZEND_USER_CODE(execute_data->func->type)) { // yay consistency 233 arg_matched = sp_match_value(builtin_param, config_node->value, config_node->value_r);
205 arg_name = ZSTR_VAL(execute_data->func->common.arg_info[i].name); 234 arg_name = builtin_param_name;
206 } else { 235 arg_value_str = builtin_param;
207 arg_name = execute_data->func->internal_function.arg_info[i].name; 236 }
208 } 237 else {
238 for (; i < nb_param; i++) {
239 arg_matched = false;
240 if (ZEND_USER_CODE(execute_data->func->type)) { // yay consistency
241 arg_name = ZSTR_VAL(execute_data->func->common.arg_info[i].name);
242 } else {
243 arg_name = execute_data->func->internal_function.arg_info[i].name;
244 }
209 245
210 const bool arg_matching = 246 const bool arg_matching =
211 config_node->param && (0 == strcmp(arg_name, config_node->param)); 247 config_node->param && (0 == strcmp(arg_name, config_node->param));
212 const bool pcre_matching = 248 const bool pcre_matching =
213 config_node->r_param && 249 config_node->r_param &&
214 (true == is_regexp_matching(config_node->r_param, arg_name)); 250 (true == is_regexp_matching(config_node->r_param, arg_name));
215 251
216 /* This is the parameter name we're looking for. */ 252 /* This is the parameter name we're looking for. */
217 if (true == arg_matching || true == pcre_matching || (config_node->pos != -1)) { 253 if (true == arg_matching || true == pcre_matching || (config_node->pos != -1)) {
218 zval* arg_value = ZEND_CALL_VAR_NUM(execute_data, i); 254 zval* arg_value = ZEND_CALL_VAR_NUM(execute_data, i);
219 255
220 if (config_node->param_type) { // Are we matching on the `type`? 256 if (config_node->param_type) { // Are we matching on the `type`?
221 if (config_node->param_type == Z_TYPE_P(arg_value)) { 257 if (config_node->param_type == Z_TYPE_P(arg_value)) {
222 arg_matched = true; 258 arg_matched = true;
223 break; 259 break;
224 } 260 }
225 } else if (Z_TYPE_P(arg_value) == IS_ARRAY) { 261 } else if (Z_TYPE_P(arg_value) == IS_ARRAY) {
226 arg_value_str = estrdup("Array"); 262 arg_value_str = estrdup("Array");
227 // match on arr -> match on all key content, if a key is an array, 263 // match on arr -> match on all key content, if a key is an array,
228 // ignore it 264 // ignore it
229 // match on arr[foo] -> match only on key foo, if the key is an 265 // match on arr[foo] -> match only on key foo, if the key is an
230 // array, match on all keys content 266 // array, match on all keys content
231 if (config_node->param_is_array == true) { 267 if (config_node->param_is_array == true) {
232 if (true == sp_match_array_key_recurse( 268 if (true == sp_match_array_key_recurse(
233 arg_value, config_node->param_array_keys, 269 arg_value, config_node->param_array_keys,
234 config_node->value, config_node->value_r)) { 270 config_node->value, config_node->value_r)) {
235 arg_matched = true; 271 arg_matched = true;
236 break; 272 break;
237 } 273 }
238 } else { // match on all keys, but don't go into subarray 274 } else { // match on all keys, but don't go into subarray
239 if (true == sp_match_array_key(arg_value, config_node->value, 275 if (true == sp_match_array_key(arg_value, config_node->value,
240 config_node->value_r)) { 276 config_node->value_r)) {
241 arg_matched = true; 277 arg_matched = true;
242 break; 278 break;
243 } 279 }
244 } 280 }
245 } else { 281 } else {
246 arg_value_str = sp_convert_to_string(arg_value); 282 arg_value_str = sp_convert_to_string(arg_value);
247 if (true == sp_match_value(arg_value_str, config_node->value, 283 if (true == sp_match_value(arg_value_str, config_node->value,
248 config_node->value_r)) { 284 config_node->value_r)) {
249 arg_matched = true; 285 arg_matched = true;
250 break; 286 break;
251 } 287 }
252 } 288 }
253 } 289 }
290 }
254 } 291 }
255 if (false == arg_matched) { 292 if (false == arg_matched) {
256 goto next; 293 goto next;
@@ -273,14 +310,18 @@ bool should_disable(zend_execute_data* execute_data) {
273 if (true == config_node->simulation) { 310 if (true == config_node->simulation) {
274 goto next; 311 goto next;
275 } else { // We've got a match, the function won't be executed 312 } else { // We've got a match, the function won't be executed
276 efree(complete_path_function); 313 if (builtin_name == NULL) {
314 efree(complete_path_function);
315 }
277 return true; 316 return true;
278 } 317 }
279next: 318next:
280config = config->next; 319config = config->next;
281 } 320 }
282allow: 321allow:
283 efree(complete_path_function); 322 if (builtin_name == NULL) {
323 efree(complete_path_function);
324 }
284 return false; 325 return false;
285} 326}
286 327
@@ -370,7 +411,7 @@ ZEND_FUNCTION(check_disabled_function) {
370 void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); 411 void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS);
371 const char* current_function_name = get_active_function_name(TSRMLS_C); 412 const char* current_function_name = get_active_function_name(TSRMLS_C);
372 413
373 if (true == should_disable(execute_data)) { 414 if (true == should_disable(execute_data, NULL, NULL, NULL)) {
374 sp_terminate(); 415 sp_terminate();
375 } 416 }
376 417
diff --git a/src/sp_disabled_functions.h b/src/sp_disabled_functions.h
index 260d430..e9180c9 100644
--- a/src/sp_disabled_functions.h
+++ b/src/sp_disabled_functions.h
@@ -2,6 +2,6 @@
2#define __SP_DISABLE_FUNCTIONS_H 2#define __SP_DISABLE_FUNCTIONS_H
3 3
4int hook_disabled_functions(); 4int hook_disabled_functions();
5bool should_disable(zend_execute_data* function_name); 5bool should_disable(zend_execute_data*, const char *, const char *, const char *);
6 6
7#endif /* __SP_DISABLE_FUNCTIONS_H */ 7#endif /* __SP_DISABLE_FUNCTIONS_H */
diff --git a/src/sp_execute.c b/src/sp_execute.c
index 45a4ae6..086d769 100644
--- a/src/sp_execute.c
+++ b/src/sp_execute.c
@@ -28,49 +28,55 @@ ZEND_COLD static inline void terminate_if_writable(const char *filename) {
28 } 28 }
29} 29}
30 30
31static void construct_include_handler(const char * const filename) { 31static void is_builtin_matching(const char * const filename, char* function_name,
32 if (SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_include) { 32 char *param_name, sp_node_t *config) {
33 const sp_node_t* config = SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_include; 33 if (!config || !config->data) {
34 if (!config || !config->data) { 34 return;
35 return; 35 }
36 } 36
37 if (true == should_disable(EG(current_execute_data), function_name, filename, param_name)) {
38 sp_terminate();
39 }
40}
41
42char *get_eval_filename(const char *filename) {
43 size_t i = strlen(filename) - 1;
44 int count = 0;
45 char *clean_filename = estrdup(filename);
37 46
38 while (config) { 47 //ghetto as fuck
39 sp_disabled_function *config_node = (sp_disabled_function*)(config->data); 48 //get the filename in which eval() is called from "foo.php(1) : eval()'d code"
40 if (true == sp_match_value(filename, config_node->value, config_node->value_r)) { 49 while (i) {
41 if (true == config_node->allow) { 50 if (clean_filename[i] == '(') {
42 return; 51 if (count == 1) {
43 } 52 clean_filename[i] = 0;
44 sp_log_disable("include", "inclusion path", filename, config_node); 53 break;
45 if (false == config_node->simulation) {
46 sp_terminate();
47 }
48 } 54 }
49 config = config->next; 55 count++;
50 } 56 }
57 i--;
51 } 58 }
59 return clean_filename;
52} 60}
53 61
54static void sp_execute_ex(zend_execute_data *execute_data) { 62static void sp_execute_ex(zend_execute_data *execute_data) {
55 if (NULL == execute_data->func->common.function_name) { 63 if (true == should_disable(execute_data, NULL, NULL, NULL)) {
56 goto execute;
57 }
58
59 if (true == should_disable(execute_data)) {
60 sp_terminate(); 64 sp_terminate();
61 } 65 }
62 66
63 if (execute_data->func->op_array.type == ZEND_EVAL_CODE) { 67 if (execute_data->func->op_array.type == ZEND_EVAL_CODE) {
64 sp_log_debug("Currently in an eval\n"); 68 sp_node_t* config = SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval;
69 char *filename = get_eval_filename((char *)zend_get_executed_filename());
70 is_builtin_matching(filename, "eval", NULL, config);
71 efree(filename);
65 } 72 }
66 73
67 if (NULL != execute_data->func->op_array.filename) { 74 if (NULL != execute_data->func->op_array.filename) {
68 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { 75 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) {
69 terminate_if_writable(ZSTR_VAL(execute_data->func->op_array.filename)); 76 terminate_if_writable(ZSTR_VAL(execute_data->func->op_array.filename));
70 } 77 }
71} 78 }
72 79
73execute:
74 orig_execute_ex(execute_data); 80 orig_execute_ex(execute_data);
75} 81}
76 82
@@ -86,7 +92,26 @@ static int sp_stream_open(const char *filename, zend_file_handle *handle) {
86 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { 92 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) {
87 terminate_if_writable(filename); 93 terminate_if_writable(filename);
88 } 94 }
89 construct_include_handler(filename); 95 sp_node_t* config = SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_include;
96 switch (data->opline->extended_value) {
97 case ZEND_INCLUDE:
98 is_builtin_matching(filename, "include", "inclusion path", config);
99 break;
100 case ZEND_REQUIRE:
101 is_builtin_matching(filename, "require", "inclusion path", config);
102 break;
103 case ZEND_REQUIRE_ONCE:
104 is_builtin_matching(filename, "require_once", "inclusion path", config);
105 break;
106 case ZEND_INCLUDE_ONCE:
107 is_builtin_matching(filename, "include_once", "inclusion path", config);
108 break;
109 case ZEND_EVAL:
110 is_builtin_matching(filename, "eval", NULL, config);
111 break;
112 default:
113 break;
114 }
90 } 115 }
91 116
92end: 117end:
diff --git a/src/sp_execute.h b/src/sp_execute.h
index 8345736..6ef50ee 100644
--- a/src/sp_execute.h
+++ b/src/sp_execute.h
@@ -2,5 +2,6 @@
2#define SP_EXECUTE_H 2#define SP_EXECUTE_H
3 3
4int hook_execute(void); 4int hook_execute(void);
5char *get_eval_filename(const char *filename);
5 6
6#endif /* SP_EXECUTE_H */ 7#endif /* SP_EXECUTE_H */
diff --git a/src/sp_utils.c b/src/sp_utils.c
index 514fc10..28c8a8b 100644
--- a/src/sp_utils.c
+++ b/src/sp_utils.c
@@ -229,6 +229,8 @@ bool sp_match_value(const char* value, const char* to_match, const pcre* rx) {
229 } 229 }
230 } else if (rx) { 230 } else if (rx) {
231 return is_regexp_matching(rx, value); 231 return is_regexp_matching(rx, value);
232 } else {
233 return true;
232 } 234 }
233 return false; 235 return false;
234} 236}
diff --git a/src/tests/config/config_disabled_functions_eval_filename.ini b/src/tests/config/config_disabled_functions_eval_filename.ini
new file mode 100644
index 0000000..f66cef3
--- /dev/null
+++ b/src/tests/config/config_disabled_functions_eval_filename.ini
@@ -0,0 +1 @@
sp.disable_function.function("eval").filename_r("^.*tests/disabled_functions_eval_filename.php$").drop();
diff --git a/src/tests/config/disabled_functions.ini b/src/tests/config/disabled_functions.ini
index 226a107..df7013f 100644
--- a/src/tests/config/disabled_functions.ini
+++ b/src/tests/config/disabled_functions.ini
@@ -5,4 +5,5 @@ sp.disable_function.function("printf").simulation().drop();
5sp.disable_function.function("print").disable().drop(); # this is a comment 5sp.disable_function.function("print").disable().drop(); # this is a comment
6sp.disable_function.function_r("^var_dump$").drop(); 6sp.disable_function.function_r("^var_dump$").drop();
7sp.disable_function.function("sprintf").filename("/wrong file name").drop(); 7sp.disable_function.function("sprintf").filename("/wrong file name").drop();
8sp.disable_function.function("sprintf").filename("/wrong file name").drop();
8sp.disable_function.function("eval").drop(); 9sp.disable_function.function("eval").drop();
diff --git a/src/tests/config/disabled_functions_eval.ini b/src/tests/config/disabled_functions_eval.ini
new file mode 100644
index 0000000..f761259
--- /dev/null
+++ b/src/tests/config/disabled_functions_eval.ini
@@ -0,0 +1 @@
sp.disable_function.function("eval").drop();
diff --git a/src/tests/config/disabled_functions_eval_simulation.ini b/src/tests/config/disabled_functions_eval_simulation.ini
new file mode 100644
index 0000000..f1dc58c
--- /dev/null
+++ b/src/tests/config/disabled_functions_eval_simulation.ini
@@ -0,0 +1 @@
sp.disable_function.function("eval").drop().simulation();
diff --git a/src/tests/deny_writable_execution.phpt b/src/tests/deny_writable_execution.phpt
index 2870561..c399d35 100644
--- a/src/tests/deny_writable_execution.phpt
+++ b/src/tests/deny_writable_execution.phpt
@@ -32,8 +32,7 @@ include "$dir/non_writable_file.txt";
32include "$dir/writable_file.txt"; 32include "$dir/writable_file.txt";
33?> 33?>
34--EXPECTF-- 34--EXPECTF--
35Code execution within a non-writable file. 35[snuffleupagus][0.0.0.0][readonly_exec][drop] Attempted execution of a writable file (%a/tests/deny_writable_execution.php).
36[snuffleupagus][0.0.0.0][readonly_exec][drop] Attempted execution of a writable file (%a/writable_file.txt).
37--CLEAN-- 36--CLEAN--
38<?php 37<?php
39$dir = __DIR__; 38$dir = __DIR__;
@@ -41,4 +40,4 @@ chmod("$dir/non_writable_file.txt", 0777);
41chmod("$dir/writable_file.txt", 0777); 40chmod("$dir/writable_file.txt", 0777);
42unlink("$dir/non_writable_file.txt"); 41unlink("$dir/non_writable_file.txt");
43unlink("$dir/writable_file.txt"); 42unlink("$dir/writable_file.txt");
44?> \ No newline at end of file 43?>
diff --git a/src/tests/disabled_functions_eval.phpt b/src/tests/disabled_functions_eval.phpt
index 0beaefe..7bd6b4b 100644
--- a/src/tests/disabled_functions_eval.phpt
+++ b/src/tests/disabled_functions_eval.phpt
@@ -3,13 +3,12 @@ Disable functions - eval
3--SKIPIF-- 3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> 4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI-- 5--INI--
6sp.configuration_file={PWD}/config/disabled_functions.ini 6sp.configuration_file={PWD}/config/disabled_functions_eval.ini
7--XFAIL--
8--FILE-- 7--FILE--
9<?php 8<?php
10$var = 1234; 9$var = 123456789;
11eval('$var = 1337;'); 10eval('$var = 1337 + 1337;');
12print("Variable: $var\n"); 11print("Variable: $var\n");
13?> 12?>
14--EXPECTF-- 13--EXPECTF--
15[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'eval' in %a/tests/disabled_functions_eval.php:%d has been disabled, because it matched a rule. 14[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'eval' in %a/tests/disabled_functions_eval.php(%d) : eval()'d code:%d has been disabled.
diff --git a/src/tests/disabled_functions_eval_filename.phpt b/src/tests/disabled_functions_eval_filename.phpt
new file mode 100644
index 0000000..5e64acc
--- /dev/null
+++ b/src/tests/disabled_functions_eval_filename.phpt
@@ -0,0 +1,14 @@
1--TEST--
2Disable functions - eval
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/config_disabled_functions_eval_filename.ini
7--FILE--
8<?php
9$var = 123456789;
10eval('$var = 1337 + 1337;');
11print("Variable: $var\n");
12?>
13--EXPECTF--
14[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'eval' in %a/tests/disabled_functions_eval_filename.php(%d) : eval()'d code:%d has been disabled.
diff --git a/src/tests/disabled_functions_eval_simulation.phpt b/src/tests/disabled_functions_eval_simulation.phpt
new file mode 100644
index 0000000..06a006e
--- /dev/null
+++ b/src/tests/disabled_functions_eval_simulation.phpt
@@ -0,0 +1,15 @@
1--TEST--
2Disable functions - eval (simulation)
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/disabled_functions_eval_simulation.ini
7--FILE--
8<?php
9$var = 123456789;
10eval('$var = 1337 + 1337;');
11print("Variable: $var\n");
12?>
13--EXPECTF--
14[snuffleupagus][0.0.0.0][disabled_function][simulation] The call to the function 'eval' in %a/tests/disabled_functions_eval_simulation.php(%d) : eval()'d code:%d has been disabled.
15Variable: 2674
diff --git a/src/tests/disabled_functions_require.phpt b/src/tests/disabled_functions_require.phpt
index f848f8b..cc904f1 100644
--- a/src/tests/disabled_functions_require.phpt
+++ b/src/tests/disabled_functions_require.phpt
@@ -14,7 +14,7 @@ require $dir . '/test.meh';
14echo "1337"; 14echo "1337";
15?> 15?>
16--EXPECTF-- 16--EXPECTF--
17BLA[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'include' in %a/disabled_functions_require.php:%d has been disabled, because its argument 'inclusion path' content (%a/test.meh) matched a rule. 17BLA[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'require' in %a/disabled_functions_require.php:%d has been disabled, because its argument 'inclusion path' content (%a/test.meh) matched a rule.
18--CLEAN-- 18--CLEAN--
19<?php 19<?php
20$dir = __DIR__; 20$dir = __DIR__;
diff --git a/src/tests/disabled_functions_require_simulation.phpt b/src/tests/disabled_functions_require_simulation.phpt
index 2744c37..bd49268 100644
--- a/src/tests/disabled_functions_require_simulation.phpt
+++ b/src/tests/disabled_functions_require_simulation.phpt
@@ -15,7 +15,7 @@ echo "1337\n";
15?> 15?>
16--EXPECTF-- 16--EXPECTF--
17BLA 17BLA
18[snuffleupagus][0.0.0.0][disabled_function][simulation] The call to the function 'include' in %a/disabled_functions_require_simulation.php:%d has been disabled, because its argument 'inclusion path' content (%a/test.sim) matched a rule. 18[snuffleupagus][0.0.0.0][disabled_function][simulation] The call to the function 'require' in %a/disabled_functions_require_simulation.php:%d has been disabled, because its argument 'inclusion path' content (%a/test.sim) matched a rule.
19MEH 19MEH
201337 201337
21--CLEAN-- 21--CLEAN--