summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjvoisin2018-01-10 14:56:33 +0100
committerGitHub2018-01-10 14:56:33 +0100
commitad6b3e723fe26bf1a3a573aed776960916d35499 (patch)
treeeec9e15028f4529d776489d273bf9699333aa987 /src
parentb6e5bc4557cca3abbcfd179e7143ea54b9844e49 (diff)
Eval whitelist
Implement whitelist in eval
Diffstat (limited to 'src')
-rw-r--r--src/php_snuffleupagus.h4
-rw-r--r--src/snuffleupagus.c4
-rw-r--r--src/sp_config.c3
-rw-r--r--src/sp_config.h6
-rw-r--r--src/sp_config_keywords.c16
-rw-r--r--src/sp_config_keywords.h3
-rw-r--r--src/sp_disabled_functions.c12
-rw-r--r--src/sp_disabled_functions.h1
-rw-r--r--src/sp_execute.c88
-rw-r--r--src/tests/config/eval_backlist.ini2
-rw-r--r--src/tests/config/eval_backlist_list.ini2
-rw-r--r--src/tests/config/eval_backlist_simulation.ini2
-rw-r--r--src/tests/config/eval_whitelist.ini1
-rw-r--r--src/tests/eval_backlist_whitelist.phpt27
-rw-r--r--src/tests/eval_whitelist_builtin.phpt19
-rw-r--r--src/tests/eval_whitelist_include_then_user.phpt29
-rw-r--r--src/tests/eval_whitelist_user_then_builtin.phpt23
17 files changed, 203 insertions, 39 deletions
diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h
index ca39bb8..93ef472 100644
--- a/src/php_snuffleupagus.h
+++ b/src/php_snuffleupagus.h
@@ -63,7 +63,7 @@ sp_config config;
63bool is_config_valid; 63bool is_config_valid;
64HashTable *disabled_functions_hook; 64HashTable *disabled_functions_hook;
65HashTable *sp_internal_functions_hook; 65HashTable *sp_internal_functions_hook;
66HashTable *sp_eval_filter_functions_hook; 66HashTable *sp_eval_blacklist_functions_hook;
67ZEND_END_MODULE_GLOBALS(snuffleupagus) 67ZEND_END_MODULE_GLOBALS(snuffleupagus)
68 68
69#define SNUFFLEUPAGUS_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(snuffleupagus, v) 69#define SNUFFLEUPAGUS_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(snuffleupagus, v)
@@ -85,7 +85,7 @@ ZEND_TSRMLS_CACHE_EXTERN()
85#endif 85#endif
86 86
87PHP_FUNCTION(check_disabled_function); 87PHP_FUNCTION(check_disabled_function);
88PHP_FUNCTION(eval_filter_callback); 88PHP_FUNCTION(eval_blacklist_callback);
89 89
90static inline void sp_terminate() { zend_bailout(); } 90static inline void sp_terminate() { zend_bailout(); }
91 91
diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c
index 4f11e1e..cb79b23 100644
--- a/src/snuffleupagus.c
+++ b/src/snuffleupagus.c
@@ -62,7 +62,7 @@ PHP_GINIT_FUNCTION(snuffleupagus) {
62 62
63 SP_INIT_HT(snuffleupagus_globals->disabled_functions_hook); 63 SP_INIT_HT(snuffleupagus_globals->disabled_functions_hook);
64 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); 65 SP_INIT_HT(snuffleupagus_globals->sp_eval_blacklist_functions_hook);
66 66
67 SP_INIT(snuffleupagus_globals->config.config_unserialize); 67 SP_INIT(snuffleupagus_globals->config.config_unserialize);
68 SP_INIT(snuffleupagus_globals->config.config_random); 68 SP_INIT(snuffleupagus_globals->config.config_random);
@@ -106,7 +106,7 @@ PHP_MSHUTDOWN_FUNCTION(snuffleupagus) {
106 pefree(SNUFFLEUPAGUS_G(F), 1); 106 pefree(SNUFFLEUPAGUS_G(F), 1);
107 107
108 FREE_HT(disabled_functions_hook); 108 FREE_HT(disabled_functions_hook);
109 FREE_HT(sp_eval_filter_functions_hook); 109 FREE_HT(sp_eval_blacklist_functions_hook);
110 110
111#undef FREE_HT 111#undef FREE_HT
112 112
diff --git a/src/sp_config.c b/src/sp_config.c
index dc5aae9..4037e26 100644
--- a/src/sp_config.c
+++ b/src/sp_config.c
@@ -19,7 +19,8 @@ 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 {.func = parse_eval_blacklist, .token = SP_TOKEN_EVAL_BLACKLIST},
23 {.func = parse_eval_whitelist, .token = SP_TOKEN_EVAL_WHITELIST},
23 {NULL, NULL}}; 24 {NULL, NULL}};
24 25
25/* Top level keyword parsing */ 26/* Top level keyword parsing */
diff --git a/src/sp_config.h b/src/sp_config.h
index a4a4f10..25963f1 100644
--- a/src/sp_config.h
+++ b/src/sp_config.h
@@ -177,7 +177,8 @@ typedef struct {
177#define SP_TOKEN_UNSERIALIZE_HMAC ".unserialize_hmac" 177#define SP_TOKEN_UNSERIALIZE_HMAC ".unserialize_hmac"
178#define SP_TOKEN_UPLOAD_VALIDATION ".upload_validation" 178#define SP_TOKEN_UPLOAD_VALIDATION ".upload_validation"
179#define SP_TOKEN_DISABLE_XXE ".disable_xxe" 179#define SP_TOKEN_DISABLE_XXE ".disable_xxe"
180#define SP_TOKEN_EVAL ".eval_filter" 180#define SP_TOKEN_EVAL_BLACKLIST ".eval_blacklist"
181#define SP_TOKEN_EVAL_WHITELIST ".eval_whitelist"
181 182
182// common tokens 183// common tokens
183#define SP_TOKEN_ENABLE ".enable(" 184#define SP_TOKEN_ENABLE ".enable("
@@ -231,8 +232,7 @@ typedef struct {
231#define SP_TOKEN_UPLOAD_SCRIPT ".script(" 232#define SP_TOKEN_UPLOAD_SCRIPT ".script("
232 233
233// eval blacklist 234// eval blacklist
234#define SP_TOKEN_EVAL_BLACKLIST ".blacklist(" 235#define SP_TOKEN_EVAL_LIST ".list("
235#define SP_TOKEN_EVAL_WHITELIST ".whitelist("
236 236
237int sp_parse_config(const char *); 237int sp_parse_config(const char *);
238int parse_array(sp_disabled_function *); 238int parse_array(sp_disabled_function *);
diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c
index 85e04ab..c5cc950 100644
--- a/src/sp_config_keywords.c
+++ b/src/sp_config_keywords.c
@@ -102,11 +102,11 @@ 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) { 105static int parse_eval_filter_conf(char *line, sp_list_node *list) {
106 char *token; 106 char *token;
107 char *rest; 107 char *rest;
108 sp_config_functions sp_config_funcs[] = { 108 sp_config_functions sp_config_funcs[] = {
109 {parse_str, SP_TOKEN_EVAL_BLACKLIST, &rest}, 109 {parse_str, SP_TOKEN_EVAL_LIST, &rest},
110 {parse_empty, SP_TOKEN_SIMULATION, 110 {parse_empty, SP_TOKEN_SIMULATION,
111 &(SNUFFLEUPAGUS_G(config).config_eval->simulation)}, 111 &(SNUFFLEUPAGUS_G(config).config_eval->simulation)},
112 {0}}; 112 {0}};
@@ -116,11 +116,21 @@ int parse_eval_filter(char *line) {
116 } 116 }
117 117
118 while ((token = strtok_r(rest, ",", &rest))) { 118 while ((token = strtok_r(rest, ",", &rest))) {
119 sp_list_insert(SNUFFLEUPAGUS_G(config).config_eval->blacklist, token); 119 sp_list_insert(list, token);
120 } 120 }
121 return SUCCESS; 121 return SUCCESS;
122} 122}
123 123
124int parse_eval_blacklist(char *line) {
125 return parse_eval_filter_conf(line,
126 SNUFFLEUPAGUS_G(config).config_eval->blacklist);
127}
128
129int parse_eval_whitelist(char *line) {
130 return parse_eval_filter_conf(line,
131 SNUFFLEUPAGUS_G(config).config_eval->whitelist);
132}
133
124int parse_cookie(char *line) { 134int parse_cookie(char *line) {
125 int ret = 0; 135 int ret = 0;
126 char *samesite = NULL; 136 char *samesite = NULL;
diff --git a/src/sp_config_keywords.h b/src/sp_config_keywords.h
index d7ea36a..4205dac 100644
--- a/src/sp_config_keywords.h
+++ b/src/sp_config_keywords.h
@@ -12,6 +12,7 @@ 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); 15int parse_eval_blacklist(char *line);
16int parse_eval_whitelist(char *line);
16 17
17#endif // __SP_CONFIG_KEYWORDS_H 18#endif // __SP_CONFIG_KEYWORDS_H
diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c
index 8e96085..fa9d625 100644
--- a/src/sp_disabled_functions.c
+++ b/src/sp_disabled_functions.c
@@ -5,7 +5,8 @@
5 5
6ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) 6ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
7 7
8static char* get_complete_function_path( 8
9char* get_complete_function_path(
9 zend_execute_data const* const execute_data) { 10 zend_execute_data const* const execute_data) {
10 if (zend_is_executing() && !EG(current_execute_data)->func) { 11 if (zend_is_executing() && !EG(current_execute_data)->func) {
11 return NULL; 12 return NULL;
@@ -107,6 +108,7 @@ static const sp_list_node* get_config_node(const char* builtin_name) {
107 return SNUFFLEUPAGUS_G(config) 108 return SNUFFLEUPAGUS_G(config)
108 .config_disabled_constructs->construct_include; 109 .config_disabled_constructs->construct_include;
109 } 110 }
111 ZEND_ASSUME(0);
110 return NULL; // This should never happen. 112 return NULL; // This should never happen.
111} 113}
112 114
@@ -463,7 +465,7 @@ static int hook_functions(const sp_list_node* config) {
463 return SUCCESS; 465 return SUCCESS;
464} 466}
465 467
466ZEND_FUNCTION(eval_filter_callback) { 468ZEND_FUNCTION(eval_blacklist_callback) {
467 void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); 469 void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS);
468 const char* current_function_name = get_active_function_name(TSRMLS_C); 470 const char* current_function_name = get_active_function_name(TSRMLS_C);
469 471
@@ -483,7 +485,7 @@ ZEND_FUNCTION(eval_filter_callback) {
483 } 485 }
484 486
485 orig_handler = zend_hash_str_find_ptr( 487 orig_handler = zend_hash_str_find_ptr(
486 SNUFFLEUPAGUS_G(sp_eval_filter_functions_hook), current_function_name, 488 SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook), current_function_name,
487 strlen(current_function_name)); 489 strlen(current_function_name));
488 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); 490 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
489} 491}
@@ -503,8 +505,8 @@ int hook_disabled_functions(void) {
503 505
504 while (it) { 506 while (it) {
505 hook_function((char*)it->data, 507 hook_function((char*)it->data,
506 SNUFFLEUPAGUS_G(sp_eval_filter_functions_hook), 508 SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook),
507 PHP_FN(eval_filter_callback), false); 509 PHP_FN(eval_blacklist_callback), false);
508 it = it->next; 510 it = it->next;
509 } 511 }
510 } 512 }
diff --git a/src/sp_disabled_functions.h b/src/sp_disabled_functions.h
index f80c9c2..9629308 100644
--- a/src/sp_disabled_functions.h
+++ b/src/sp_disabled_functions.h
@@ -5,5 +5,6 @@ int hook_disabled_functions();
5bool should_disable(zend_execute_data *, const char *, const char *, 5bool should_disable(zend_execute_data *, const char *, const char *,
6 const char *); 6 const char *);
7bool should_drop_on_ret(zval *, const zend_execute_data *const); 7bool should_drop_on_ret(zval *, const zend_execute_data *const);
8char* get_complete_function_path(zend_execute_data const* const execute_data);
8 9
9#endif /* __SP_DISABLE_FUNCTIONS_H */ 10#endif /* __SP_DISABLE_FUNCTIONS_H */
diff --git a/src/sp_execute.c b/src/sp_execute.c
index 3ce6643..c1d68d7 100644
--- a/src/sp_execute.c
+++ b/src/sp_execute.c
@@ -6,6 +6,8 @@
6ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) 6ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
7 7
8static void (*orig_execute_ex)(zend_execute_data *execute_data); 8static void (*orig_execute_ex)(zend_execute_data *execute_data);
9static void (*orig_zend_execute_internal)(zend_execute_data *execute_data,
10 zval *return_value);
9static int (*orig_zend_stream_open)(const char *filename, 11static int (*orig_zend_stream_open)(const char *filename,
10 zend_file_handle *handle); 12 zend_file_handle *handle);
11 13
@@ -29,9 +31,9 @@ ZEND_COLD static inline void terminate_if_writable(const char *filename) {
29} 31}
30 32
31static void is_builtin_matching(const char *restrict const filename, 33static void is_builtin_matching(const char *restrict const filename,
32 char *restrict function_name, 34 const char *restrict const function_name,
33 char *restrict param_name, 35 const char *restrict const param_name,
34 sp_list_node *config) { 36 const sp_list_node *config) {
35 if (!config || !config->data) { 37 if (!config || !config->data) {
36 return; 38 return;
37 } 39 }
@@ -42,6 +44,43 @@ static void is_builtin_matching(const char *restrict const filename,
42 } 44 }
43} 45}
44 46
47static void is_in_eval_and_whitelisted(zend_execute_data *execute_data) {
48 if (EXPECTED(0 == SNUFFLEUPAGUS_G(in_eval))) {
49 return;
50 }
51
52 if (EXPECTED(NULL == SNUFFLEUPAGUS_G(config).config_eval->whitelist->data)) {
53 return;
54 }
55
56 if (zend_is_executing() && !EG(current_execute_data)->func) {
57 return;
58 }
59
60 if (!(execute_data->func->common.function_name)) {
61 return;
62 }
63
64 char const* const current_function = ZSTR_VAL(EX(func)->common.function_name);
65
66 if (EXPECTED(current_function)) {
67 const sp_list_node *it = SNUFFLEUPAGUS_G(config).config_eval->whitelist;
68 while (it) {
69 if (0 == strcmp(current_function, (char *)(it->data))) {
70 /* We've got a match, the function is whiteslited. */
71 return;
72 }
73 it = it->next;
74 }
75
76 sp_log_msg(
77 "Eval_whitelist", SP_LOG_DROP,
78 "The function '%s' isn't in the eval whitelist, dropping its call.",
79 current_function);
80 sp_terminate();
81 }
82}
83
45/* This function gets the filename in which `eval()` is called from, 84/* This function gets the filename in which `eval()` is called from,
46 * since it looks like "foo.php(1) : eval()'d code", so we're starting 85 * since it looks like "foo.php(1) : eval()'d code", so we're starting
47 * from the end of the string until the second closing parenthesis. */ 86 * from the end of the string until the second closing parenthesis. */
@@ -67,28 +106,42 @@ static void sp_execute_ex(zend_execute_data *execute_data) {
67 sp_terminate(); 106 sp_terminate();
68 } 107 }
69 108
70 if (execute_data->func->op_array.type == ZEND_EVAL_CODE) { 109 if (EX(func)->op_array.type == ZEND_EVAL_CODE) {
71 SNUFFLEUPAGUS_G(in_eval)++; 110 SNUFFLEUPAGUS_G(in_eval)++;
72 sp_list_node *config = 111 const sp_list_node *config =
73 SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval; 112 SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval;
74 char *filename = get_eval_filename((char *)zend_get_executed_filename()); 113 char *filename = get_eval_filename((char *)zend_get_executed_filename());
75 is_builtin_matching(filename, "eval", NULL, config); 114 is_builtin_matching(filename, "eval", NULL, config);
76 efree(filename); 115 efree(filename);
77 } 116 }
78 117
79 if (NULL != execute_data->func->op_array.filename) { 118 is_in_eval_and_whitelisted(execute_data);
119
120 if (NULL != EX(func)->op_array.filename) {
80 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { 121 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) {
81 terminate_if_writable(ZSTR_VAL(execute_data->func->op_array.filename)); 122 terminate_if_writable(ZSTR_VAL(EX(func)->op_array.filename));
82 } 123 }
83 } 124 }
84 125
85 orig_execute_ex(execute_data); 126 orig_execute_ex(execute_data);
86 127
87 if (true == should_drop_on_ret(execute_data->return_value, execute_data)) { 128 if (true == should_drop_on_ret(EX(return_value), execute_data)) {
88 sp_terminate(); 129 sp_terminate();
89 } 130 }
90 131
91 SNUFFLEUPAGUS_G(in_eval)--; 132 if (ZEND_EVAL_CODE == EX(func)->op_array.type) {
133 SNUFFLEUPAGUS_G(in_eval)--;
134 }
135}
136
137static void sp_zend_execute_internal(INTERNAL_FUNCTION_PARAMETERS) {
138 is_in_eval_and_whitelisted(execute_data);
139
140 EX(func)->internal_function.handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
141
142 if (UNEXPECTED(NULL != orig_zend_execute_internal)) {
143 orig_zend_execute_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
144 }
92} 145}
93 146
94static int sp_stream_open(const char *filename, zend_file_handle *handle) { 147static int sp_stream_open(const char *filename, zend_file_handle *handle) {
@@ -121,11 +174,7 @@ static int sp_stream_open(const char *filename, zend_file_handle *handle) {
121 is_builtin_matching(filename, "include_once", "inclusion path", 174 is_builtin_matching(filename, "include_once", "inclusion path",
122 config); 175 config);
123 break; 176 break;
124 case ZEND_EVAL: 177 EMPTY_SWITCH_DEFAULT_CASE();
125 is_builtin_matching(filename, "eval", NULL, config);
126 break;
127 default:
128 break;
129 } 178 }
130 } 179 }
131 180
@@ -136,16 +185,17 @@ end:
136int hook_execute(void) { 185int hook_execute(void) {
137 TSRMLS_FETCH(); 186 TSRMLS_FETCH();
138 187
139 /* zend_execute_ex is used for "classic" function calls */ 188 /* zend_execute_ex is used for "user" function calls */
140 orig_execute_ex = zend_execute_ex; 189 orig_execute_ex = zend_execute_ex;
141 zend_execute_ex = sp_execute_ex; 190 zend_execute_ex = sp_execute_ex;
142 191
143 /* zend_stream_open_function is used FIXME */ 192 /* zend_execute_internal is used for "builtin" functions calls */
193 orig_zend_execute_internal = zend_execute_internal;
194 zend_execute_internal = sp_zend_execute_internal;
195
196 /* zend_stream_open_function is used for include-related stuff */
144 orig_zend_stream_open = zend_stream_open_function; 197 orig_zend_stream_open = zend_stream_open_function;
145 zend_stream_open_function = sp_stream_open; 198 zend_stream_open_function = sp_stream_open;
146 199
147 /* zend_execute_internal is used for "indirect" functions call,
148 * like array_map or call_user_func. */
149
150 return SUCCESS; 200 return SUCCESS;
151} 201}
diff --git a/src/tests/config/eval_backlist.ini b/src/tests/config/eval_backlist.ini
index 1e34b5b..b181598 100644
--- a/src/tests/config/eval_backlist.ini
+++ b/src/tests/config/eval_backlist.ini
@@ -1 +1 @@
sp.eval_filter.blacklist("strlen"); sp.eval_blacklist.list("strlen");
diff --git a/src/tests/config/eval_backlist_list.ini b/src/tests/config/eval_backlist_list.ini
index da5650d..b395d03 100644
--- a/src/tests/config/eval_backlist_list.ini
+++ b/src/tests/config/eval_backlist_list.ini
@@ -1 +1 @@
sp.eval_filter.blacklist("strcmp,strlen"); sp.eval_blacklist.list("strcmp,strlen");
diff --git a/src/tests/config/eval_backlist_simulation.ini b/src/tests/config/eval_backlist_simulation.ini
index fafebd5..2d8dc73 100644
--- a/src/tests/config/eval_backlist_simulation.ini
+++ b/src/tests/config/eval_backlist_simulation.ini
@@ -1 +1 @@
sp.eval_filter.blacklist("strlen").simulation(); sp.eval_blacklist.list("strlen").simulation();
diff --git a/src/tests/config/eval_whitelist.ini b/src/tests/config/eval_whitelist.ini
new file mode 100644
index 0000000..7a8f6ef
--- /dev/null
+++ b/src/tests/config/eval_whitelist.ini
@@ -0,0 +1 @@
sp.eval_whitelist.list("my_fun,cos");
diff --git a/src/tests/eval_backlist_whitelist.phpt b/src/tests/eval_backlist_whitelist.phpt
new file mode 100644
index 0000000..1611288
--- /dev/null
+++ b/src/tests/eval_backlist_whitelist.phpt
@@ -0,0 +1,27 @@
1--TEST--
2Eval whitelist
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/eval_whitelist.ini
7--FILE--
8<?php
9function my_fun($p) {
10 return "my_fun: $p";
11}
12
13function my_other_fun($p) {
14 return "my_other_fun: $p";
15}
16
17$a = my_fun("1337 1337 1337");
18echo "Outside of eval: $a\n";
19eval('$a = my_fun("1234");');
20echo "After allowed eval: $a\n";
21eval('$a = my_other_fun("1234");');
22echo "After eval: $a\n";
23?>
24--EXPECTF--
25Outside of eval: my_fun: 1337 1337 1337
26After allowed eval: my_fun: 1234
27[snuffleupagus][0.0.0.0][Eval_whitelist][drop] The function 'my_other_fun' isn't in the eval whitelist, dropping its call.
diff --git a/src/tests/eval_whitelist_builtin.phpt b/src/tests/eval_whitelist_builtin.phpt
new file mode 100644
index 0000000..bd7c2ac
--- /dev/null
+++ b/src/tests/eval_whitelist_builtin.phpt
@@ -0,0 +1,19 @@
1--TEST--
2Eval whitelist - builtin function
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/eval_whitelist.ini
7--FILE--
8<?php
9$a = cos(1);
10echo "Outside of eval: $a\n";
11eval('$a = cos(5);');
12echo "After allowed eval: $a\n";
13eval('$a = sin(4);');
14echo "After eval: $a\n";
15?>
16--EXPECTF--
17Outside of eval: 0.54030230586814
18After allowed eval: 0.28366218546323
19[snuffleupagus][0.0.0.0][Eval_whitelist][drop] The function 'sin' isn't in the eval whitelist, dropping its call.
diff --git a/src/tests/eval_whitelist_include_then_user.phpt b/src/tests/eval_whitelist_include_then_user.phpt
new file mode 100644
index 0000000..6d4e36a
--- /dev/null
+++ b/src/tests/eval_whitelist_include_then_user.phpt
@@ -0,0 +1,29 @@
1--TEST--
2Eval whitelist - builtin function
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/eval_whitelist.ini
7--FILE--
8<?php
9$b = 1337;
10$dir = __DIR__;
11
12file_put_contents($dir . '/test.bla', '<?php $b = sin(1) ?>');
13
14$a = cos(1);
15echo "Outside of eval: $a\n";
16eval('$a = cos(5);');
17echo "After allowed eval: $a\n";
18eval("include_once('$dir' . '/test.bla');");
19echo "After eval: $b\n";
20?>
21--CLEAN--
22<?php
23$dir = __DIR__;
24unlink($dir . '/test.bla');
25?>
26--EXPECTF--
27Outside of eval: 0.54030230586814
28After allowed eval: 0.28366218546323
29[snuffleupagus][0.0.0.0][Eval_whitelist][drop] The function 'sin' isn't in the eval whitelist, dropping its call.
diff --git a/src/tests/eval_whitelist_user_then_builtin.phpt b/src/tests/eval_whitelist_user_then_builtin.phpt
new file mode 100644
index 0000000..8db36fc
--- /dev/null
+++ b/src/tests/eval_whitelist_user_then_builtin.phpt
@@ -0,0 +1,23 @@
1--TEST--
2Eval whitelist - builtin function
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/eval_whitelist.ini
7--FILE--
8<?php
9
10function my_fun() {
11 return sin(10);
12}
13
14$a = my_fun(1);
15echo "Outside of eval: $a\n";
16eval('$a = my_fun(5);');
17echo "After allowed eval: $a\n";
18eval('$a = my_fun(4);');
19echo "After eval: $a\n";
20?>
21--EXPECTF--
22Outside of eval: -0.54402111088937
23[snuffleupagus][0.0.0.0][Eval_whitelist][drop] The function 'sin' isn't in the eval whitelist, dropping its call.