Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Commit

Permalink
Implement matching on the calltrace (#17)
Browse files Browse the repository at this point in the history
* Implement matching on the calltrace
  • Loading branch information
jvoisin committed Oct 9, 2017
1 parent 50bb0ed commit 7234fdb
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ src/Makefile.objects
src/missing
src/mkinstalldirs
src/run-tests.php
doc/build/
1 change: 1 addition & 0 deletions src/sp_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ typedef struct {

char *function;
pcre *r_function;
sp_node_t *functions_list;

char *hash;
int simulation;
Expand Down
4 changes: 4 additions & 0 deletions src/sp_config_keywords.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
20 changes: 20 additions & 0 deletions src/sp_config_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
1 change: 1 addition & 0 deletions src/sp_config_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
48 changes: 45 additions & 3 deletions src/sp_disabled_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions src/sp_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
1 change: 1 addition & 0 deletions src/sp_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions src/tests/config/config_disabled_functions_chain.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sp.disable_functions.function("outer>inner").drop();
28 changes: 28 additions & 0 deletions src/tests/disabled_functions_chain.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
Disable functions by matching the calltrace
--SKIPIF--
<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
--INI--
sp.configuration_file={PWD}/config/config_disabled_functions_chain.ini
--FILE--
<?php

function outer() {
function inner() {
echo "I'm in the inner function!\n";
}
echo "I'm in the outer function, before the call!\n";
inner();
echo "I'm in the outer function, after the call!\n";
}

echo "I'm before the call to outer\n";
outer();
echo "I'm after the call to outer\n";
?>
--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
28 changes: 28 additions & 0 deletions src/tests/disabled_functions_chain_not_matching.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
Disable functions by matching the calltrace
--SKIPIF--
<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
--INI--
sp.configuration_file={PWD}/config/config_disabled_functions_chain.ini
--FILE--
<?php

function outer() {
function inner_() {
echo "I'm in the inner function!\n";
}
echo "I'm in the outer function, before the call!\n";
inner_();
echo "I'm in the outer function, after the call!\n";
}

echo "I'm before the call to outer\n";
outer();
echo "I'm after the call to outer\n";
?>
--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

0 comments on commit 7234fdb

Please sign in to comment.