summaryrefslogtreecommitdiff
path: root/src/sp_disabled_functions.c
diff options
context:
space:
mode:
authorxXx-caillou-xXx2018-07-13 10:36:50 +0200
committerjvoisin2018-07-13 08:36:50 +0000
commit7963580d72a358975133f86f01de2d2eab08ba38 (patch)
tree4bec345d70f687a2a6002b36e2f2fc79318959f6 /src/sp_disabled_functions.c
parent12b740bc7bb01ffe397cecc5b6fa25b136304911 (diff)
Massively optimize how rules are handled
This commit does a lot of things: - Use hashtables instead of lists to store the rules - Rules that can be applied at launch time won't be tried at runtime - Improve feedback when writing nonsensical rules - Make intensive use of `zend_string` instead of `char*`
Diffstat (limited to 'src/sp_disabled_functions.c')
-rw-r--r--src/sp_disabled_functions.c304
1 files changed, 180 insertions, 124 deletions
diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c
index 341c0a4..14783f6 100644
--- a/src/sp_disabled_functions.c
+++ b/src/sp_disabled_functions.c
@@ -65,7 +65,7 @@ static bool is_functions_list_matching(zend_execute_data* execute_data,
65static bool is_local_var_matching( 65static bool is_local_var_matching(
66 zend_execute_data* execute_data, 66 zend_execute_data* execute_data,
67 const sp_disabled_function* const config_node) { 67 const sp_disabled_function* const config_node) {
68 zval* var_value; 68 zval* var_value = {0};
69 69
70 var_value = sp_get_var_value(execute_data, config_node->var, false); 70 var_value = sp_get_var_value(execute_data, config_node->var, false);
71 if (var_value) { 71 if (var_value) {
@@ -76,14 +76,13 @@ static bool is_local_var_matching(
76 return true; 76 return true;
77 } 77 }
78 } else if (sp_match_array_value(var_value, config_node->value, 78 } else if (sp_match_array_value(var_value, config_node->value,
79 config_node->value_r)) { 79 config_node->r_value)) {
80 return true; 80 return true;
81 } 81 }
82 } else { 82 } else {
83 char* var_value_str = sp_convert_to_string(var_value); 83 const zend_string* var_value_str = sp_zval_to_zend_string(var_value);
84 bool match = sp_match_value(var_value_str, config_node->value, 84 bool match = sp_match_value(var_value_str, config_node->value,
85 config_node->value_r); 85 config_node->r_value);
86 efree(var_value_str);
87 86
88 if (true == match) { 87 if (true == match) {
89 return true; 88 return true;
@@ -93,28 +92,12 @@ static bool is_local_var_matching(
93 return false; 92 return false;
94} 93}
95 94
96static inline const sp_list_node* get_config_node(const char* builtin_name) {
97 if (EXPECTED(!builtin_name)) {
98 return SNUFFLEUPAGUS_G(config)
99 .config_disabled_functions->disabled_functions;
100 } else if (!strcmp(builtin_name, "eval")) {
101 return SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval;
102 } else if (!strcmp(builtin_name, "include") ||
103 !strcmp(builtin_name, "include_once") ||
104 !strcmp(builtin_name, "require") ||
105 !strcmp(builtin_name, "require_once")) {
106 return SNUFFLEUPAGUS_G(config)
107 .config_disabled_constructs->construct_include;
108 }
109 ZEND_ASSUME(0);
110}
111
112static bool is_param_matching(zend_execute_data* execute_data, 95static bool is_param_matching(zend_execute_data* execute_data,
113 sp_disabled_function const* const config_node, 96 sp_disabled_function const* const config_node,
114 const char* builtin_name, 97 const zend_string* builtin_param,
115 const char* builtin_param, const char** arg_name, 98 const char** arg_name,
116 const char* builtin_param_name, 99 const char* builtin_param_name,
117 const char** arg_value_str) { 100 const zend_string** arg_value_str) {
118 int nb_param = ZEND_CALL_NUM_ARGS(execute_data); 101 int nb_param = ZEND_CALL_NUM_ARGS(execute_data);
119 int i = 0; 102 int i = 0;
120 zval* arg_value; 103 zval* arg_value;
@@ -136,14 +119,14 @@ static bool is_param_matching(zend_execute_data* execute_data,
136 } 119 }
137 } 120 }
138 121
139 if (builtin_name) { 122 if (builtin_param) {
140 /* We're matching on a language construct (here named "builtin"), 123 /* We're matching on a language construct (here named "builtin"),
141 * and they can only take a single argument, but PHP considers them 124 * and they can only take a single argument, but PHP considers them
142 * differently than functions arguments. */ 125 * differently than functions arguments. */
143 *arg_name = builtin_param_name; 126 *arg_name = builtin_param_name;
144 *arg_value_str = builtin_param; 127 *arg_value_str = builtin_param;
145 return sp_match_value(builtin_param, config_node->value, 128 return sp_match_value(builtin_param, config_node->value,
146 config_node->value_r); 129 config_node->r_value);
147 } else if (config_node->r_param || config_node->pos != -1) { 130 } else if (config_node->r_param || config_node->pos != -1) {
148 // We're matching on a function (and not a language construct) 131 // We're matching on a function (and not a language construct)
149 for (; i < nb_param; i++) { 132 for (; i < nb_param; i++) {
@@ -165,20 +148,20 @@ static bool is_param_matching(zend_execute_data* execute_data,
165 return true; 148 return true;
166 } 149 }
167 } else if (Z_TYPE_P(arg_value) == IS_ARRAY) { 150 } else if (Z_TYPE_P(arg_value) == IS_ARRAY) {
168 *arg_value_str = sp_convert_to_string(arg_value); 151 *arg_value_str = sp_zval_to_zend_string(arg_value);
169 if (config_node->key || config_node->r_key) { 152 if (config_node->key || config_node->r_key) {
170 if (sp_match_array_key(arg_value, config_node->key, 153 if (sp_match_array_key(arg_value, config_node->key,
171 config_node->r_key)) { 154 config_node->r_key)) {
172 return true; 155 return true;
173 } 156 }
174 } else if (sp_match_array_value(arg_value, config_node->value, 157 } else if (sp_match_array_value(arg_value, config_node->value,
175 config_node->value_r)) { 158 config_node->r_value)) {
176 return true; 159 return true;
177 } 160 }
178 } else { 161 } else {
179 *arg_value_str = sp_convert_to_string(arg_value); 162 *arg_value_str = sp_zval_to_zend_string(arg_value);
180 if (sp_match_value(*arg_value_str, config_node->value, 163 if (sp_match_value(*arg_value_str, config_node->value,
181 config_node->value_r)) { 164 config_node->r_value)) {
182 return true; 165 return true;
183 } 166 }
184 } 167 }
@@ -189,7 +172,7 @@ static bool is_param_matching(zend_execute_data* execute_data,
189 arg_value = sp_get_var_value(execute_data, config_node->param, true); 172 arg_value = sp_get_var_value(execute_data, config_node->param, true);
190 173
191 if (arg_value) { 174 if (arg_value) {
192 *arg_value_str = sp_convert_to_string(arg_value); 175 *arg_value_str = sp_zval_to_zend_string(arg_value);
193 if (config_node->param_type) { // Are we matching on the `type`? 176 if (config_node->param_type) { // Are we matching on the `type`?
194 if (config_node->param_type == Z_TYPE_P(arg_value)) { 177 if (config_node->param_type == Z_TYPE_P(arg_value)) {
195 return true; 178 return true;
@@ -201,11 +184,11 @@ static bool is_param_matching(zend_execute_data* execute_data,
201 return true; 184 return true;
202 } 185 }
203 } else if (sp_match_array_value(arg_value, config_node->value, 186 } else if (sp_match_array_value(arg_value, config_node->value,
204 config_node->value_r)) { 187 config_node->r_value)) {
205 return true; 188 return true;
206 } 189 }
207 } else if (sp_match_value(*arg_value_str, config_node->value, 190 } else if (sp_match_value(*arg_value_str, config_node->value,
208 config_node->value_r)) { 191 config_node->r_value)) {
209 return true; 192 return true;
210 } 193 }
211 } 194 }
@@ -216,7 +199,7 @@ static bool is_param_matching(zend_execute_data* execute_data,
216static zend_execute_data* is_file_matching( 199static zend_execute_data* is_file_matching(
217 zend_execute_data* const execute_data, 200 zend_execute_data* const execute_data,
218 sp_disabled_function const* const config_node, 201 sp_disabled_function const* const config_node,
219 char const* const current_filename) { 202 zend_string const* const current_filename) {
220#define ITERATE(ex) \ 203#define ITERATE(ex) \
221 ex = ex->prev_execute_data; \ 204 ex = ex->prev_execute_data; \
222 while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) \ 205 while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) \
@@ -225,22 +208,21 @@ static zend_execute_data* is_file_matching(
225 208
226 zend_execute_data* ex = execute_data; 209 zend_execute_data* ex = execute_data;
227 if (config_node->filename) { 210 if (config_node->filename) {
228 if (0 == strcmp(current_filename, config_node->filename)) { 211 if (zend_string_equals_literal(current_filename, config_node->filename)) {
229 return ex; 212 return ex;
230 } 213 }
231 ITERATE(ex); 214 ITERATE(ex);
232 if (0 == 215 if (zend_string_equals_literal(ex->func->op_array.filename,
233 strcmp(ZSTR_VAL(ex->func->op_array.filename), config_node->filename)) { 216 config_node->filename)) {
234 return ex; 217 return ex;
235 } 218 }
236 } else if (config_node->r_filename) { 219 } else if (config_node->r_filename) {
237 if (true == 220 if (sp_is_regexp_matching_zend(config_node->r_filename, current_filename)) {
238 sp_is_regexp_matching(config_node->r_filename, current_filename)) {
239 return ex; 221 return ex;
240 } 222 }
241 ITERATE(ex); 223 ITERATE(ex);
242 if (true == sp_is_regexp_matching(config_node->r_filename, 224 if (sp_is_regexp_matching_zend(config_node->r_filename,
243 ZSTR_VAL(ex->func->op_array.filename))) { 225 ex->func->op_array.filename)) {
244 return ex; 226 return ex;
245 } 227 }
246 } 228 }
@@ -251,10 +233,10 @@ static zend_execute_data* is_file_matching(
251static bool check_is_builtin_name( 233static bool check_is_builtin_name(
252 sp_disabled_function const* const config_node) { 234 sp_disabled_function const* const config_node) {
253 if (config_node->function) { 235 if (config_node->function) {
254 return (!strcmp(config_node->function, "include") || 236 return (zend_string_equals_literal(config_node->function, "include") ||
255 !strcmp(config_node->function, "include_once") || 237 zend_string_equals_literal(config_node->function, "include_once") ||
256 !strcmp(config_node->function, "require") || 238 zend_string_equals_literal(config_node->function, "require") ||
257 !strcmp(config_node->function, "require_once")); 239 zend_string_equals_literal(config_node->function, "require_once"));
258 } 240 }
259 if (config_node->r_function) { 241 if (config_node->r_function) {
260 return (sp_is_regexp_matching(config_node->r_function, "include") || 242 return (sp_is_regexp_matching(config_node->r_function, "include") ||
@@ -265,43 +247,67 @@ static bool check_is_builtin_name(
265 return false; 247 return false;
266} 248}
267 249
268bool should_disable(zend_execute_data* execute_data, const char* builtin_name, 250bool should_disable_ht(zend_execute_data* execute_data,
269 const char* builtin_param, const char* builtin_param_name) { 251 const char* builtin_name,
270 char current_file_hash[SHA256_SIZE * 2 + 1] = {0}; 252 const zend_string* builtin_param,
271 const sp_list_node* config = get_config_node(builtin_name); 253 const char* builtin_param_name,
272 char* complete_path_function = NULL; 254 const sp_list_node* config, const HashTable* ht) {
273 const char* current_filename = NULL; 255 char* complete_function_path = NULL;
274 unsigned int line = 0; 256 const sp_list_node* ht_entry = NULL;
275 char* filename = NULL; 257 bool ret = false;
258 zend_string* current_filename;
276 259
277 if (!execute_data) { 260 if (!execute_data) {
278 return false; 261 return false;
279 } 262 }
280 263
281 if (!config || !config->data) { 264 if (builtin_name) {
282 return false; 265 complete_function_path = estrdup(builtin_name);
266 } else {
267 complete_function_path = get_complete_function_path(execute_data);
268 if (!complete_function_path) {
269 return false;
270 }
283 } 271 }
284 272
285 if (UNEXPECTED(builtin_name && !strcmp(builtin_name, "eval"))) { 273 if (UNEXPECTED(builtin_param && !strcmp(complete_function_path, "eval"))) {
286 current_filename = get_eval_filename(zend_get_executed_filename()); 274 current_filename = get_eval_filename(zend_get_executed_filename());
287 } else { 275 } else {
288 current_filename = zend_get_executed_filename(); 276 const char* tmp = zend_get_executed_filename();
277 current_filename = zend_string_init(tmp, strlen(tmp), 0);
289 } 278 }
290 279
291 complete_path_function = get_complete_function_path(execute_data); 280 ht_entry = zend_hash_str_find_ptr(ht, complete_function_path,
292 if (!complete_path_function) { 281 strlen(complete_function_path));
293 if (builtin_name) { 282
294 complete_path_function = estrdup(builtin_name); 283 if (ht_entry &&
295 } else { 284 should_disable(execute_data, complete_function_path, builtin_param,
296 return false; 285 builtin_param_name, ht_entry, current_filename)) {
297 } 286 ret = true;
287 } else if (config && config->data) {
288 ret = should_disable(execute_data, complete_function_path, builtin_param,
289 builtin_param_name, config, current_filename);
298 } 290 }
299 291
292 efree(complete_function_path);
293 efree(current_filename);
294 return ret;
295}
296
297bool should_disable(zend_execute_data* execute_data,
298 const char* complete_function_path,
299 const zend_string* builtin_param,
300 const char* builtin_param_name, const sp_list_node* config,
301 const zend_string* current_filename) {
302 char current_file_hash[SHA256_SIZE * 2 + 1] = {0};
303 unsigned int line = 0;
304 char* filename = NULL;
305
300 while (config) { 306 while (config) {
301 sp_disabled_function const* const config_node = 307 sp_disabled_function const* const config_node =
302 (sp_disabled_function*)(config->data); 308 (sp_disabled_function*)(config->data);
303 const char* arg_name = NULL; 309 const char* arg_name = NULL;
304 const char* arg_value_str = NULL; 310 const zend_string* arg_value_str = NULL;
305 311
306 /* The order matters, since when we have `config_node->functions_list`, 312 /* The order matters, since when we have `config_node->functions_list`,
307 we also do have `config_node->function` */ 313 we also do have `config_node->function` */
@@ -311,12 +317,13 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name,
311 goto next; 317 goto next;
312 } 318 }
313 } else if (config_node->function) { 319 } else if (config_node->function) {
314 if (0 != strcmp(config_node->function, complete_path_function)) { 320 if (0 !=
321 strcmp(ZSTR_VAL(config_node->function), complete_function_path)) {
315 goto next; 322 goto next;
316 } 323 }
317 } else if (config_node->r_function) { 324 } else if (config_node->r_function) {
318 if (false == sp_is_regexp_matching(config_node->r_function, 325 if (false == sp_is_regexp_matching(config_node->r_function,
319 complete_path_function)) { 326 complete_function_path)) {
320 goto next; 327 goto next;
321 } 328 }
322 } 329 }
@@ -350,9 +357,10 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name,
350 357
351 if (config_node->hash) { 358 if (config_node->hash) {
352 if ('\0' == current_file_hash[0]) { 359 if ('\0' == current_file_hash[0]) {
353 compute_hash(current_filename, current_file_hash); 360 compute_hash(ZSTR_VAL(current_filename), current_file_hash);
354 } 361 }
355 if (0 != strncmp(current_file_hash, config_node->hash, SHA256_SIZE)) { 362 if (0 != strncmp(current_file_hash, ZSTR_VAL(config_node->hash),
363 SHA256_SIZE)) {
356 goto next; 364 goto next;
357 } 365 }
358 } 366 }
@@ -360,25 +368,25 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name,
360 /* Check if we filter on parameter value*/ 368 /* Check if we filter on parameter value*/
361 if (config_node->param || config_node->r_param || 369 if (config_node->param || config_node->r_param ||
362 (config_node->pos != -1)) { 370 (config_node->pos != -1)) {
363 if (!builtin_name && execute_data->func->op_array.arg_info->is_variadic) { 371 if (!builtin_param &&
372 execute_data->func->op_array.arg_info->is_variadic) {
364 sp_log_err( 373 sp_log_err(
365 "disable_function", 374 "disable_function",
366 "Snuffleupagus doesn't support variadic functions yet, sorry. " 375 "Snuffleupagus doesn't support variadic functions yet, sorry. "
367 "Check https://github.com/nbs-system/snuffleupagus/issues/164 for " 376 "Check https://github.com/nbs-system/snuffleupagus/issues/164 for "
368 "details."); 377 "details.");
369 } else if (false == is_param_matching(execute_data, config_node, 378 } else if (false == is_param_matching(
370 builtin_name, builtin_param, 379 execute_data, config_node, builtin_param,
371 &arg_name, builtin_param_name, 380 &arg_name, builtin_param_name, &arg_value_str)) {
372 &arg_value_str)) {
373 goto next; 381 goto next;
374 } 382 }
375 } 383 }
376 384
377 if (config_node->value_r || config_node->value) { 385 if (config_node->r_value || config_node->value) {
378 if (check_is_builtin_name(config_node)) { 386 if (check_is_builtin_name(config_node)) {
379 if (false == is_param_matching(execute_data, config_node, builtin_name, 387 if (false == is_param_matching(execute_data, config_node, builtin_param,
380 builtin_param, &arg_name, 388 &arg_name, builtin_param_name,
381 builtin_param_name, &arg_value_str)) { 389 &arg_value_str)) {
382 goto next; 390 goto next;
383 } 391 }
384 } 392 }
@@ -390,63 +398,76 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name,
390 } 398 }
391 399
392 if (config_node->functions_list) { 400 if (config_node->functions_list) {
393 sp_log_disable(config_node->function, arg_name, arg_value_str, 401 sp_log_disable(ZSTR_VAL(config_node->function), arg_name, arg_value_str,
394 config_node, line, filename); 402 config_node, line, filename);
395 } else { 403 } else {
396 sp_log_disable(complete_path_function, arg_name, arg_value_str, 404 sp_log_disable(complete_function_path, arg_name, arg_value_str,
397 config_node, line, filename); 405 config_node, line, filename);
398 } 406 }
399 if (true == config_node->simulation) { 407 if (true == config_node->simulation) {
400 goto next; 408 goto next;
401 } else { // We've got a match, the function won't be executed 409 } else { // We've got a match, the function won't be executed
402 efree(complete_path_function);
403 return true; 410 return true;
404 } 411 }
405 next: 412 next:
406 config = config->next; 413 config = config->next;
407 } 414 }
408allow: 415allow:
409 efree(complete_path_function);
410 return false; 416 return false;
411} 417}
412 418
413bool should_drop_on_ret(zval* return_value, 419bool should_drop_on_ret_ht(zval* return_value,
414 const zend_execute_data* const execute_data) { 420 const zend_execute_data* const execute_data,
415 const sp_list_node* config = 421 const sp_list_node* config, const HashTable* ht) {
416 SNUFFLEUPAGUS_G(config).config_disabled_functions_ret->disabled_functions; 422 char* complete_function_path = get_complete_function_path(execute_data);
417 char* complete_path_function = get_complete_function_path(execute_data); 423 const sp_list_node* ht_entry = NULL;
418 const char* current_filename = zend_get_executed_filename(TSRMLS_C); 424 bool ret = false;
419 char current_file_hash[SHA256_SIZE * 2 + 1] = {0};
420 bool match_type = false, match_value = false;
421 425
422 if (!complete_path_function) { 426 if (!complete_function_path) {
423 return false; 427 return ret;
424 } 428 }
425 429
426 if (!config || !config->data) { 430 ht_entry = zend_hash_str_find_ptr(ht, complete_function_path,
427 return false; 431 strlen(complete_function_path));
432
433 if (ht_entry &&
434 should_drop_on_ret(return_value, ht_entry, complete_function_path)) {
435 ret = true;
436 } else if (config && config->data) {
437 ret = should_drop_on_ret(return_value, config, complete_function_path);
428 } 438 }
429 439
440 efree(complete_function_path);
441 return ret;
442}
443
444bool should_drop_on_ret(zval* return_value, const sp_list_node* config,
445 const char* complete_function_path) {
446 const char* current_filename = zend_get_executed_filename(TSRMLS_C);
447 char current_file_hash[SHA256_SIZE * 2 + 1] = {0};
448 bool match_type = false, match_value = false;
449
430 while (config) { 450 while (config) {
431 char* ret_value_str = NULL; 451 const zend_string* ret_value_str = NULL;
432 sp_disabled_function const* const config_node = 452 sp_disabled_function const* const config_node =
433 (sp_disabled_function*)(config->data); 453 (sp_disabled_function*)(config->data);
434 454
435 assert(config_node->function || config_node->r_function); 455 assert(config_node->function || config_node->r_function);
436 456
437 if (config_node->function) { 457 if (config_node->function) {
438 if (0 != strcmp(config_node->function, complete_path_function)) { 458 if (0 !=
459 strcmp(ZSTR_VAL(config_node->function), complete_function_path)) {
439 goto next; 460 goto next;
440 } 461 }
441 } else if (config_node->r_function) { 462 } else if (config_node->r_function) {
442 if (false == sp_is_regexp_matching(config_node->r_function, 463 if (false == sp_is_regexp_matching(config_node->r_function,
443 complete_path_function)) { 464 complete_function_path)) {
444 goto next; 465 goto next;
445 } 466 }
446 } 467 }
447 468
448 if (config_node->filename) { /* Check the current file name. */ 469 if (config_node->filename) { /* Check the current file name. */
449 if (0 != strcmp(current_filename, config_node->filename)) { 470 if (0 != strcmp(current_filename, ZSTR_VAL(config_node->filename))) {
450 goto next; 471 goto next;
451 } 472 }
452 } else if (config_node->r_filename) { 473 } else if (config_node->r_filename) {
@@ -460,12 +481,13 @@ bool should_drop_on_ret(zval* return_value,
460 if ('\0' == current_file_hash[0]) { 481 if ('\0' == current_file_hash[0]) {
461 compute_hash(current_filename, current_file_hash); 482 compute_hash(current_filename, current_file_hash);
462 } 483 }
463 if (0 != strncmp(current_file_hash, config_node->hash, SHA256_SIZE)) { 484 if (0 != strncmp(current_file_hash, ZSTR_VAL(config_node->hash),
485 SHA256_SIZE)) {
464 goto next; 486 goto next;
465 } 487 }
466 } 488 }
467 489
468 ret_value_str = sp_convert_to_string(return_value); 490 ret_value_str = sp_zval_to_zend_string(return_value);
469 491
470 match_type = (config_node->ret_type) && 492 match_type = (config_node->ret_type) &&
471 (config_node->ret_type == Z_TYPE_P(return_value)); 493 (config_node->ret_type == Z_TYPE_P(return_value));
@@ -475,22 +497,16 @@ bool should_drop_on_ret(zval* return_value,
475 497
476 if (true == match_type || true == match_value) { 498 if (true == match_type || true == match_value) {
477 if (true == config_node->allow) { 499 if (true == config_node->allow) {
478 efree(complete_path_function);
479 efree(ret_value_str);
480 return false; 500 return false;
481 } 501 }
482 sp_log_disable_ret(complete_path_function, ret_value_str, config_node); 502 sp_log_disable_ret(complete_function_path, ret_value_str, config_node);
483 if (false == config_node->simulation) { 503 if (false == config_node->simulation) {
484 efree(complete_path_function);
485 efree(ret_value_str);
486 return true; 504 return true;
487 } 505 }
488 } 506 }
489 next: 507 next:
490 efree(ret_value_str);
491 config = config->next; 508 config = config->next;
492 } 509 }
493 efree(complete_path_function);
494 return false; 510 return false;
495} 511}
496 512
@@ -498,7 +514,11 @@ ZEND_FUNCTION(check_disabled_function) {
498 void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); 514 void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS);
499 const char* current_function_name = get_active_function_name(TSRMLS_C); 515 const char* current_function_name = get_active_function_name(TSRMLS_C);
500 516
501 if (true == should_disable(execute_data, NULL, NULL, NULL)) { 517 if (true == should_disable_ht(
518 execute_data, NULL, NULL, NULL,
519 SNUFFLEUPAGUS_G(config)
520 .config_disabled_functions_reg->disabled_functions,
521 SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked)) {
502 sp_terminate(); 522 sp_terminate();
503 } 523 }
504 524
@@ -506,23 +526,29 @@ ZEND_FUNCTION(check_disabled_function) {
506 SNUFFLEUPAGUS_G(disabled_functions_hook), current_function_name, 526 SNUFFLEUPAGUS_G(disabled_functions_hook), current_function_name,
507 strlen(current_function_name)); 527 strlen(current_function_name));
508 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); 528 orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
509 if (true == should_drop_on_ret(return_value, execute_data)) { 529 if (true ==
530 should_drop_on_ret_ht(
531 return_value, execute_data,
532 SNUFFLEUPAGUS_G(config)
533 .config_disabled_functions_reg_ret->disabled_functions,
534 SNUFFLEUPAGUS_G(config).config_disabled_functions_ret_hooked)) {
510 sp_terminate(); 535 sp_terminate();
511 } 536 }
512} 537}
513 538
514static int hook_functions(const sp_list_node* config) { 539static int hook_functions_regexp(const sp_list_node* config) {
515 while (config && config->data) { 540 while (config && config->data) {
516 const char* function_name = ((sp_disabled_function*)config->data)->function; 541 const zend_string* function_name =
542 ((sp_disabled_function*)config->data)->function;
517 const sp_pcre* function_name_regexp = 543 const sp_pcre* function_name_regexp =
518 ((sp_disabled_function*)config->data)->r_function; 544 ((sp_disabled_function*)config->data)->r_function;
519 545
520 assert(function_name || function_name_regexp); 546 assert(function_name || function_name_regexp);
521 547
522 if (NULL != function_name) { // hook function by name 548 if (function_name) {
523 HOOK_FUNCTION(function_name, disabled_functions_hook, 549 HOOK_FUNCTION(ZSTR_VAL(function_name), disabled_functions_hook,
524 PHP_FN(check_disabled_function)); 550 PHP_FN(check_disabled_function));
525 } else if (NULL != function_name_regexp) { // hook function by regexp 551 } else {
526 HOOK_FUNCTION_BY_REGEXP(function_name_regexp, disabled_functions_hook, 552 HOOK_FUNCTION_BY_REGEXP(function_name_regexp, disabled_functions_hook,
527 PHP_FN(check_disabled_function)); 553 PHP_FN(check_disabled_function));
528 } 554 }
@@ -532,16 +558,36 @@ static int hook_functions(const sp_list_node* config) {
532 return SUCCESS; 558 return SUCCESS;
533} 559}
534 560
561static int hook_functions(HashTable* to_hook_ht, HashTable* hooked_ht) {
562 zend_string* key;
563 zval* value;
564
565 ZEND_HASH_FOREACH_STR_KEY_VAL(to_hook_ht, key, value) {
566 if (!HOOK_FUNCTION(ZSTR_VAL(key), disabled_functions_hook,
567 PHP_FN(check_disabled_function)) ||
568 check_is_builtin_name(((sp_list_node*)Z_PTR_P(value))->data)) {
569 zend_symtable_add_new(hooked_ht, key, value);
570 zend_hash_del(to_hook_ht, key);
571 }
572 }
573 ZEND_HASH_FOREACH_END();
574 return SUCCESS;
575}
576
535ZEND_FUNCTION(eval_blacklist_callback) { 577ZEND_FUNCTION(eval_blacklist_callback) {
536 void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); 578 void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS);
537 const char* current_function_name = get_active_function_name(TSRMLS_C); 579 const char* current_function_name = get_active_function_name(TSRMLS_C);
580 zend_string* tmp =
581 zend_string_init(current_function_name, strlen(current_function_name), 0);
538 582
539 if (true == check_is_in_eval_whitelist(current_function_name)) { 583 if (true == check_is_in_eval_whitelist(tmp)) {
584 zend_string_release(tmp);
540 goto whitelisted; 585 goto whitelisted;
541 } 586 }
587 zend_string_release(tmp);
542 588
543 if (SNUFFLEUPAGUS_G(in_eval) > 0) { 589 if (SNUFFLEUPAGUS_G(in_eval) > 0) {
544 char* filename = get_eval_filename(zend_get_executed_filename()); 590 zend_string* filename = get_eval_filename(zend_get_executed_filename());
545 const int line_number = zend_get_executed_lineno(TSRMLS_C); 591 const int line_number = zend_get_executed_lineno(TSRMLS_C);
546 if (SNUFFLEUPAGUS_G(config).config_eval->dump) { 592 if (SNUFFLEUPAGUS_G(config).config_eval->dump) {
547 sp_log_request( 593 sp_log_request(
@@ -549,14 +595,14 @@ ZEND_FUNCTION(eval_blacklist_callback) {
549 SNUFFLEUPAGUS_G(config).config_eval->textual_representation, 595 SNUFFLEUPAGUS_G(config).config_eval->textual_representation,
550 SP_TOKEN_EVAL_BLACKLIST); 596 SP_TOKEN_EVAL_BLACKLIST);
551 } 597 }
552 if (1 == SNUFFLEUPAGUS_G(config).config_eval->simulation) { 598 if (SNUFFLEUPAGUS_G(config).config_eval->simulation) {
553 sp_log_msg("eval", SP_LOG_SIMULATION, 599 sp_log_msg("eval", SP_LOG_SIMULATION,
554 "A call to %s was tried in eval, in %s:%d, logging it.", 600 "A call to %s was tried in eval, in %s:%d, logging it.",
555 current_function_name, filename, line_number); 601 current_function_name, ZSTR_VAL(filename), line_number);
556 } else { 602 } else {
557 sp_log_msg("eval", SP_LOG_DROP, 603 sp_log_msg("eval", SP_LOG_DROP,
558 "A call to %s was tried in eval, in %s:%d, dropping it.", 604 "A call to %s was tried in eval, in %s:%d, dropping it.",
559 current_function_name, filename, line_number); 605 current_function_name, ZSTR_VAL(filename), line_number);
560 sp_terminate(); 606 sp_terminate();
561 } 607 }
562 efree(filename); 608 efree(filename);
@@ -574,21 +620,31 @@ int hook_disabled_functions(void) {
574 620
575 int ret = SUCCESS; 621 int ret = SUCCESS;
576 622
623 ret |=
624 hook_functions(SNUFFLEUPAGUS_G(config).config_disabled_functions,
625 SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked);
626
577 ret |= hook_functions( 627 ret |= hook_functions(
578 SNUFFLEUPAGUS_G(config).config_disabled_functions->disabled_functions); 628 SNUFFLEUPAGUS_G(config).config_disabled_functions_ret,
579 ret |= hook_functions(SNUFFLEUPAGUS_G(config) 629 SNUFFLEUPAGUS_G(config).config_disabled_functions_ret_hooked);
580 .config_disabled_functions_ret->disabled_functions); 630
631 ret |= hook_functions_regexp(
632 SNUFFLEUPAGUS_G(config)
633 .config_disabled_functions_reg->disabled_functions);
634
635 ret |= hook_functions_regexp(
636 SNUFFLEUPAGUS_G(config)
637 .config_disabled_functions_reg_ret->disabled_functions);
581 638
582 if (NULL != SNUFFLEUPAGUS_G(config).config_eval->blacklist) { 639 if (NULL != SNUFFLEUPAGUS_G(config).config_eval->blacklist) {
583 sp_list_node* it = SNUFFLEUPAGUS_G(config).config_eval->blacklist; 640 sp_list_node* it = SNUFFLEUPAGUS_G(config).config_eval->blacklist;
584 641
585 while (it) { 642 while (it) {
586 hook_function((char*)it->data, 643 hook_function(ZSTR_VAL((zend_string*)it->data),
587 SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook), 644 SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook),
588 PHP_FN(eval_blacklist_callback)); 645 PHP_FN(eval_blacklist_callback));
589 it = it->next; 646 it = it->next;
590 } 647 }
591 } 648 }
592
593 return ret; 649 return ret;
594} 650}