From 7234fdbb0cb0dd45ed1d6e7814c91e596126ee25 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Mon, 9 Oct 2017 11:54:11 +0200 Subject: Implement matching on the calltrace (#17) * Implement matching on the calltrace--- src/sp_config.h | 1 + src/sp_config_keywords.c | 4 ++ src/sp_config_utils.c | 20 +++++++++ src/sp_config_utils.h | 1 + src/sp_disabled_functions.c | 48 ++++++++++++++++++++-- src/sp_list.c | 18 ++++++++ src/sp_list.h | 1 + .../config/config_disabled_functions_chain.ini | 1 + src/tests/disabled_functions_chain.phpt | 28 +++++++++++++ .../disabled_functions_chain_not_matching.phpt | 28 +++++++++++++ 10 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 src/tests/config/config_disabled_functions_chain.ini create mode 100644 src/tests/disabled_functions_chain.phpt create mode 100644 src/tests/disabled_functions_chain_not_matching.phpt (limited to 'src') diff --git a/src/sp_config.h b/src/sp_config.h index 34096ce..d5cd1dc 100644 --- a/src/sp_config.h +++ b/src/sp_config.h @@ -68,6 +68,7 @@ typedef struct { char *function; pcre *r_function; + sp_node_t *functions_list; char *hash; int simulation; diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index cf52ae3..d6107c3 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -185,6 +185,10 @@ int parse_disabled_functions(char *line) { return -1; } + if (df->function) { + df->functions_list = parse_functions_list(df->function); + } + if (df->param && strchr(df->param, '[')) { // assume that this is an array df->param_array_keys = sp_new_list(); if (0 != array_to_list(&df->param, &df->param_array_keys)) { diff --git a/src/sp_config_utils.c b/src/sp_config_utils.c index 3ea82d0..b0c7d3c 100644 --- a/src/sp_config_utils.c +++ b/src/sp_config_utils.c @@ -167,3 +167,23 @@ int array_to_list(char **name_ptr, sp_node_t **keys) { *name_ptr = pestrdup(tmp, 1); return in_key; } + + +zend_always_inline sp_node_t *parse_functions_list(char *value) { + const char *sep = ">"; + + if (NULL == strchr(value, sep[0])) { + return NULL; + } + + sp_node_t *list = sp_new_list(); + char* tmp = strdup(value); + char* function_name; + char *next_token = tmp; + while ((function_name = strtok_r(NULL, sep, &next_token))) { + sp_list_prepend(list, strdup(function_name)); + } + free(tmp); + + return list; +} \ No newline at end of file diff --git a/src/sp_config_utils.h b/src/sp_config_utils.h index f2f8fce..e561d57 100644 --- a/src/sp_config_utils.h +++ b/src/sp_config_utils.h @@ -4,5 +4,6 @@ int parse_keywords(sp_config_functions *, char *); char *get_param(size_t *, char *restrict, sp_type, const char *restrict); int array_to_list(char **, sp_node_t **); +sp_node_t *parse_functions_list(char *value); #endif /* SP_CONFIG_UTILS */ diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c index b3e5cbc..b465a30 100644 --- a/src/sp_disabled_functions.c +++ b/src/sp_disabled_functions.c @@ -31,6 +31,35 @@ static zend_always_inline char* get_complete_function_path( return complete_path_function; } +static bool is_functions_list_matching(zend_execute_data *execute_data, sp_node_t *functions_list) { + zend_execute_data *orig_execute_data, *current; + orig_execute_data = current = execute_data; + sp_node_t *it = functions_list; + + while (current) { + if (it == NULL) { // every function in the list matched, we've got a match! + return true; + } + + EG(current_execute_data) = current; + + char *complete_path_function = get_complete_function_path(current); + int match = strcmp(((char*)it->data), complete_path_function); + efree(complete_path_function); + + if (0 == match) { + it = it->next; + current = current->prev_execute_data; + } else { + EG(current_execute_data) = orig_execute_data; + return false; + } + } + + EG(current_execute_data) = orig_execute_data; + return false; +} + static bool is_local_var_matching(zend_execute_data *execute_data, const sp_disabled_function *const config_node) { zend_execute_data *orig_execute_data = execute_data; @@ -100,7 +129,14 @@ bool should_disable(zend_execute_data* execute_data) { goto next; } - if (config_node->function) { /* Litteral match against the function name. */ + /* The order matters, since when we have `config_node->functions_list`, + we also do have `config_node->function` */ + if (config_node->functions_list) { + if (false == + is_functions_list_matching(execute_data, config_node->functions_list)) { + goto next; + } + } else if (config_node->function) { /* Litteral match against the function name. */ if (0 != strcmp(config_node->function, complete_path_function)) { goto next; } @@ -110,6 +146,7 @@ bool should_disable(zend_execute_data* execute_data) { goto next; } } + if (config_node->var) { if (false == is_local_var_matching(execute_data, config_node)) { goto next; @@ -207,8 +244,13 @@ bool should_disable(zend_execute_data* execute_data) { goto allow; } - sp_log_disable(complete_path_function, arg_name, arg_value_str, - config_node); + if (config_node->functions_list) { + sp_log_disable(config_node->function, arg_name, arg_value_str, + config_node); + } else { + sp_log_disable(complete_path_function, arg_name, arg_value_str, + config_node); + } if (true == config_node->simulation) { goto next; } else { // We've got a match, the function won't be executed diff --git a/src/sp_list.c b/src/sp_list.c index 04154b7..112d822 100644 --- a/src/sp_list.c +++ b/src/sp_list.c @@ -35,3 +35,21 @@ void sp_list_insert(sp_node_t *list, void *data) { list->next = new; } } + +void sp_list_prepend(sp_node_t *list, void *data) { + if (list->head == NULL) { + list->data = data; + list->next = NULL; + list->head = list; + } else { + sp_node_t *new = pecalloc(sizeof(*new), 1, 1); + + new->next = list->next; + list->next = new; + + new->head = list; + + new->data = list->data; + list->data = data; + } +} \ No newline at end of file diff --git a/src/sp_list.h b/src/sp_list.h index 48b11f6..476c64c 100644 --- a/src/sp_list.h +++ b/src/sp_list.h @@ -11,5 +11,6 @@ typedef struct sp_node_s { sp_node_t *sp_new_list(); void sp_list_insert(sp_node_t *, void *); void sp_list_free(sp_node_t *); +void sp_list_prepend(sp_node_t *, void *); #endif diff --git a/src/tests/config/config_disabled_functions_chain.ini b/src/tests/config/config_disabled_functions_chain.ini new file mode 100644 index 0000000..f47af34 --- /dev/null +++ b/src/tests/config/config_disabled_functions_chain.ini @@ -0,0 +1 @@ +sp.disable_functions.function("outer>inner").drop(); diff --git a/src/tests/disabled_functions_chain.phpt b/src/tests/disabled_functions_chain.phpt new file mode 100644 index 0000000..b25f800 --- /dev/null +++ b/src/tests/disabled_functions_chain.phpt @@ -0,0 +1,28 @@ +--TEST-- +Disable functions by matching the calltrace +--SKIPIF-- + +--INI-- +sp.configuration_file={PWD}/config/config_disabled_functions_chain.ini +--FILE-- + +--EXPECTF-- +I'm before the call to outer +I'm in the outer function, before the call! +[snuffleupagus][0.0.0.0][disabled_function][drop] The call to the function 'outer>inner' in %a/disabled_functions_chain.php:%d has been disabled. +I'm in the outer function, after the call! +I'm after the call to outer diff --git a/src/tests/disabled_functions_chain_not_matching.phpt b/src/tests/disabled_functions_chain_not_matching.phpt new file mode 100644 index 0000000..3a0400a --- /dev/null +++ b/src/tests/disabled_functions_chain_not_matching.phpt @@ -0,0 +1,28 @@ +--TEST-- +Disable functions by matching the calltrace +--SKIPIF-- + +--INI-- +sp.configuration_file={PWD}/config/config_disabled_functions_chain.ini +--FILE-- + +--EXPECTF-- +I'm before the call to outer +I'm in the outer function, before the call! +I'm in the inner function! +I'm in the outer function, after the call! +I'm after the call to outer -- cgit v1.3