diff options
| author | jvoisin | 2018-01-10 17:38:24 +0100 |
|---|---|---|
| committer | jvoisin | 2018-01-10 17:38:24 +0100 |
| commit | 6f21bff1d40326f69bc3b75b1b83b03623180365 (patch) | |
| tree | 09cc459ca549693d69f35098046d8ad64f3cde91 /src | |
| parent | 773c9b94c6978ccd41c5a46f0d03448fd0c039a7 (diff) | |
Rework the priority of bl/wl in eval
Diffstat (limited to 'src')
| -rw-r--r-- | src/sp_disabled_functions.c | 9 | ||||
| -rw-r--r-- | src/sp_execute.c | 34 | ||||
| -rw-r--r-- | src/sp_utils.c | 21 | ||||
| -rw-r--r-- | src/sp_utils.h | 1 | ||||
| -rw-r--r-- | src/tests/config/eval_whitelist_blacklist.ini | 2 | ||||
| -rw-r--r-- | src/tests/eval_backlist_whitelist.phpt | 10 | ||||
| -rw-r--r-- | src/tests/eval_whitelist.phpt | 27 |
7 files changed, 73 insertions, 31 deletions
diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c index fa9d625..07c8696 100644 --- a/src/sp_disabled_functions.c +++ b/src/sp_disabled_functions.c | |||
| @@ -5,9 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | 6 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) |
| 7 | 7 | ||
| 8 | 8 | char* get_complete_function_path(zend_execute_data const* const execute_data) { | |
| 9 | char* get_complete_function_path( | ||
| 10 | zend_execute_data const* const execute_data) { | ||
| 11 | if (zend_is_executing() && !EG(current_execute_data)->func) { | 9 | if (zend_is_executing() && !EG(current_execute_data)->func) { |
| 12 | return NULL; | 10 | return NULL; |
| 13 | } | 11 | } |
| @@ -469,6 +467,10 @@ ZEND_FUNCTION(eval_blacklist_callback) { | |||
| 469 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); | 467 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); |
| 470 | const char* current_function_name = get_active_function_name(TSRMLS_C); | 468 | const char* current_function_name = get_active_function_name(TSRMLS_C); |
| 471 | 469 | ||
| 470 | if (true == check_is_in_eval_whitelist(current_function_name)) { | ||
| 471 | goto whitelisted; | ||
| 472 | } | ||
| 473 | |||
| 472 | if (SNUFFLEUPAGUS_G(in_eval) > 0) { | 474 | if (SNUFFLEUPAGUS_G(in_eval) > 0) { |
| 473 | const char* filename = get_eval_filename(zend_get_executed_filename()); | 475 | const char* filename = get_eval_filename(zend_get_executed_filename()); |
| 474 | const int line_number = zend_get_executed_lineno(TSRMLS_C); | 476 | const int line_number = zend_get_executed_lineno(TSRMLS_C); |
| @@ -484,6 +486,7 @@ ZEND_FUNCTION(eval_blacklist_callback) { | |||
| 484 | } | 486 | } |
| 485 | } | 487 | } |
| 486 | 488 | ||
| 489 | whitelisted: | ||
| 487 | orig_handler = zend_hash_str_find_ptr( | 490 | orig_handler = zend_hash_str_find_ptr( |
| 488 | SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook), current_function_name, | 491 | SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook), current_function_name, |
| 489 | strlen(current_function_name)); | 492 | strlen(current_function_name)); |
diff --git a/src/sp_execute.c b/src/sp_execute.c index e6df1b6..ac7cee3 100644 --- a/src/sp_execute.c +++ b/src/sp_execute.c | |||
| @@ -44,7 +44,8 @@ static void is_builtin_matching(const char *restrict const filename, | |||
| 44 | } | 44 | } |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | static void is_in_eval_and_whitelisted(const zend_execute_data *execute_data) { | 47 | static void ZEND_HOT |
| 48 | is_in_eval_and_whitelisted(const zend_execute_data *execute_data) { | ||
| 48 | if (EXPECTED(0 == SNUFFLEUPAGUS_G(in_eval))) { | 49 | if (EXPECTED(0 == SNUFFLEUPAGUS_G(in_eval))) { |
| 49 | return; | 50 | return; |
| 50 | } | 51 | } |
| @@ -61,25 +62,16 @@ static void is_in_eval_and_whitelisted(const zend_execute_data *execute_data) { | |||
| 61 | return; | 62 | return; |
| 62 | } | 63 | } |
| 63 | 64 | ||
| 64 | char const* const current_function = ZSTR_VAL(EX(func)->common.function_name); | 65 | char const *const current_function = ZSTR_VAL(EX(func)->common.function_name); |
| 65 | 66 | ||
| 66 | if (EXPECTED(current_function)) { | 67 | if (EXPECTED(NULL != current_function)) { |
| 67 | const sp_list_node *it = SNUFFLEUPAGUS_G(config).config_eval->whitelist; | 68 | if (false == check_is_in_eval_whitelist(current_function)) { |
| 68 | /* yes, we could use a HashTable instead, but since the list is pretty | 69 | sp_log_msg( |
| 69 | * small, it doesn't maka a difference in practise. */ | 70 | "Eval_whitelist", SP_LOG_DROP, |
| 70 | while (it) { | 71 | "The function '%s' isn't in the eval whitelist, dropping its call.", |
| 71 | if (0 == strcmp(current_function, (char *)(it->data))) { | 72 | current_function); |
| 72 | /* We've got a match, the function is whiteslited. */ | 73 | sp_terminate(); |
| 73 | return; | ||
| 74 | } | ||
| 75 | it = it->next; | ||
| 76 | } | 74 | } |
| 77 | |||
| 78 | sp_log_msg( | ||
| 79 | "Eval_whitelist", SP_LOG_DROP, | ||
| 80 | "The function '%s' isn't in the eval whitelist, dropping its call.", | ||
| 81 | current_function); | ||
| 82 | sp_terminate(); | ||
| 83 | } | 75 | } |
| 84 | } | 76 | } |
| 85 | 77 | ||
| @@ -104,6 +96,8 @@ char *get_eval_filename(const char *filename) { | |||
| 104 | } | 96 | } |
| 105 | 97 | ||
| 106 | static void sp_execute_ex(zend_execute_data *execute_data) { | 98 | static void sp_execute_ex(zend_execute_data *execute_data) { |
| 99 | is_in_eval_and_whitelisted(execute_data); | ||
| 100 | |||
| 107 | if (true == should_disable(execute_data, NULL, NULL, NULL)) { | 101 | if (true == should_disable(execute_data, NULL, NULL, NULL)) { |
| 108 | sp_terminate(); | 102 | sp_terminate(); |
| 109 | } | 103 | } |
| @@ -117,8 +111,6 @@ static void sp_execute_ex(zend_execute_data *execute_data) { | |||
| 117 | efree(filename); | 111 | efree(filename); |
| 118 | } | 112 | } |
| 119 | 113 | ||
| 120 | is_in_eval_and_whitelisted(execute_data); | ||
| 121 | |||
| 122 | if (NULL != EX(func)->op_array.filename) { | 114 | if (NULL != EX(func)->op_array.filename) { |
| 123 | if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { | 115 | if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { |
| 124 | terminate_if_writable(ZSTR_VAL(EX(func)->op_array.filename)); | 116 | terminate_if_writable(ZSTR_VAL(EX(func)->op_array.filename)); |
| @@ -176,7 +168,7 @@ static int sp_stream_open(const char *filename, zend_file_handle *handle) { | |||
| 176 | is_builtin_matching(filename, "include_once", "inclusion path", | 168 | is_builtin_matching(filename, "include_once", "inclusion path", |
| 177 | config); | 169 | config); |
| 178 | break; | 170 | break; |
| 179 | EMPTY_SWITCH_DEFAULT_CASE(); | 171 | EMPTY_SWITCH_DEFAULT_CASE(); |
| 180 | } | 172 | } |
| 181 | } | 173 | } |
| 182 | 174 | ||
diff --git a/src/sp_utils.c b/src/sp_utils.c index 8a1ed87..19b7179 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | #include <string.h> | 7 | #include <string.h> |
| 8 | #include <unistd.h> | 8 | #include <unistd.h> |
| 9 | 9 | ||
| 10 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | ||
| 11 | |||
| 10 | static inline void _sp_log_err(const char* fmt, ...) { | 12 | static inline void _sp_log_err(const char* fmt, ...) { |
| 11 | char* msg; | 13 | char* msg; |
| 12 | va_list args; | 14 | va_list args; |
| @@ -394,3 +396,22 @@ int hook_regexp(const pcre* regexp, HashTable* hook_table, | |||
| 394 | ZEND_HASH_FOREACH_END(); | 396 | ZEND_HASH_FOREACH_END(); |
| 395 | return SUCCESS; | 397 | return SUCCESS; |
| 396 | } | 398 | } |
| 399 | |||
| 400 | bool check_is_in_eval_whitelist(const char* const function_name) { | ||
| 401 | const sp_list_node* it = SNUFFLEUPAGUS_G(config).config_eval->whitelist; | ||
| 402 | |||
| 403 | if (!it->head) { | ||
| 404 | return false; | ||
| 405 | } | ||
| 406 | |||
| 407 | /* yes, we could use a HashTable instead, but since the list is pretty | ||
| 408 | * small, it doesn't maka a difference in practise. */ | ||
| 409 | while (it && it->data) { | ||
| 410 | if (0 == strcmp(function_name, (char*)(it->data))) { | ||
| 411 | /* We've got a match, the function is whiteslited. */ | ||
| 412 | return true; | ||
| 413 | } | ||
| 414 | it = it->next; | ||
| 415 | } | ||
| 416 | return false; | ||
| 417 | } | ||
diff --git a/src/sp_utils.h b/src/sp_utils.h index e055e70..a7b672f 100644 --- a/src/sp_utils.h +++ b/src/sp_utils.h | |||
| @@ -69,5 +69,6 @@ int hook_function(const char *, HashTable *, | |||
| 69 | void (*)(INTERNAL_FUNCTION_PARAMETERS), bool); | 69 | void (*)(INTERNAL_FUNCTION_PARAMETERS), bool); |
| 70 | int hook_regexp(const pcre *, HashTable *, | 70 | int hook_regexp(const pcre *, HashTable *, |
| 71 | void (*)(INTERNAL_FUNCTION_PARAMETERS), bool); | 71 | void (*)(INTERNAL_FUNCTION_PARAMETERS), bool); |
| 72 | bool check_is_in_eval_whitelist(const char * const function_name); | ||
| 72 | 73 | ||
| 73 | #endif /* SP_UTILS_H */ | 74 | #endif /* SP_UTILS_H */ |
diff --git a/src/tests/config/eval_whitelist_blacklist.ini b/src/tests/config/eval_whitelist_blacklist.ini new file mode 100644 index 0000000..a916004 --- /dev/null +++ b/src/tests/config/eval_whitelist_blacklist.ini | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | sp.eval_blacklist.list("my_fun,cos"); | ||
| 2 | sp.eval_whitelist.list("my_fun"); | ||
diff --git a/src/tests/eval_backlist_whitelist.phpt b/src/tests/eval_backlist_whitelist.phpt index 1611288..9b0bb55 100644 --- a/src/tests/eval_backlist_whitelist.phpt +++ b/src/tests/eval_backlist_whitelist.phpt | |||
| @@ -3,25 +3,21 @@ Eval whitelist | |||
| 3 | --SKIPIF-- | 3 | --SKIPIF-- |
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> |
| 5 | --INI-- | 5 | --INI-- |
| 6 | sp.configuration_file={PWD}/config/eval_whitelist.ini | 6 | sp.configuration_file={PWD}/config/eval_whitelist_blacklist.ini |
| 7 | --FILE-- | 7 | --FILE-- |
| 8 | <?php | 8 | <?php |
| 9 | function my_fun($p) { | 9 | function my_fun($p) { |
| 10 | return "my_fun: $p"; | 10 | return "my_fun: $p"; |
| 11 | } | 11 | } |
| 12 | 12 | ||
| 13 | function my_other_fun($p) { | ||
| 14 | return "my_other_fun: $p"; | ||
| 15 | } | ||
| 16 | |||
| 17 | $a = my_fun("1337 1337 1337"); | 13 | $a = my_fun("1337 1337 1337"); |
| 18 | echo "Outside of eval: $a\n"; | 14 | echo "Outside of eval: $a\n"; |
| 19 | eval('$a = my_fun("1234");'); | 15 | eval('$a = my_fun("1234");'); |
| 20 | echo "After allowed eval: $a\n"; | 16 | echo "After allowed eval: $a\n"; |
| 21 | eval('$a = my_other_fun("1234");'); | 17 | eval('$a = cos(1234);'); |
| 22 | echo "After eval: $a\n"; | 18 | echo "After eval: $a\n"; |
| 23 | ?> | 19 | ?> |
| 24 | --EXPECTF-- | 20 | --EXPECTF-- |
| 25 | Outside of eval: my_fun: 1337 1337 1337 | 21 | Outside of eval: my_fun: 1337 1337 1337 |
| 26 | After allowed eval: my_fun: 1234 | 22 | After 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. | 23 | [snuffleupagus][0.0.0.0][Eval_whitelist][drop] The function 'cos' isn't in the eval whitelist, dropping its call. |
diff --git a/src/tests/eval_whitelist.phpt b/src/tests/eval_whitelist.phpt new file mode 100644 index 0000000..1611288 --- /dev/null +++ b/src/tests/eval_whitelist.phpt | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | --TEST-- | ||
| 2 | Eval whitelist | ||
| 3 | --SKIPIF-- | ||
| 4 | <?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> | ||
| 5 | --INI-- | ||
| 6 | sp.configuration_file={PWD}/config/eval_whitelist.ini | ||
| 7 | --FILE-- | ||
| 8 | <?php | ||
| 9 | function my_fun($p) { | ||
| 10 | return "my_fun: $p"; | ||
| 11 | } | ||
| 12 | |||
| 13 | function my_other_fun($p) { | ||
| 14 | return "my_other_fun: $p"; | ||
| 15 | } | ||
| 16 | |||
| 17 | $a = my_fun("1337 1337 1337"); | ||
| 18 | echo "Outside of eval: $a\n"; | ||
| 19 | eval('$a = my_fun("1234");'); | ||
| 20 | echo "After allowed eval: $a\n"; | ||
| 21 | eval('$a = my_other_fun("1234");'); | ||
| 22 | echo "After eval: $a\n"; | ||
| 23 | ?> | ||
| 24 | --EXPECTF-- | ||
| 25 | Outside of eval: my_fun: 1337 1337 1337 | ||
| 26 | After 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. | ||
