diff options
| author | Ben Fuhrmannek | 2021-02-18 15:59:41 +0100 |
|---|---|---|
| committer | Ben Fuhrmannek | 2021-02-18 15:59:41 +0100 |
| commit | fb9b3787246dff3e9b76e75f698ff7131ea5403d (patch) | |
| tree | 919b4ba77dcfc5487a3906851c24e71f4d25ad82 /src/sp_disabled_functions.c | |
| parent | 01528718850c8528ef6d2ed5296e244d4aa7b675 (diff) | |
rewrote parameter matching logic. breaks compatibility with previous versions.
Diffstat (limited to 'src/sp_disabled_functions.c')
| -rw-r--r-- | src/sp_disabled_functions.c | 157 |
1 files changed, 79 insertions, 78 deletions
diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c index c47b5cb..84d8acf 100644 --- a/src/sp_disabled_functions.c +++ b/src/sp_disabled_functions.c | |||
| @@ -33,6 +33,8 @@ char* get_complete_function_path(zend_execute_data const* const execute_data) { | |||
| 33 | } else { | 33 | } else { |
| 34 | complete_path_function = estrdup(function_name); | 34 | complete_path_function = estrdup(function_name); |
| 35 | } | 35 | } |
| 36 | sp_log_debug("%s", complete_path_function); | ||
| 37 | |||
| 36 | return complete_path_function; | 38 | return complete_path_function; |
| 37 | } | 39 | } |
| 38 | 40 | ||
| @@ -98,107 +100,105 @@ static bool is_local_var_matching( | |||
| 98 | return false; | 100 | return false; |
| 99 | } | 101 | } |
| 100 | 102 | ||
| 103 | static inline const char* get_fn_arg_name(zend_function *fn, uint32_t i) { | ||
| 104 | if (fn->type == ZEND_USER_FUNCTION || (fn->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) { | ||
| 105 | return ZSTR_VAL(fn->op_array.arg_info[i].name); | ||
| 106 | } else { | ||
| 107 | return fn->internal_function.arg_info[i].name; | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 101 | static bool is_param_matching(zend_execute_data* execute_data, | 111 | static bool is_param_matching(zend_execute_data* execute_data, |
| 102 | sp_disabled_function const* const config_node, | 112 | sp_disabled_function const* const config_node, |
| 103 | const zend_string* builtin_param, | 113 | const zend_string* builtin_param, |
| 104 | const char* builtin_param_name, | 114 | const char* builtin_param_name, |
| 105 | const char** arg_name, | 115 | const char** arg_name, |
| 106 | const zend_string** arg_value_str) { | 116 | const zend_string** arg_value_str) { |
| 107 | int nb_param = ZEND_CALL_NUM_ARGS(execute_data); | 117 | // builtin functions |
| 108 | int i = 0; | ||
| 109 | zval* arg_value; | ||
| 110 | |||
| 111 | if (config_node->pos != -1) { | ||
| 112 | if (config_node->pos > nb_param - 1) { | ||
| 113 | char* complete_function_path = get_complete_function_path(execute_data); | ||
| 114 | sp_log_warn("config", | ||
| 115 | "It seems that you wrote a rule filtering on the " | ||
| 116 | "%d%s argument of the function '%s', but it takes only %d " | ||
| 117 | "arguments. " | ||
| 118 | "Matching on _all_ arguments instead.", | ||
| 119 | config_node->pos, GET_SUFFIX(config_node->pos), | ||
| 120 | complete_function_path, nb_param); | ||
| 121 | efree(complete_function_path); | ||
| 122 | } else { | ||
| 123 | i = config_node->pos; | ||
| 124 | nb_param = (config_node->pos) + 1; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | if (builtin_param) { | 118 | if (builtin_param) { |
| 129 | /* We're matching on a language construct (here named "builtin"), | 119 | /* We're matching on a language construct (here named "builtin"), |
| 130 | * and they can only take a single argument, but PHP considers them | 120 | * and they can only take a single argument, but PHP considers them |
| 131 | * differently than functions arguments. */ | 121 | * differently than functions arguments. */ |
| 132 | *arg_name = builtin_param_name; | 122 | *arg_name = builtin_param_name; |
| 133 | *arg_value_str = builtin_param; | 123 | *arg_value_str = builtin_param; |
| 134 | return sp_match_value(builtin_param, config_node->value, | 124 | return sp_match_value(builtin_param, config_node->value, |
| 135 | config_node->r_value); | 125 | config_node->r_value); |
| 136 | } else if (config_node->r_param || config_node->pos != -1) { | 126 | } |
| 137 | // We're matching on a function (and not a language construct) | ||
| 138 | for (; i < nb_param; i++) { | ||
| 139 | if (ZEND_USER_CODE(execute_data->func->type)) { // yay consistency | ||
| 140 | *arg_name = ZSTR_VAL(execute_data->func->common.arg_info[i].name); | ||
| 141 | } else { | ||
| 142 | *arg_name = execute_data->func->internal_function.arg_info[i].name; | ||
| 143 | } | ||
| 144 | const bool pcre_matching = | ||
| 145 | config_node->r_param && | ||
| 146 | (true == sp_is_regexp_matching(config_node->r_param, *arg_name)); | ||
| 147 | 127 | ||
| 148 | /* This is the parameter name we're looking for. */ | 128 | // safeguards |
| 149 | if (true == pcre_matching || config_node->pos != -1) { | 129 | if (!execute_data || !execute_data->func) { |
| 150 | arg_value = ZEND_CALL_ARG(execute_data, i + 1); | 130 | sp_log_debug("no execute data -> silently ignore parameter matching"); |
| 131 | return false; | ||
| 132 | } | ||
| 151 | 133 | ||
| 152 | if (config_node->param_type) { // Are we matching on the `type`? | 134 | *arg_name = NULL; |
| 153 | if (config_node->param_type == Z_TYPE_P(arg_value)) { | 135 | int call_num_args = EX_NUM_ARGS(); |
| 154 | return true; | 136 | zend_function *fn = execute_data->func; |
| 155 | } | 137 | int fn_num_args = fn->common.num_args; |
| 156 | } else if (Z_TYPE_P(arg_value) == IS_ARRAY) { | 138 | |
| 157 | *arg_value_str = sp_zval_to_zend_string(arg_value); | 139 | if (!call_num_args) { |
| 158 | if (config_node->key || config_node->r_key) { | 140 | sp_log_debug("no call arguments -> return"); |
| 159 | if (sp_match_array_key(arg_value, config_node->key, | 141 | return false; // no arguments to check |
| 160 | config_node->r_key)) { | 142 | } |
| 161 | return true; | 143 | |
| 162 | } | 144 | if (config_node->pos > call_num_args - 1 || config_node->pos > fn_num_args) { |
| 163 | } else if (sp_match_array_value(arg_value, config_node->value, | 145 | // trying to match argument beyond last given argument OR beyond last declared argument. |
| 164 | config_node->r_value)) { | 146 | // this is perfectly normal for functions with |
| 165 | return true; | 147 | // (a) optional arguments |
| 166 | } | 148 | // (b) excess arguments |
| 167 | } else { | 149 | // (c) variadic arguments which are not supported |
| 168 | *arg_value_str = sp_zval_to_zend_string(arg_value); | 150 | return false; |
| 169 | if (sp_match_value(*arg_value_str, config_node->value, | 151 | } |
| 170 | config_node->r_value)) { | 152 | |
| 171 | return true; | 153 | zval* arg_value = NULL; |
| 172 | } | 154 | |
| 173 | } | 155 | if (config_node->pos > -1) { |
| 174 | } | 156 | if (config_node->pos < fn_num_args) { |
| 157 | *arg_name = get_fn_arg_name(fn, config_node->pos); | ||
| 175 | } | 158 | } |
| 159 | arg_value = ZEND_CALL_ARG(execute_data, config_node->pos + 1); | ||
| 176 | } else if (config_node->param) { | 160 | } else if (config_node->param) { |
| 177 | *arg_name = config_node->param->value; | 161 | *arg_name = config_node->param->value; |
| 178 | arg_value = sp_get_var_value(execute_data, config_node->param, true); | 162 | arg_value = sp_get_var_value(execute_data, config_node->param, true); |
| 163 | } else if (config_node->r_param) { | ||
| 164 | for (int i = 0; i < call_num_args; i++) { | ||
| 165 | *arg_name = get_fn_arg_name(fn, i); | ||
| 166 | if (true == sp_is_regexp_matching(config_node->r_param, *arg_name)) { | ||
| 167 | arg_value = ZEND_CALL_ARG(execute_data, i + 1); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | if (!arg_value) { | ||
| 173 | sp_log_debug("no argument match -> return"); | ||
| 174 | return false; | ||
| 175 | } | ||
| 179 | 176 | ||
| 180 | if (arg_value) { | 177 | if (config_node->param_type) { |
| 181 | *arg_value_str = sp_zval_to_zend_string(arg_value); | 178 | if (config_node->param_type == Z_TYPE_P(arg_value)) { |
| 182 | if (config_node->param_type) { // Are we matching on the `type`? | 179 | if (!(config_node->key || config_node->r_key || config_node->value || config_node->r_value)) { // Are we matching on the `type` only? |
| 183 | if (config_node->param_type == Z_TYPE_P(arg_value)) { | 180 | sp_log_debug("arg type match only."); |
| 184 | return true; | ||
| 185 | } | ||
| 186 | } else if (Z_TYPE_P(arg_value) == IS_ARRAY) { | ||
| 187 | if (config_node->key || config_node->r_key) { | ||
| 188 | if (sp_match_array_key(arg_value, config_node->key, | ||
| 189 | config_node->r_key)) { | ||
| 190 | return true; | ||
| 191 | } | ||
| 192 | } else if (sp_match_array_value(arg_value, config_node->value, | ||
| 193 | config_node->r_value)) { | ||
| 194 | return true; | ||
| 195 | } | ||
| 196 | } else if (sp_match_value(*arg_value_str, config_node->value, | ||
| 197 | config_node->r_value)) { | ||
| 198 | return true; | 181 | return true; |
| 199 | } | 182 | } |
| 183 | } else { | ||
| 184 | sp_log_debug("arg type mismatch -> return"); | ||
| 185 | return false; | ||
| 200 | } | 186 | } |
| 201 | } | 187 | } |
| 188 | |||
| 189 | *arg_value_str = sp_zval_to_zend_string(arg_value); | ||
| 190 | if (Z_TYPE_P(arg_value) == IS_ARRAY) { | ||
| 191 | if (config_node->key || config_node->r_key) { | ||
| 192 | if (sp_match_array_key(arg_value, config_node->key, config_node->r_key)) { | ||
| 193 | return true; | ||
| 194 | } | ||
| 195 | } else if (sp_match_array_value(arg_value, config_node->value, config_node->r_value)) { | ||
| 196 | return true; | ||
| 197 | } | ||
| 198 | } else if (sp_match_value(*arg_value_str, config_node->value, config_node->r_value)) { | ||
| 199 | return true; | ||
| 200 | } | ||
| 201 | |||
| 202 | return false; | 202 | return false; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| @@ -287,6 +287,7 @@ static void should_disable(zend_execute_data* execute_data, | |||
| 287 | const sp_list_node* config, | 287 | const sp_list_node* config, |
| 288 | const zend_string* current_filename) { | 288 | const zend_string* current_filename) { |
| 289 | char current_file_hash[SHA256_SIZE * 2 + 1] = {0}; | 289 | char current_file_hash[SHA256_SIZE * 2 + 1] = {0}; |
| 290 | // sp_log_debug("%s %s %s", complete_function_path, builtin_param, builtin_param_name); | ||
| 290 | 291 | ||
| 291 | while (config) { | 292 | while (config) { |
| 292 | sp_disabled_function const* const config_node = | 293 | sp_disabled_function const* const config_node = |
