summaryrefslogtreecommitdiff
path: root/src/sp_execute.c
diff options
context:
space:
mode:
authorjvoisin2018-01-10 14:56:33 +0100
committerGitHub2018-01-10 14:56:33 +0100
commitad6b3e723fe26bf1a3a573aed776960916d35499 (patch)
treeeec9e15028f4529d776489d273bf9699333aa987 /src/sp_execute.c
parentb6e5bc4557cca3abbcfd179e7143ea54b9844e49 (diff)
Eval whitelist
Implement whitelist in eval
Diffstat (limited to 'src/sp_execute.c')
-rw-r--r--src/sp_execute.c88
1 files changed, 69 insertions, 19 deletions
diff --git a/src/sp_execute.c b/src/sp_execute.c
index 3ce6643..c1d68d7 100644
--- a/src/sp_execute.c
+++ b/src/sp_execute.c
@@ -6,6 +6,8 @@
6ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) 6ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
7 7
8static void (*orig_execute_ex)(zend_execute_data *execute_data); 8static void (*orig_execute_ex)(zend_execute_data *execute_data);
9static void (*orig_zend_execute_internal)(zend_execute_data *execute_data,
10 zval *return_value);
9static int (*orig_zend_stream_open)(const char *filename, 11static int (*orig_zend_stream_open)(const char *filename,
10 zend_file_handle *handle); 12 zend_file_handle *handle);
11 13
@@ -29,9 +31,9 @@ ZEND_COLD static inline void terminate_if_writable(const char *filename) {
29} 31}
30 32
31static void is_builtin_matching(const char *restrict const filename, 33static void is_builtin_matching(const char *restrict const filename,
32 char *restrict function_name, 34 const char *restrict const function_name,
33 char *restrict param_name, 35 const char *restrict const param_name,
34 sp_list_node *config) { 36 const sp_list_node *config) {
35 if (!config || !config->data) { 37 if (!config || !config->data) {
36 return; 38 return;
37 } 39 }
@@ -42,6 +44,43 @@ static void is_builtin_matching(const char *restrict const filename,
42 } 44 }
43} 45}
44 46
47static void is_in_eval_and_whitelisted(zend_execute_data *execute_data) {
48 if (EXPECTED(0 == SNUFFLEUPAGUS_G(in_eval))) {
49 return;
50 }
51
52 if (EXPECTED(NULL == SNUFFLEUPAGUS_G(config).config_eval->whitelist->data)) {
53 return;
54 }
55
56 if (zend_is_executing() && !EG(current_execute_data)->func) {
57 return;
58 }
59
60 if (!(execute_data->func->common.function_name)) {
61 return;
62 }
63
64 char const* const current_function = ZSTR_VAL(EX(func)->common.function_name);
65
66 if (EXPECTED(current_function)) {
67 const sp_list_node *it = SNUFFLEUPAGUS_G(config).config_eval->whitelist;
68 while (it) {
69 if (0 == strcmp(current_function, (char *)(it->data))) {
70 /* We've got a match, the function is whiteslited. */
71 return;
72 }
73 it = it->next;
74 }
75
76 sp_log_msg(
77 "Eval_whitelist", SP_LOG_DROP,
78 "The function '%s' isn't in the eval whitelist, dropping its call.",
79 current_function);
80 sp_terminate();
81 }
82}
83
45/* This function gets the filename in which `eval()` is called from, 84/* This function gets the filename in which `eval()` is called from,
46 * since it looks like "foo.php(1) : eval()'d code", so we're starting 85 * since it looks like "foo.php(1) : eval()'d code", so we're starting
47 * from the end of the string until the second closing parenthesis. */ 86 * from the end of the string until the second closing parenthesis. */
@@ -67,28 +106,42 @@ static void sp_execute_ex(zend_execute_data *execute_data) {
67 sp_terminate(); 106 sp_terminate();
68 } 107 }
69 108
70 if (execute_data->func->op_array.type == ZEND_EVAL_CODE) { 109 if (EX(func)->op_array.type == ZEND_EVAL_CODE) {
71 SNUFFLEUPAGUS_G(in_eval)++; 110 SNUFFLEUPAGUS_G(in_eval)++;
72 sp_list_node *config = 111 const sp_list_node *config =
73 SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval; 112 SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval;
74 char *filename = get_eval_filename((char *)zend_get_executed_filename()); 113 char *filename = get_eval_filename((char *)zend_get_executed_filename());
75 is_builtin_matching(filename, "eval", NULL, config); 114 is_builtin_matching(filename, "eval", NULL, config);
76 efree(filename); 115 efree(filename);
77 } 116 }
78 117
79 if (NULL != execute_data->func->op_array.filename) { 118 is_in_eval_and_whitelisted(execute_data);
119
120 if (NULL != EX(func)->op_array.filename) {
80 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { 121 if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) {
81 terminate_if_writable(ZSTR_VAL(execute_data->func->op_array.filename)); 122 terminate_if_writable(ZSTR_VAL(EX(func)->op_array.filename));
82 } 123 }
83 } 124 }
84 125
85 orig_execute_ex(execute_data); 126 orig_execute_ex(execute_data);
86 127
87 if (true == should_drop_on_ret(execute_data->return_value, execute_data)) { 128 if (true == should_drop_on_ret(EX(return_value), execute_data)) {
88 sp_terminate(); 129 sp_terminate();
89 } 130 }
90 131
91 SNUFFLEUPAGUS_G(in_eval)--; 132 if (ZEND_EVAL_CODE == EX(func)->op_array.type) {
133 SNUFFLEUPAGUS_G(in_eval)--;
134 }
135}
136
137static void sp_zend_execute_internal(INTERNAL_FUNCTION_PARAMETERS) {
138 is_in_eval_and_whitelisted(execute_data);
139
140 EX(func)->internal_function.handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
141
142 if (UNEXPECTED(NULL != orig_zend_execute_internal)) {
143 orig_zend_execute_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
144 }
92} 145}
93 146
94static int sp_stream_open(const char *filename, zend_file_handle *handle) { 147static int sp_stream_open(const char *filename, zend_file_handle *handle) {
@@ -121,11 +174,7 @@ static int sp_stream_open(const char *filename, zend_file_handle *handle) {
121 is_builtin_matching(filename, "include_once", "inclusion path", 174 is_builtin_matching(filename, "include_once", "inclusion path",
122 config); 175 config);
123 break; 176 break;
124 case ZEND_EVAL: 177 EMPTY_SWITCH_DEFAULT_CASE();
125 is_builtin_matching(filename, "eval", NULL, config);
126 break;
127 default:
128 break;
129 } 178 }
130 } 179 }
131 180
@@ -136,16 +185,17 @@ end:
136int hook_execute(void) { 185int hook_execute(void) {
137 TSRMLS_FETCH(); 186 TSRMLS_FETCH();
138 187
139 /* zend_execute_ex is used for "classic" function calls */ 188 /* zend_execute_ex is used for "user" function calls */
140 orig_execute_ex = zend_execute_ex; 189 orig_execute_ex = zend_execute_ex;
141 zend_execute_ex = sp_execute_ex; 190 zend_execute_ex = sp_execute_ex;
142 191
143 /* zend_stream_open_function is used FIXME */ 192 /* zend_execute_internal is used for "builtin" functions calls */
193 orig_zend_execute_internal = zend_execute_internal;
194 zend_execute_internal = sp_zend_execute_internal;
195
196 /* zend_stream_open_function is used for include-related stuff */
144 orig_zend_stream_open = zend_stream_open_function; 197 orig_zend_stream_open = zend_stream_open_function;
145 zend_stream_open_function = sp_stream_open; 198 zend_stream_open_function = sp_stream_open;
146 199
147 /* zend_execute_internal is used for "indirect" functions call,
148 * like array_map or call_user_func. */
149
150 return SUCCESS; 200 return SUCCESS;
151} 201}