summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjvoisin2018-01-10 17:38:24 +0100
committerjvoisin2018-01-10 17:38:24 +0100
commit6f21bff1d40326f69bc3b75b1b83b03623180365 (patch)
tree09cc459ca549693d69f35098046d8ad64f3cde91 /src
parent773c9b94c6978ccd41c5a46f0d03448fd0c039a7 (diff)
Rework the priority of bl/wl in eval
Diffstat (limited to 'src')
-rw-r--r--src/sp_disabled_functions.c9
-rw-r--r--src/sp_execute.c34
-rw-r--r--src/sp_utils.c21
-rw-r--r--src/sp_utils.h1
-rw-r--r--src/tests/config/eval_whitelist_blacklist.ini2
-rw-r--r--src/tests/eval_backlist_whitelist.phpt10
-rw-r--r--src/tests/eval_whitelist.phpt27
7 files changed, 73 insertions, 31 deletions
diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c
index fa9d625..07c8696 100644
--- a/src/sp_disabled_functions.c
+++ b/src/sp_disabled_functions.c
@@ -5,9 +5,7 @@
5 5
6ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) 6ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
7 7
8 8char* get_complete_function_path(zend_execute_data const* const execute_data) {
9char* get_complete_function_path(
10 zend_execute_data const* const execute_data) {
11 if (zend_is_executing() && !EG(current_execute_data)->func) { 9 if (zend_is_executing() && !EG(current_execute_data)->func) {
12 return NULL; 10 return NULL;
13 } 11 }
@@ -469,6 +467,10 @@ ZEND_FUNCTION(eval_blacklist_callback) {
469 void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); 467 void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS);
470 const char* current_function_name = get_active_function_name(TSRMLS_C); 468 const char* current_function_name = get_active_function_name(TSRMLS_C);
471 469
470 if (true == check_is_in_eval_whitelist(current_function_name)) {
471 goto whitelisted;
472 }
473
472 if (SNUFFLEUPAGUS_G(in_eval) > 0) { 474 if (SNUFFLEUPAGUS_G(in_eval) > 0) {
473 const char* filename = get_eval_filename(zend_get_executed_filename()); 475 const char* filename = get_eval_filename(zend_get_executed_filename());
474 const int line_number = zend_get_executed_lineno(TSRMLS_C); 476 const int line_number = zend_get_executed_lineno(TSRMLS_C);
@@ -484,6 +486,7 @@ ZEND_FUNCTION(eval_blacklist_callback) {
484 } 486 }
485 } 487 }
486 488
489whitelisted:
487 orig_handler = zend_hash_str_find_ptr( 490 orig_handler = zend_hash_str_find_ptr(
488 SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook), current_function_name, 491 SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook), current_function_name,
489 strlen(current_function_name)); 492 strlen(current_function_name));
diff --git a/src/sp_execute.c b/src/sp_execute.c
index e6df1b6..ac7cee3 100644
--- a/src/sp_execute.c
+++ b/src/sp_execute.c
@@ -44,7 +44,8 @@ static void is_builtin_matching(const char *restrict const filename,
44 } 44 }
45} 45}
46 46
47static void is_in_eval_and_whitelisted(const zend_execute_data *execute_data) { 47static void ZEND_HOT
48is_in_eval_and_whitelisted(const zend_execute_data *execute_data) {
48 if (EXPECTED(0 == SNUFFLEUPAGUS_G(in_eval))) { 49 if (EXPECTED(0 == SNUFFLEUPAGUS_G(in_eval))) {
49 return; 50 return;
50 } 51 }
@@ -61,25 +62,16 @@ static void is_in_eval_and_whitelisted(const zend_execute_data *execute_data) {
61 return; 62 return;
62 } 63 }
63 64
64 char const* const current_function = ZSTR_VAL(EX(func)->common.function_name); 65 char const *const current_function = ZSTR_VAL(EX(func)->common.function_name);
65 66
66 if (EXPECTED(current_function)) { 67 if (EXPECTED(NULL != current_function)) {
67 const sp_list_node *it = SNUFFLEUPAGUS_G(config).config_eval->whitelist; 68 if (false == check_is_in_eval_whitelist(current_function)) {
68 /* yes, we could use a HashTable instead, but since the list is pretty 69 sp_log_msg(
69 * small, it doesn't maka a difference in practise. */ 70 "Eval_whitelist", SP_LOG_DROP,
70 while (it) { 71 "The function '%s' isn't in the eval whitelist, dropping its call.",
71 if (0 == strcmp(current_function, (char *)(it->data))) { 72 current_function);
72 /* We've got a match, the function is whiteslited. */ 73 sp_terminate();
73 return;
74 }
75 it = it->next;
76 } 74 }
77
78 sp_log_msg(
79 "Eval_whitelist", SP_LOG_DROP,
80 "The function '%s' isn't in the eval whitelist, dropping its call.",
81 current_function);
82 sp_terminate();
83 } 75 }
84} 76}
85 77
@@ -104,6 +96,8 @@ char *get_eval_filename(const char *filename) {
104} 96}
105 97
106static void sp_execute_ex(zend_execute_data *execute_data) { 98static void sp_execute_ex(zend_execute_data *execute_data) {
99 is_in_eval_and_whitelisted(execute_data);
100
107 if (true == should_disable(execute_data, NULL, NULL, NULL)) { 101 if (true == should_disable(execute_data, NULL, NULL, NULL)) {
108 sp_terminate(); 102 sp_terminate();
109 } 103 }
@@ -117,8 +111,6 @@ static void sp_execute_ex(zend_execute_data *execute_data) {
117 efree(filename); 111 efree(filename);
118 } 112 }
119 113
120 is_in_eval_and_whitelisted(execute_data);
121
122 if (NULL != EX(func)->op_array.filename) { 114 if (NULL != EX(func)->op_array.filename) {
123 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { 115 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) {
124 terminate_if_writable(ZSTR_VAL(EX(func)->op_array.filename)); 116 terminate_if_writable(ZSTR_VAL(EX(func)->op_array.filename));
@@ -176,7 +168,7 @@ static int sp_stream_open(const char *filename, zend_file_handle *handle) {
176 is_builtin_matching(filename, "include_once", "inclusion path", 168 is_builtin_matching(filename, "include_once", "inclusion path",
177 config); 169 config);
178 break; 170 break;
179 EMPTY_SWITCH_DEFAULT_CASE(); 171 EMPTY_SWITCH_DEFAULT_CASE();
180 } 172 }
181 } 173 }
182 174
diff --git a/src/sp_utils.c b/src/sp_utils.c
index 8a1ed87..19b7179 100644
--- a/src/sp_utils.c
+++ b/src/sp_utils.c
@@ -7,6 +7,8 @@
7#include <string.h> 7#include <string.h>
8#include <unistd.h> 8#include <unistd.h>
9 9
10ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
11
10static inline void _sp_log_err(const char* fmt, ...) { 12static inline void _sp_log_err(const char* fmt, ...) {
11 char* msg; 13 char* msg;
12 va_list args; 14 va_list args;
@@ -394,3 +396,22 @@ int hook_regexp(const pcre* regexp, HashTable* hook_table,
394 ZEND_HASH_FOREACH_END(); 396 ZEND_HASH_FOREACH_END();
395 return SUCCESS; 397 return SUCCESS;
396} 398}
399
400bool check_is_in_eval_whitelist(const char* const function_name) {
401 const sp_list_node* it = SNUFFLEUPAGUS_G(config).config_eval->whitelist;
402
403 if (!it->head) {
404 return false;
405 }
406
407 /* yes, we could use a HashTable instead, but since the list is pretty
408 * small, it doesn't maka a difference in practise. */
409 while (it && it->data) {
410 if (0 == strcmp(function_name, (char*)(it->data))) {
411 /* We've got a match, the function is whiteslited. */
412 return true;
413 }
414 it = it->next;
415 }
416 return false;
417}
diff --git a/src/sp_utils.h b/src/sp_utils.h
index e055e70..a7b672f 100644
--- a/src/sp_utils.h
+++ b/src/sp_utils.h
@@ -69,5 +69,6 @@ int hook_function(const char *, HashTable *,
69 void (*)(INTERNAL_FUNCTION_PARAMETERS), bool); 69 void (*)(INTERNAL_FUNCTION_PARAMETERS), bool);
70int hook_regexp(const pcre *, HashTable *, 70int hook_regexp(const pcre *, HashTable *,
71 void (*)(INTERNAL_FUNCTION_PARAMETERS), bool); 71 void (*)(INTERNAL_FUNCTION_PARAMETERS), bool);
72bool check_is_in_eval_whitelist(const char * const function_name);
72 73
73#endif /* SP_UTILS_H */ 74#endif /* SP_UTILS_H */
diff --git a/src/tests/config/eval_whitelist_blacklist.ini b/src/tests/config/eval_whitelist_blacklist.ini
new file mode 100644
index 0000000..a916004
--- /dev/null
+++ b/src/tests/config/eval_whitelist_blacklist.ini
@@ -0,0 +1,2 @@
1sp.eval_blacklist.list("my_fun,cos");
2sp.eval_whitelist.list("my_fun");
diff --git a/src/tests/eval_backlist_whitelist.phpt b/src/tests/eval_backlist_whitelist.phpt
index 1611288..9b0bb55 100644
--- a/src/tests/eval_backlist_whitelist.phpt
+++ b/src/tests/eval_backlist_whitelist.phpt
@@ -3,25 +3,21 @@ Eval whitelist
3--SKIPIF-- 3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?> 4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI-- 5--INI--
6sp.configuration_file={PWD}/config/eval_whitelist.ini 6sp.configuration_file={PWD}/config/eval_whitelist_blacklist.ini
7--FILE-- 7--FILE--
8<?php 8<?php
9function my_fun($p) { 9function my_fun($p) {
10 return "my_fun: $p"; 10 return "my_fun: $p";
11} 11}
12 12
13function my_other_fun($p) {
14 return "my_other_fun: $p";
15}
16
17$a = my_fun("1337 1337 1337"); 13$a = my_fun("1337 1337 1337");
18echo "Outside of eval: $a\n"; 14echo "Outside of eval: $a\n";
19eval('$a = my_fun("1234");'); 15eval('$a = my_fun("1234");');
20echo "After allowed eval: $a\n"; 16echo "After allowed eval: $a\n";
21eval('$a = my_other_fun("1234");'); 17eval('$a = cos(1234);');
22echo "After eval: $a\n"; 18echo "After eval: $a\n";
23?> 19?>
24--EXPECTF-- 20--EXPECTF--
25Outside of eval: my_fun: 1337 1337 1337 21Outside of eval: my_fun: 1337 1337 1337
26After allowed eval: my_fun: 1234 22After allowed eval: my_fun: 1234
27[snuffleupagus][0.0.0.0][Eval_whitelist][drop] The function 'my_other_fun' isn't in the eval whitelist, dropping its call. 23[snuffleupagus][0.0.0.0][Eval_whitelist][drop] The function 'cos' isn't in the eval whitelist, dropping its call.
diff --git a/src/tests/eval_whitelist.phpt b/src/tests/eval_whitelist.phpt
new file mode 100644
index 0000000..1611288
--- /dev/null
+++ b/src/tests/eval_whitelist.phpt
@@ -0,0 +1,27 @@
1--TEST--
2Eval whitelist
3--SKIPIF--
4<?php if (!extension_loaded("snuffleupagus")) die "skip"; ?>
5--INI--
6sp.configuration_file={PWD}/config/eval_whitelist.ini
7--FILE--
8<?php
9function my_fun($p) {
10 return "my_fun: $p";
11}
12
13function my_other_fun($p) {
14 return "my_other_fun: $p";
15}
16
17$a = my_fun("1337 1337 1337");
18echo "Outside of eval: $a\n";
19eval('$a = my_fun("1234");');
20echo "After allowed eval: $a\n";
21eval('$a = my_other_fun("1234");');
22echo "After eval: $a\n";
23?>
24--EXPECTF--
25Outside of eval: my_fun: 1337 1337 1337
26After allowed eval: my_fun: 1234
27[snuffleupagus][0.0.0.0][Eval_whitelist][drop] The function 'my_other_fun' isn't in the eval whitelist, dropping its call.