diff options
| author | jvoisin | 2018-01-10 14:56:33 +0100 |
|---|---|---|
| committer | GitHub | 2018-01-10 14:56:33 +0100 |
| commit | ad6b3e723fe26bf1a3a573aed776960916d35499 (patch) | |
| tree | eec9e15028f4529d776489d273bf9699333aa987 /src/sp_execute.c | |
| parent | b6e5bc4557cca3abbcfd179e7143ea54b9844e49 (diff) | |
Eval whitelist
Implement whitelist in eval
Diffstat (limited to 'src/sp_execute.c')
| -rw-r--r-- | src/sp_execute.c | 88 |
1 files changed, 69 insertions, 19 deletions
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 @@ | |||
| 6 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | 6 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) |
| 7 | 7 | ||
| 8 | static void (*orig_execute_ex)(zend_execute_data *execute_data); | 8 | static void (*orig_execute_ex)(zend_execute_data *execute_data); |
| 9 | static void (*orig_zend_execute_internal)(zend_execute_data *execute_data, | ||
| 10 | zval *return_value); | ||
| 9 | static int (*orig_zend_stream_open)(const char *filename, | 11 | static 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 | ||
| 31 | static void is_builtin_matching(const char *restrict const filename, | 33 | static 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 | ||
| 47 | static 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 | |||
| 137 | static 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 | ||
| 94 | static int sp_stream_open(const char *filename, zend_file_handle *handle) { | 147 | static 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: | |||
| 136 | int hook_execute(void) { | 185 | int 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 | } |
