summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjvoisin2018-01-04 15:59:59 +0100
committerGitHub2018-01-04 15:59:59 +0100
commit3b113be573cdbca20ce9ec9c0a6efb25ccf51db5 (patch)
tree5fabbd1da7cd740f26354ffbd2234eba71ffdead
parent84e423300c440e96c34ada2620e0f78f827592e8 (diff)
Eval blacklist
Add support for eval filtering, only blacklist for now
-rw-r--r--doc/source/config.rst14
-rw-r--r--doc/source/features.rst13
-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
19 files changed, 198 insertions, 8 deletions
diff --git a/doc/source/config.rst b/doc/source/config.rst
index e42cb99..d16474f 100644
--- a/doc/source/config.rst
+++ b/doc/source/config.rst
@@ -246,6 +246,20 @@ disable_xxe
246 sp.disable_xxe.enable(); 246 sp.disable_xxe.enable();
247 247
248 248
249Eval white and blacklist
250^^^^^^^^^^^^^^^^^^^^^^^^
251 * `default: disabled`
252 * :ref:`more <eval-feature>`
253
254``eval_filter`` allows to specify white and blacklist of functions allowed and
255forbidden from being called inside ``eval``. The functions names are comma-separated.
256
257::
258
259 sp.eval_filter.blacklist("system,exec,shell_exec");
260 sp.eval_filter.whitelist("strlen,strcmp").simulation();
261
262
249Virtual-patching 263Virtual-patching
250---------------- 264----------------
251 265
diff --git a/doc/source/features.rst b/doc/source/features.rst
index afe139a..8ecf57d 100644
--- a/doc/source/features.rst
+++ b/doc/source/features.rst
@@ -321,6 +321,19 @@ Snuffleupagus can prevent the execution of this kind of file. A good practice
321would be to use a different user to run PHP than for administrating the website, 321would be to use a different user to run PHP than for administrating the website,
322and using this feature to lock this up. 322and using this feature to lock this up.
323 323
324.. _eval-feature:
325
326White and blacklist in ``eval``
327^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
328
329While `eval <https://secure.php.net/manual/en/function.eval.php>`__ is a
330dangerous primitive, tricky to use right, with almost no legitimate usage
331besides templating and building mathematical expressions based on user input,
332it's broadly (mis)used all around the web.
333
334Snuffleupagus provides a white and blacklist mechanism, to explicitly allow
335and forbid specific functions call from being issued inside ``eval``.
336
324 337
325Protection against cross site request forgery 338Protection against cross site request forgery
326^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 339^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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.