diff options
| author | jvoisin | 2017-11-29 11:36:57 +0100 |
|---|---|---|
| committer | GitHub | 2017-11-29 11:36:57 +0100 |
| commit | 10437787b0e8ede80976de4a1c22775fc1282f36 (patch) | |
| tree | 1ab911ab000989b98449475eda655a797e278049 /src/sp_disabled_functions.c | |
| parent | 8df77884f38e7a7334b56aafe2f441567f175af8 (diff) | |
Implement eval hooking
It's not possible to hook the `eval` builtin like other functions.
Diffstat (limited to 'src/sp_disabled_functions.c')
| -rw-r--r-- | src/sp_disabled_functions.c | 153 |
1 files changed, 97 insertions, 56 deletions
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 | ||
| 104 | bool should_disable(zend_execute_data* execute_data) { | 104 | static 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 | |||
| 120 | bool 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 | } |
| 279 | next: | 318 | next: |
| 280 | config = config->next; | 319 | config = config->next; |
| 281 | } | 320 | } |
| 282 | allow: | 321 | allow: |
| 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 | ||
