diff options
| author | xXx-caillou-xXx | 2018-07-13 10:36:50 +0200 |
|---|---|---|
| committer | jvoisin | 2018-07-13 08:36:50 +0000 |
| commit | 7963580d72a358975133f86f01de2d2eab08ba38 (patch) | |
| tree | 4bec345d70f687a2a6002b36e2f2fc79318959f6 /src/sp_disabled_functions.c | |
| parent | 12b740bc7bb01ffe397cecc5b6fa25b136304911 (diff) | |
Massively optimize how rules are handled
This commit does a lot of things:
- Use hashtables instead of lists to store the rules
- Rules that can be applied at launch time won't be tried at runtime
- Improve feedback when writing nonsensical rules
- Make intensive use of `zend_string` instead of `char*`
Diffstat (limited to '')
| -rw-r--r-- | src/sp_disabled_functions.c | 304 |
1 files changed, 180 insertions, 124 deletions
diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c index 341c0a4..14783f6 100644 --- a/src/sp_disabled_functions.c +++ b/src/sp_disabled_functions.c | |||
| @@ -65,7 +65,7 @@ static bool is_functions_list_matching(zend_execute_data* execute_data, | |||
| 65 | static bool is_local_var_matching( | 65 | static bool is_local_var_matching( |
| 66 | zend_execute_data* execute_data, | 66 | zend_execute_data* execute_data, |
| 67 | const sp_disabled_function* const config_node) { | 67 | const sp_disabled_function* const config_node) { |
| 68 | zval* var_value; | 68 | zval* var_value = {0}; |
| 69 | 69 | ||
| 70 | var_value = sp_get_var_value(execute_data, config_node->var, false); | 70 | var_value = sp_get_var_value(execute_data, config_node->var, false); |
| 71 | if (var_value) { | 71 | if (var_value) { |
| @@ -76,14 +76,13 @@ static bool is_local_var_matching( | |||
| 76 | return true; | 76 | return true; |
| 77 | } | 77 | } |
| 78 | } else if (sp_match_array_value(var_value, config_node->value, | 78 | } else if (sp_match_array_value(var_value, config_node->value, |
| 79 | config_node->value_r)) { | 79 | config_node->r_value)) { |
| 80 | return true; | 80 | return true; |
| 81 | } | 81 | } |
| 82 | } else { | 82 | } else { |
| 83 | char* var_value_str = sp_convert_to_string(var_value); | 83 | const zend_string* var_value_str = sp_zval_to_zend_string(var_value); |
| 84 | bool match = sp_match_value(var_value_str, config_node->value, | 84 | bool match = sp_match_value(var_value_str, config_node->value, |
| 85 | config_node->value_r); | 85 | config_node->r_value); |
| 86 | efree(var_value_str); | ||
| 87 | 86 | ||
| 88 | if (true == match) { | 87 | if (true == match) { |
| 89 | return true; | 88 | return true; |
| @@ -93,28 +92,12 @@ static bool is_local_var_matching( | |||
| 93 | return false; | 92 | return false; |
| 94 | } | 93 | } |
| 95 | 94 | ||
| 96 | static inline const sp_list_node* get_config_node(const char* builtin_name) { | ||
| 97 | if (EXPECTED(!builtin_name)) { | ||
| 98 | return SNUFFLEUPAGUS_G(config) | ||
| 99 | .config_disabled_functions->disabled_functions; | ||
| 100 | } else if (!strcmp(builtin_name, "eval")) { | ||
| 101 | return SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval; | ||
| 102 | } else if (!strcmp(builtin_name, "include") || | ||
| 103 | !strcmp(builtin_name, "include_once") || | ||
| 104 | !strcmp(builtin_name, "require") || | ||
| 105 | !strcmp(builtin_name, "require_once")) { | ||
| 106 | return SNUFFLEUPAGUS_G(config) | ||
| 107 | .config_disabled_constructs->construct_include; | ||
| 108 | } | ||
| 109 | ZEND_ASSUME(0); | ||
| 110 | } | ||
| 111 | |||
| 112 | static bool is_param_matching(zend_execute_data* execute_data, | 95 | static bool is_param_matching(zend_execute_data* execute_data, |
| 113 | sp_disabled_function const* const config_node, | 96 | sp_disabled_function const* const config_node, |
| 114 | const char* builtin_name, | 97 | const zend_string* builtin_param, |
| 115 | const char* builtin_param, const char** arg_name, | 98 | const char** arg_name, |
| 116 | const char* builtin_param_name, | 99 | const char* builtin_param_name, |
| 117 | const char** arg_value_str) { | 100 | const zend_string** arg_value_str) { |
| 118 | int nb_param = ZEND_CALL_NUM_ARGS(execute_data); | 101 | int nb_param = ZEND_CALL_NUM_ARGS(execute_data); |
| 119 | int i = 0; | 102 | int i = 0; |
| 120 | zval* arg_value; | 103 | zval* arg_value; |
| @@ -136,14 +119,14 @@ static bool is_param_matching(zend_execute_data* execute_data, | |||
| 136 | } | 119 | } |
| 137 | } | 120 | } |
| 138 | 121 | ||
| 139 | if (builtin_name) { | 122 | if (builtin_param) { |
| 140 | /* We're matching on a language construct (here named "builtin"), | 123 | /* We're matching on a language construct (here named "builtin"), |
| 141 | * and they can only take a single argument, but PHP considers them | 124 | * and they can only take a single argument, but PHP considers them |
| 142 | * differently than functions arguments. */ | 125 | * differently than functions arguments. */ |
| 143 | *arg_name = builtin_param_name; | 126 | *arg_name = builtin_param_name; |
| 144 | *arg_value_str = builtin_param; | 127 | *arg_value_str = builtin_param; |
| 145 | return sp_match_value(builtin_param, config_node->value, | 128 | return sp_match_value(builtin_param, config_node->value, |
| 146 | config_node->value_r); | 129 | config_node->r_value); |
| 147 | } else if (config_node->r_param || config_node->pos != -1) { | 130 | } else if (config_node->r_param || config_node->pos != -1) { |
| 148 | // We're matching on a function (and not a language construct) | 131 | // We're matching on a function (and not a language construct) |
| 149 | for (; i < nb_param; i++) { | 132 | for (; i < nb_param; i++) { |
| @@ -165,20 +148,20 @@ static bool is_param_matching(zend_execute_data* execute_data, | |||
| 165 | return true; | 148 | return true; |
| 166 | } | 149 | } |
| 167 | } else if (Z_TYPE_P(arg_value) == IS_ARRAY) { | 150 | } else if (Z_TYPE_P(arg_value) == IS_ARRAY) { |
| 168 | *arg_value_str = sp_convert_to_string(arg_value); | 151 | *arg_value_str = sp_zval_to_zend_string(arg_value); |
| 169 | if (config_node->key || config_node->r_key) { | 152 | if (config_node->key || config_node->r_key) { |
| 170 | if (sp_match_array_key(arg_value, config_node->key, | 153 | if (sp_match_array_key(arg_value, config_node->key, |
| 171 | config_node->r_key)) { | 154 | config_node->r_key)) { |
| 172 | return true; | 155 | return true; |
| 173 | } | 156 | } |
| 174 | } else if (sp_match_array_value(arg_value, config_node->value, | 157 | } else if (sp_match_array_value(arg_value, config_node->value, |
| 175 | config_node->value_r)) { | 158 | config_node->r_value)) { |
| 176 | return true; | 159 | return true; |
| 177 | } | 160 | } |
| 178 | } else { | 161 | } else { |
| 179 | *arg_value_str = sp_convert_to_string(arg_value); | 162 | *arg_value_str = sp_zval_to_zend_string(arg_value); |
| 180 | if (sp_match_value(*arg_value_str, config_node->value, | 163 | if (sp_match_value(*arg_value_str, config_node->value, |
| 181 | config_node->value_r)) { | 164 | config_node->r_value)) { |
| 182 | return true; | 165 | return true; |
| 183 | } | 166 | } |
| 184 | } | 167 | } |
| @@ -189,7 +172,7 @@ static bool is_param_matching(zend_execute_data* execute_data, | |||
| 189 | arg_value = sp_get_var_value(execute_data, config_node->param, true); | 172 | arg_value = sp_get_var_value(execute_data, config_node->param, true); |
| 190 | 173 | ||
| 191 | if (arg_value) { | 174 | if (arg_value) { |
| 192 | *arg_value_str = sp_convert_to_string(arg_value); | 175 | *arg_value_str = sp_zval_to_zend_string(arg_value); |
| 193 | if (config_node->param_type) { // Are we matching on the `type`? | 176 | if (config_node->param_type) { // Are we matching on the `type`? |
| 194 | if (config_node->param_type == Z_TYPE_P(arg_value)) { | 177 | if (config_node->param_type == Z_TYPE_P(arg_value)) { |
| 195 | return true; | 178 | return true; |
| @@ -201,11 +184,11 @@ static bool is_param_matching(zend_execute_data* execute_data, | |||
| 201 | return true; | 184 | return true; |
| 202 | } | 185 | } |
| 203 | } else if (sp_match_array_value(arg_value, config_node->value, | 186 | } else if (sp_match_array_value(arg_value, config_node->value, |
| 204 | config_node->value_r)) { | 187 | config_node->r_value)) { |
| 205 | return true; | 188 | return true; |
| 206 | } | 189 | } |
| 207 | } else if (sp_match_value(*arg_value_str, config_node->value, | 190 | } else if (sp_match_value(*arg_value_str, config_node->value, |
| 208 | config_node->value_r)) { | 191 | config_node->r_value)) { |
| 209 | return true; | 192 | return true; |
| 210 | } | 193 | } |
| 211 | } | 194 | } |
| @@ -216,7 +199,7 @@ static bool is_param_matching(zend_execute_data* execute_data, | |||
| 216 | static zend_execute_data* is_file_matching( | 199 | static zend_execute_data* is_file_matching( |
| 217 | zend_execute_data* const execute_data, | 200 | zend_execute_data* const execute_data, |
| 218 | sp_disabled_function const* const config_node, | 201 | sp_disabled_function const* const config_node, |
| 219 | char const* const current_filename) { | 202 | zend_string const* const current_filename) { |
| 220 | #define ITERATE(ex) \ | 203 | #define ITERATE(ex) \ |
| 221 | ex = ex->prev_execute_data; \ | 204 | ex = ex->prev_execute_data; \ |
| 222 | while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) \ | 205 | while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) \ |
| @@ -225,22 +208,21 @@ static zend_execute_data* is_file_matching( | |||
| 225 | 208 | ||
| 226 | zend_execute_data* ex = execute_data; | 209 | zend_execute_data* ex = execute_data; |
| 227 | if (config_node->filename) { | 210 | if (config_node->filename) { |
| 228 | if (0 == strcmp(current_filename, config_node->filename)) { | 211 | if (zend_string_equals_literal(current_filename, config_node->filename)) { |
| 229 | return ex; | 212 | return ex; |
| 230 | } | 213 | } |
| 231 | ITERATE(ex); | 214 | ITERATE(ex); |
| 232 | if (0 == | 215 | if (zend_string_equals_literal(ex->func->op_array.filename, |
| 233 | strcmp(ZSTR_VAL(ex->func->op_array.filename), config_node->filename)) { | 216 | config_node->filename)) { |
| 234 | return ex; | 217 | return ex; |
| 235 | } | 218 | } |
| 236 | } else if (config_node->r_filename) { | 219 | } else if (config_node->r_filename) { |
| 237 | if (true == | 220 | if (sp_is_regexp_matching_zend(config_node->r_filename, current_filename)) { |
| 238 | sp_is_regexp_matching(config_node->r_filename, current_filename)) { | ||
| 239 | return ex; | 221 | return ex; |
| 240 | } | 222 | } |
| 241 | ITERATE(ex); | 223 | ITERATE(ex); |
| 242 | if (true == sp_is_regexp_matching(config_node->r_filename, | 224 | if (sp_is_regexp_matching_zend(config_node->r_filename, |
| 243 | ZSTR_VAL(ex->func->op_array.filename))) { | 225 | ex->func->op_array.filename)) { |
| 244 | return ex; | 226 | return ex; |
| 245 | } | 227 | } |
| 246 | } | 228 | } |
| @@ -251,10 +233,10 @@ static zend_execute_data* is_file_matching( | |||
| 251 | static bool check_is_builtin_name( | 233 | static bool check_is_builtin_name( |
| 252 | sp_disabled_function const* const config_node) { | 234 | sp_disabled_function const* const config_node) { |
| 253 | if (config_node->function) { | 235 | if (config_node->function) { |
| 254 | return (!strcmp(config_node->function, "include") || | 236 | return (zend_string_equals_literal(config_node->function, "include") || |
| 255 | !strcmp(config_node->function, "include_once") || | 237 | zend_string_equals_literal(config_node->function, "include_once") || |
| 256 | !strcmp(config_node->function, "require") || | 238 | zend_string_equals_literal(config_node->function, "require") || |
| 257 | !strcmp(config_node->function, "require_once")); | 239 | zend_string_equals_literal(config_node->function, "require_once")); |
| 258 | } | 240 | } |
| 259 | if (config_node->r_function) { | 241 | if (config_node->r_function) { |
| 260 | return (sp_is_regexp_matching(config_node->r_function, "include") || | 242 | return (sp_is_regexp_matching(config_node->r_function, "include") || |
| @@ -265,43 +247,67 @@ static bool check_is_builtin_name( | |||
| 265 | return false; | 247 | return false; |
| 266 | } | 248 | } |
| 267 | 249 | ||
| 268 | bool should_disable(zend_execute_data* execute_data, const char* builtin_name, | 250 | bool should_disable_ht(zend_execute_data* execute_data, |
| 269 | const char* builtin_param, const char* builtin_param_name) { | 251 | const char* builtin_name, |
| 270 | char current_file_hash[SHA256_SIZE * 2 + 1] = {0}; | 252 | const zend_string* builtin_param, |
| 271 | const sp_list_node* config = get_config_node(builtin_name); | 253 | const char* builtin_param_name, |
| 272 | char* complete_path_function = NULL; | 254 | const sp_list_node* config, const HashTable* ht) { |
| 273 | const char* current_filename = NULL; | 255 | char* complete_function_path = NULL; |
| 274 | unsigned int line = 0; | 256 | const sp_list_node* ht_entry = NULL; |
| 275 | char* filename = NULL; | 257 | bool ret = false; |
| 258 | zend_string* current_filename; | ||
| 276 | 259 | ||
| 277 | if (!execute_data) { | 260 | if (!execute_data) { |
| 278 | return false; | 261 | return false; |
| 279 | } | 262 | } |
| 280 | 263 | ||
| 281 | if (!config || !config->data) { | 264 | if (builtin_name) { |
| 282 | return false; | 265 | complete_function_path = estrdup(builtin_name); |
| 266 | } else { | ||
| 267 | complete_function_path = get_complete_function_path(execute_data); | ||
| 268 | if (!complete_function_path) { | ||
| 269 | return false; | ||
| 270 | } | ||
| 283 | } | 271 | } |
| 284 | 272 | ||
| 285 | if (UNEXPECTED(builtin_name && !strcmp(builtin_name, "eval"))) { | 273 | if (UNEXPECTED(builtin_param && !strcmp(complete_function_path, "eval"))) { |
| 286 | current_filename = get_eval_filename(zend_get_executed_filename()); | 274 | current_filename = get_eval_filename(zend_get_executed_filename()); |
| 287 | } else { | 275 | } else { |
| 288 | current_filename = zend_get_executed_filename(); | 276 | const char* tmp = zend_get_executed_filename(); |
| 277 | current_filename = zend_string_init(tmp, strlen(tmp), 0); | ||
| 289 | } | 278 | } |
| 290 | 279 | ||
| 291 | complete_path_function = get_complete_function_path(execute_data); | 280 | ht_entry = zend_hash_str_find_ptr(ht, complete_function_path, |
| 292 | if (!complete_path_function) { | 281 | strlen(complete_function_path)); |
| 293 | if (builtin_name) { | 282 | |
| 294 | complete_path_function = estrdup(builtin_name); | 283 | if (ht_entry && |
| 295 | } else { | 284 | should_disable(execute_data, complete_function_path, builtin_param, |
| 296 | return false; | 285 | builtin_param_name, ht_entry, current_filename)) { |
| 297 | } | 286 | ret = true; |
| 287 | } else if (config && config->data) { | ||
| 288 | ret = should_disable(execute_data, complete_function_path, builtin_param, | ||
| 289 | builtin_param_name, config, current_filename); | ||
| 298 | } | 290 | } |
| 299 | 291 | ||
| 292 | efree(complete_function_path); | ||
| 293 | efree(current_filename); | ||
| 294 | return ret; | ||
| 295 | } | ||
| 296 | |||
| 297 | bool should_disable(zend_execute_data* execute_data, | ||
| 298 | const char* complete_function_path, | ||
| 299 | const zend_string* builtin_param, | ||
| 300 | const char* builtin_param_name, const sp_list_node* config, | ||
| 301 | const zend_string* current_filename) { | ||
| 302 | char current_file_hash[SHA256_SIZE * 2 + 1] = {0}; | ||
| 303 | unsigned int line = 0; | ||
| 304 | char* filename = NULL; | ||
| 305 | |||
| 300 | while (config) { | 306 | while (config) { |
| 301 | sp_disabled_function const* const config_node = | 307 | sp_disabled_function const* const config_node = |
| 302 | (sp_disabled_function*)(config->data); | 308 | (sp_disabled_function*)(config->data); |
| 303 | const char* arg_name = NULL; | 309 | const char* arg_name = NULL; |
| 304 | const char* arg_value_str = NULL; | 310 | const zend_string* arg_value_str = NULL; |
| 305 | 311 | ||
| 306 | /* The order matters, since when we have `config_node->functions_list`, | 312 | /* The order matters, since when we have `config_node->functions_list`, |
| 307 | we also do have `config_node->function` */ | 313 | we also do have `config_node->function` */ |
| @@ -311,12 +317,13 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name, | |||
| 311 | goto next; | 317 | goto next; |
| 312 | } | 318 | } |
| 313 | } else if (config_node->function) { | 319 | } else if (config_node->function) { |
| 314 | if (0 != strcmp(config_node->function, complete_path_function)) { | 320 | if (0 != |
| 321 | strcmp(ZSTR_VAL(config_node->function), complete_function_path)) { | ||
| 315 | goto next; | 322 | goto next; |
| 316 | } | 323 | } |
| 317 | } else if (config_node->r_function) { | 324 | } else if (config_node->r_function) { |
| 318 | if (false == sp_is_regexp_matching(config_node->r_function, | 325 | if (false == sp_is_regexp_matching(config_node->r_function, |
| 319 | complete_path_function)) { | 326 | complete_function_path)) { |
| 320 | goto next; | 327 | goto next; |
| 321 | } | 328 | } |
| 322 | } | 329 | } |
| @@ -350,9 +357,10 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name, | |||
| 350 | 357 | ||
| 351 | if (config_node->hash) { | 358 | if (config_node->hash) { |
| 352 | if ('\0' == current_file_hash[0]) { | 359 | if ('\0' == current_file_hash[0]) { |
| 353 | compute_hash(current_filename, current_file_hash); | 360 | compute_hash(ZSTR_VAL(current_filename), current_file_hash); |
| 354 | } | 361 | } |
| 355 | if (0 != strncmp(current_file_hash, config_node->hash, SHA256_SIZE)) { | 362 | if (0 != strncmp(current_file_hash, ZSTR_VAL(config_node->hash), |
| 363 | SHA256_SIZE)) { | ||
| 356 | goto next; | 364 | goto next; |
| 357 | } | 365 | } |
| 358 | } | 366 | } |
| @@ -360,25 +368,25 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name, | |||
| 360 | /* Check if we filter on parameter value*/ | 368 | /* Check if we filter on parameter value*/ |
| 361 | if (config_node->param || config_node->r_param || | 369 | if (config_node->param || config_node->r_param || |
| 362 | (config_node->pos != -1)) { | 370 | (config_node->pos != -1)) { |
| 363 | if (!builtin_name && execute_data->func->op_array.arg_info->is_variadic) { | 371 | if (!builtin_param && |
| 372 | execute_data->func->op_array.arg_info->is_variadic) { | ||
| 364 | sp_log_err( | 373 | sp_log_err( |
| 365 | "disable_function", | 374 | "disable_function", |
| 366 | "Snuffleupagus doesn't support variadic functions yet, sorry. " | 375 | "Snuffleupagus doesn't support variadic functions yet, sorry. " |
| 367 | "Check https://github.com/nbs-system/snuffleupagus/issues/164 for " | 376 | "Check https://github.com/nbs-system/snuffleupagus/issues/164 for " |
| 368 | "details."); | 377 | "details."); |
| 369 | } else if (false == is_param_matching(execute_data, config_node, | 378 | } else if (false == is_param_matching( |
| 370 | builtin_name, builtin_param, | 379 | execute_data, config_node, builtin_param, |
| 371 | &arg_name, builtin_param_name, | 380 | &arg_name, builtin_param_name, &arg_value_str)) { |
| 372 | &arg_value_str)) { | ||
| 373 | goto next; | 381 | goto next; |
| 374 | } | 382 | } |
| 375 | } | 383 | } |
| 376 | 384 | ||
| 377 | if (config_node->value_r || config_node->value) { | 385 | if (config_node->r_value || config_node->value) { |
| 378 | if (check_is_builtin_name(config_node)) { | 386 | if (check_is_builtin_name(config_node)) { |
| 379 | if (false == is_param_matching(execute_data, config_node, builtin_name, | 387 | if (false == is_param_matching(execute_data, config_node, builtin_param, |
| 380 | builtin_param, &arg_name, | 388 | &arg_name, builtin_param_name, |
| 381 | builtin_param_name, &arg_value_str)) { | 389 | &arg_value_str)) { |
| 382 | goto next; | 390 | goto next; |
| 383 | } | 391 | } |
| 384 | } | 392 | } |
| @@ -390,63 +398,76 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name, | |||
| 390 | } | 398 | } |
| 391 | 399 | ||
| 392 | if (config_node->functions_list) { | 400 | if (config_node->functions_list) { |
| 393 | sp_log_disable(config_node->function, arg_name, arg_value_str, | 401 | sp_log_disable(ZSTR_VAL(config_node->function), arg_name, arg_value_str, |
| 394 | config_node, line, filename); | 402 | config_node, line, filename); |
| 395 | } else { | 403 | } else { |
| 396 | sp_log_disable(complete_path_function, arg_name, arg_value_str, | 404 | sp_log_disable(complete_function_path, arg_name, arg_value_str, |
| 397 | config_node, line, filename); | 405 | config_node, line, filename); |
| 398 | } | 406 | } |
| 399 | if (true == config_node->simulation) { | 407 | if (true == config_node->simulation) { |
| 400 | goto next; | 408 | goto next; |
| 401 | } else { // We've got a match, the function won't be executed | 409 | } else { // We've got a match, the function won't be executed |
| 402 | efree(complete_path_function); | ||
| 403 | return true; | 410 | return true; |
| 404 | } | 411 | } |
| 405 | next: | 412 | next: |
| 406 | config = config->next; | 413 | config = config->next; |
| 407 | } | 414 | } |
| 408 | allow: | 415 | allow: |
| 409 | efree(complete_path_function); | ||
| 410 | return false; | 416 | return false; |
| 411 | } | 417 | } |
| 412 | 418 | ||
| 413 | bool should_drop_on_ret(zval* return_value, | 419 | bool should_drop_on_ret_ht(zval* return_value, |
| 414 | const zend_execute_data* const execute_data) { | 420 | const zend_execute_data* const execute_data, |
| 415 | const sp_list_node* config = | 421 | const sp_list_node* config, const HashTable* ht) { |
| 416 | SNUFFLEUPAGUS_G(config).config_disabled_functions_ret->disabled_functions; | 422 | char* complete_function_path = get_complete_function_path(execute_data); |
| 417 | char* complete_path_function = get_complete_function_path(execute_data); | 423 | const sp_list_node* ht_entry = NULL; |
| 418 | const char* current_filename = zend_get_executed_filename(TSRMLS_C); | 424 | bool ret = false; |
| 419 | char current_file_hash[SHA256_SIZE * 2 + 1] = {0}; | ||
| 420 | bool match_type = false, match_value = false; | ||
| 421 | 425 | ||
| 422 | if (!complete_path_function) { | 426 | if (!complete_function_path) { |
| 423 | return false; | 427 | return ret; |
| 424 | } | 428 | } |
| 425 | 429 | ||
| 426 | if (!config || !config->data) { | 430 | ht_entry = zend_hash_str_find_ptr(ht, complete_function_path, |
| 427 | return false; | 431 | strlen(complete_function_path)); |
| 432 | |||
| 433 | if (ht_entry && | ||
| 434 | should_drop_on_ret(return_value, ht_entry, complete_function_path)) { | ||
| 435 | ret = true; | ||
| 436 | } else if (config && config->data) { | ||
| 437 | ret = should_drop_on_ret(return_value, config, complete_function_path); | ||
| 428 | } | 438 | } |
| 429 | 439 | ||
| 440 | efree(complete_function_path); | ||
| 441 | return ret; | ||
| 442 | } | ||
| 443 | |||
| 444 | bool should_drop_on_ret(zval* return_value, const sp_list_node* config, | ||
| 445 | const char* complete_function_path) { | ||
| 446 | const char* current_filename = zend_get_executed_filename(TSRMLS_C); | ||
| 447 | char current_file_hash[SHA256_SIZE * 2 + 1] = {0}; | ||
| 448 | bool match_type = false, match_value = false; | ||
| 449 | |||
| 430 | while (config) { | 450 | while (config) { |
| 431 | char* ret_value_str = NULL; | 451 | const zend_string* ret_value_str = NULL; |
| 432 | sp_disabled_function const* const config_node = | 452 | sp_disabled_function const* const config_node = |
| 433 | (sp_disabled_function*)(config->data); | 453 | (sp_disabled_function*)(config->data); |
| 434 | 454 | ||
| 435 | assert(config_node->function || config_node->r_function); | 455 | assert(config_node->function || config_node->r_function); |
| 436 | 456 | ||
| 437 | if (config_node->function) { | 457 | if (config_node->function) { |
| 438 | if (0 != strcmp(config_node->function, complete_path_function)) { | 458 | if (0 != |
| 459 | strcmp(ZSTR_VAL(config_node->function), complete_function_path)) { | ||
| 439 | goto next; | 460 | goto next; |
| 440 | } | 461 | } |
| 441 | } else if (config_node->r_function) { | 462 | } else if (config_node->r_function) { |
| 442 | if (false == sp_is_regexp_matching(config_node->r_function, | 463 | if (false == sp_is_regexp_matching(config_node->r_function, |
| 443 | complete_path_function)) { | 464 | complete_function_path)) { |
| 444 | goto next; | 465 | goto next; |
| 445 | } | 466 | } |
| 446 | } | 467 | } |
| 447 | 468 | ||
| 448 | if (config_node->filename) { /* Check the current file name. */ | 469 | if (config_node->filename) { /* Check the current file name. */ |
| 449 | if (0 != strcmp(current_filename, config_node->filename)) { | 470 | if (0 != strcmp(current_filename, ZSTR_VAL(config_node->filename))) { |
| 450 | goto next; | 471 | goto next; |
| 451 | } | 472 | } |
| 452 | } else if (config_node->r_filename) { | 473 | } else if (config_node->r_filename) { |
| @@ -460,12 +481,13 @@ bool should_drop_on_ret(zval* return_value, | |||
| 460 | if ('\0' == current_file_hash[0]) { | 481 | if ('\0' == current_file_hash[0]) { |
| 461 | compute_hash(current_filename, current_file_hash); | 482 | compute_hash(current_filename, current_file_hash); |
| 462 | } | 483 | } |
| 463 | if (0 != strncmp(current_file_hash, config_node->hash, SHA256_SIZE)) { | 484 | if (0 != strncmp(current_file_hash, ZSTR_VAL(config_node->hash), |
| 485 | SHA256_SIZE)) { | ||
| 464 | goto next; | 486 | goto next; |
| 465 | } | 487 | } |
| 466 | } | 488 | } |
| 467 | 489 | ||
| 468 | ret_value_str = sp_convert_to_string(return_value); | 490 | ret_value_str = sp_zval_to_zend_string(return_value); |
| 469 | 491 | ||
| 470 | match_type = (config_node->ret_type) && | 492 | match_type = (config_node->ret_type) && |
| 471 | (config_node->ret_type == Z_TYPE_P(return_value)); | 493 | (config_node->ret_type == Z_TYPE_P(return_value)); |
| @@ -475,22 +497,16 @@ bool should_drop_on_ret(zval* return_value, | |||
| 475 | 497 | ||
| 476 | if (true == match_type || true == match_value) { | 498 | if (true == match_type || true == match_value) { |
| 477 | if (true == config_node->allow) { | 499 | if (true == config_node->allow) { |
| 478 | efree(complete_path_function); | ||
| 479 | efree(ret_value_str); | ||
| 480 | return false; | 500 | return false; |
| 481 | } | 501 | } |
| 482 | sp_log_disable_ret(complete_path_function, ret_value_str, config_node); | 502 | sp_log_disable_ret(complete_function_path, ret_value_str, config_node); |
| 483 | if (false == config_node->simulation) { | 503 | if (false == config_node->simulation) { |
| 484 | efree(complete_path_function); | ||
| 485 | efree(ret_value_str); | ||
| 486 | return true; | 504 | return true; |
| 487 | } | 505 | } |
| 488 | } | 506 | } |
| 489 | next: | 507 | next: |
| 490 | efree(ret_value_str); | ||
| 491 | config = config->next; | 508 | config = config->next; |
| 492 | } | 509 | } |
| 493 | efree(complete_path_function); | ||
| 494 | return false; | 510 | return false; |
| 495 | } | 511 | } |
| 496 | 512 | ||
| @@ -498,7 +514,11 @@ ZEND_FUNCTION(check_disabled_function) { | |||
| 498 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); | 514 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); |
| 499 | const char* current_function_name = get_active_function_name(TSRMLS_C); | 515 | const char* current_function_name = get_active_function_name(TSRMLS_C); |
| 500 | 516 | ||
| 501 | if (true == should_disable(execute_data, NULL, NULL, NULL)) { | 517 | if (true == should_disable_ht( |
| 518 | execute_data, NULL, NULL, NULL, | ||
| 519 | SNUFFLEUPAGUS_G(config) | ||
| 520 | .config_disabled_functions_reg->disabled_functions, | ||
| 521 | SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked)) { | ||
| 502 | sp_terminate(); | 522 | sp_terminate(); |
| 503 | } | 523 | } |
| 504 | 524 | ||
| @@ -506,23 +526,29 @@ ZEND_FUNCTION(check_disabled_function) { | |||
| 506 | SNUFFLEUPAGUS_G(disabled_functions_hook), current_function_name, | 526 | SNUFFLEUPAGUS_G(disabled_functions_hook), current_function_name, |
| 507 | strlen(current_function_name)); | 527 | strlen(current_function_name)); |
| 508 | orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); | 528 | orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); |
| 509 | if (true == should_drop_on_ret(return_value, execute_data)) { | 529 | if (true == |
| 530 | should_drop_on_ret_ht( | ||
| 531 | return_value, execute_data, | ||
| 532 | SNUFFLEUPAGUS_G(config) | ||
| 533 | .config_disabled_functions_reg_ret->disabled_functions, | ||
| 534 | SNUFFLEUPAGUS_G(config).config_disabled_functions_ret_hooked)) { | ||
| 510 | sp_terminate(); | 535 | sp_terminate(); |
| 511 | } | 536 | } |
| 512 | } | 537 | } |
| 513 | 538 | ||
| 514 | static int hook_functions(const sp_list_node* config) { | 539 | static int hook_functions_regexp(const sp_list_node* config) { |
| 515 | while (config && config->data) { | 540 | while (config && config->data) { |
| 516 | const char* function_name = ((sp_disabled_function*)config->data)->function; | 541 | const zend_string* function_name = |
| 542 | ((sp_disabled_function*)config->data)->function; | ||
| 517 | const sp_pcre* function_name_regexp = | 543 | const sp_pcre* function_name_regexp = |
| 518 | ((sp_disabled_function*)config->data)->r_function; | 544 | ((sp_disabled_function*)config->data)->r_function; |
| 519 | 545 | ||
| 520 | assert(function_name || function_name_regexp); | 546 | assert(function_name || function_name_regexp); |
| 521 | 547 | ||
| 522 | if (NULL != function_name) { // hook function by name | 548 | if (function_name) { |
| 523 | HOOK_FUNCTION(function_name, disabled_functions_hook, | 549 | HOOK_FUNCTION(ZSTR_VAL(function_name), disabled_functions_hook, |
| 524 | PHP_FN(check_disabled_function)); | 550 | PHP_FN(check_disabled_function)); |
| 525 | } else if (NULL != function_name_regexp) { // hook function by regexp | 551 | } else { |
| 526 | HOOK_FUNCTION_BY_REGEXP(function_name_regexp, disabled_functions_hook, | 552 | HOOK_FUNCTION_BY_REGEXP(function_name_regexp, disabled_functions_hook, |
| 527 | PHP_FN(check_disabled_function)); | 553 | PHP_FN(check_disabled_function)); |
| 528 | } | 554 | } |
| @@ -532,16 +558,36 @@ static int hook_functions(const sp_list_node* config) { | |||
| 532 | return SUCCESS; | 558 | return SUCCESS; |
| 533 | } | 559 | } |
| 534 | 560 | ||
| 561 | static int hook_functions(HashTable* to_hook_ht, HashTable* hooked_ht) { | ||
| 562 | zend_string* key; | ||
| 563 | zval* value; | ||
| 564 | |||
| 565 | ZEND_HASH_FOREACH_STR_KEY_VAL(to_hook_ht, key, value) { | ||
| 566 | if (!HOOK_FUNCTION(ZSTR_VAL(key), disabled_functions_hook, | ||
| 567 | PHP_FN(check_disabled_function)) || | ||
| 568 | check_is_builtin_name(((sp_list_node*)Z_PTR_P(value))->data)) { | ||
| 569 | zend_symtable_add_new(hooked_ht, key, value); | ||
| 570 | zend_hash_del(to_hook_ht, key); | ||
| 571 | } | ||
| 572 | } | ||
| 573 | ZEND_HASH_FOREACH_END(); | ||
| 574 | return SUCCESS; | ||
| 575 | } | ||
| 576 | |||
| 535 | ZEND_FUNCTION(eval_blacklist_callback) { | 577 | ZEND_FUNCTION(eval_blacklist_callback) { |
| 536 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); | 578 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); |
| 537 | const char* current_function_name = get_active_function_name(TSRMLS_C); | 579 | const char* current_function_name = get_active_function_name(TSRMLS_C); |
| 580 | zend_string* tmp = | ||
| 581 | zend_string_init(current_function_name, strlen(current_function_name), 0); | ||
| 538 | 582 | ||
| 539 | if (true == check_is_in_eval_whitelist(current_function_name)) { | 583 | if (true == check_is_in_eval_whitelist(tmp)) { |
| 584 | zend_string_release(tmp); | ||
| 540 | goto whitelisted; | 585 | goto whitelisted; |
| 541 | } | 586 | } |
| 587 | zend_string_release(tmp); | ||
| 542 | 588 | ||
| 543 | if (SNUFFLEUPAGUS_G(in_eval) > 0) { | 589 | if (SNUFFLEUPAGUS_G(in_eval) > 0) { |
| 544 | char* filename = get_eval_filename(zend_get_executed_filename()); | 590 | zend_string* filename = get_eval_filename(zend_get_executed_filename()); |
| 545 | const int line_number = zend_get_executed_lineno(TSRMLS_C); | 591 | const int line_number = zend_get_executed_lineno(TSRMLS_C); |
| 546 | if (SNUFFLEUPAGUS_G(config).config_eval->dump) { | 592 | if (SNUFFLEUPAGUS_G(config).config_eval->dump) { |
| 547 | sp_log_request( | 593 | sp_log_request( |
| @@ -549,14 +595,14 @@ ZEND_FUNCTION(eval_blacklist_callback) { | |||
| 549 | SNUFFLEUPAGUS_G(config).config_eval->textual_representation, | 595 | SNUFFLEUPAGUS_G(config).config_eval->textual_representation, |
| 550 | SP_TOKEN_EVAL_BLACKLIST); | 596 | SP_TOKEN_EVAL_BLACKLIST); |
| 551 | } | 597 | } |
| 552 | if (1 == SNUFFLEUPAGUS_G(config).config_eval->simulation) { | 598 | if (SNUFFLEUPAGUS_G(config).config_eval->simulation) { |
| 553 | sp_log_msg("eval", SP_LOG_SIMULATION, | 599 | sp_log_msg("eval", SP_LOG_SIMULATION, |
| 554 | "A call to %s was tried in eval, in %s:%d, logging it.", | 600 | "A call to %s was tried in eval, in %s:%d, logging it.", |
| 555 | current_function_name, filename, line_number); | 601 | current_function_name, ZSTR_VAL(filename), line_number); |
| 556 | } else { | 602 | } else { |
| 557 | sp_log_msg("eval", SP_LOG_DROP, | 603 | sp_log_msg("eval", SP_LOG_DROP, |
| 558 | "A call to %s was tried in eval, in %s:%d, dropping it.", | 604 | "A call to %s was tried in eval, in %s:%d, dropping it.", |
| 559 | current_function_name, filename, line_number); | 605 | current_function_name, ZSTR_VAL(filename), line_number); |
| 560 | sp_terminate(); | 606 | sp_terminate(); |
| 561 | } | 607 | } |
| 562 | efree(filename); | 608 | efree(filename); |
| @@ -574,21 +620,31 @@ int hook_disabled_functions(void) { | |||
| 574 | 620 | ||
| 575 | int ret = SUCCESS; | 621 | int ret = SUCCESS; |
| 576 | 622 | ||
| 623 | ret |= | ||
| 624 | hook_functions(SNUFFLEUPAGUS_G(config).config_disabled_functions, | ||
| 625 | SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked); | ||
| 626 | |||
| 577 | ret |= hook_functions( | 627 | ret |= hook_functions( |
| 578 | SNUFFLEUPAGUS_G(config).config_disabled_functions->disabled_functions); | 628 | SNUFFLEUPAGUS_G(config).config_disabled_functions_ret, |
| 579 | ret |= hook_functions(SNUFFLEUPAGUS_G(config) | 629 | SNUFFLEUPAGUS_G(config).config_disabled_functions_ret_hooked); |
| 580 | .config_disabled_functions_ret->disabled_functions); | 630 | |
| 631 | ret |= hook_functions_regexp( | ||
| 632 | SNUFFLEUPAGUS_G(config) | ||
| 633 | .config_disabled_functions_reg->disabled_functions); | ||
| 634 | |||
| 635 | ret |= hook_functions_regexp( | ||
| 636 | SNUFFLEUPAGUS_G(config) | ||
| 637 | .config_disabled_functions_reg_ret->disabled_functions); | ||
| 581 | 638 | ||
| 582 | if (NULL != SNUFFLEUPAGUS_G(config).config_eval->blacklist) { | 639 | if (NULL != SNUFFLEUPAGUS_G(config).config_eval->blacklist) { |
| 583 | sp_list_node* it = SNUFFLEUPAGUS_G(config).config_eval->blacklist; | 640 | sp_list_node* it = SNUFFLEUPAGUS_G(config).config_eval->blacklist; |
| 584 | 641 | ||
| 585 | while (it) { | 642 | while (it) { |
| 586 | hook_function((char*)it->data, | 643 | hook_function(ZSTR_VAL((zend_string*)it->data), |
| 587 | SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook), | 644 | SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook), |
| 588 | PHP_FN(eval_blacklist_callback)); | 645 | PHP_FN(eval_blacklist_callback)); |
| 589 | it = it->next; | 646 | it = it->next; |
| 590 | } | 647 | } |
| 591 | } | 648 | } |
| 592 | |||
| 593 | return ret; | 649 | return ret; |
| 594 | } | 650 | } |
