summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/snuffleupagus.c52
-rw-r--r--src/sp_config_utils.c5
-rw-r--r--src/sp_upload_validation.c5
-rw-r--r--src/sp_utils.c7
-rw-r--r--src/tests/disable_function/disabled_function_echo_2.phpt6
5 files changed, 62 insertions, 13 deletions
diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c
index 4d5fa09..6b0a327 100644
--- a/src/snuffleupagus.c
+++ b/src/snuffleupagus.c
@@ -25,6 +25,39 @@ static inline void sp_op_array_handler(zend_op_array *const op) {
25 op->fn_flags |= ZEND_ACC_STRICT_TYPES; 25 op->fn_flags |= ZEND_ACC_STRICT_TYPES;
26 } 26 }
27 } 27 }
28#if PHP_VERSION_ID >= 80500
29 /* Prevent opcache from inlining user functions that have return-value
30 * monitoring rules, otherwise zend_execute_ex is never called and the
31 * hook never fires. ZEND_ACC_HAS_TYPE_HINTS is checked by
32 * zend_try_inline_call() and blocks inlining. For functions without
33 * actual type hints the only runtime effect is that ZEND_RECV opcodes
34 * are executed instead of skipped; for 0-arg functions (the common
35 * inlineable case) there are no RECV opcodes so the impact is zero. */
36 if (op->function_name && ZEND_USER_CODE(op->type) &&
37 ((SPCFG(disabled_functions_ret) && zend_hash_num_elements(SPCFG(disabled_functions_ret))) ||
38 SPCFG(disabled_functions_reg_ret).disabled_functions)) {
39 char *fname = NULL;
40 if (op->scope) {
41 const size_t len = ZSTR_LEN(op->scope->name) + 2 + ZSTR_LEN(op->function_name) + 1;
42 fname = emalloc(len);
43 snprintf(fname, len, "%s::%s", ZSTR_VAL(op->scope->name), ZSTR_VAL(op->function_name));
44 } else {
45 fname = estrdup(ZSTR_VAL(op->function_name));
46 }
47 bool has_ret_rule = false;
48 if (SPCFG(disabled_functions_ret) &&
49 zend_hash_str_find_ptr(SPCFG(disabled_functions_ret), fname, strlen(fname))) {
50 has_ret_rule = true;
51 }
52 if (!has_ret_rule && SPCFG(disabled_functions_reg_ret).disabled_functions) {
53 has_ret_rule = true; /* regex rules require runtime matching */
54 }
55 if (has_ret_rule) {
56 op->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS;
57 }
58 efree(fname);
59 }
60#endif
28} 61}
29 62
30ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) 63ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus)
@@ -246,7 +279,7 @@ PHP_MINFO_FUNCTION(snuffleupagus) {
246 php_info_print_table_start(); 279 php_info_print_table_start();
247 php_info_print_table_row( 280 php_info_print_table_row(
248 2, "snuffleupagus support", 281 2, "snuffleupagus support",
249 SPG(is_config_valid) ? "enabled" : "disabled"); 282 SPG(is_config_valid) == SP_CONFIG_VALID ? "enabled" : "disabled");
250 php_info_print_table_row(2, "Version", PHP_SNUFFLEUPAGUS_VERSION); 283 php_info_print_table_row(2, "Version", PHP_SNUFFLEUPAGUS_VERSION);
251 php_info_print_table_row(2, "Valid config", valid_config); 284 php_info_print_table_row(2, "Valid config", valid_config);
252 php_info_print_table_end(); 285 php_info_print_table_end();
@@ -582,12 +615,25 @@ static PHP_INI_MH(OnUpdateConfiguration) {
582 615
583 sp_hook_register_server_variables(); 616 sp_hook_register_server_variables();
584 617
585 if (SPCFG(global_strict).enable) { 618 bool need_op_array_handler = SPCFG(global_strict).enable;
619
620#if PHP_VERSION_ID >= 80500
621 /* Register as zend extension to get op_array_handler callbacks, which we
622 * use to prevent opcache from inlining monitored functions. */
623 if (SPCFG(disabled_functions_ret) && zend_hash_num_elements(SPCFG(disabled_functions_ret))) {
624 need_op_array_handler = true;
625 }
626 if (SPCFG(disabled_functions_reg_ret).disabled_functions) {
627 need_op_array_handler = true;
628 }
629#endif
630
631 if (need_op_array_handler) {
586 if (!zend_get_extension(PHP_SNUFFLEUPAGUS_EXTNAME)) { 632 if (!zend_get_extension(PHP_SNUFFLEUPAGUS_EXTNAME)) {
587 zend_extension_entry.startup = NULL; 633 zend_extension_entry.startup = NULL;
588 zend_register_extension(&zend_extension_entry, NULL); 634 zend_register_extension(&zend_extension_entry, NULL);
589 } 635 }
590 // This is needed to implement the global strict mode 636 // This is needed to enable the op_array_handler callback
591 CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY; 637 CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
592 } 638 }
593 639
diff --git a/src/sp_config_utils.c b/src/sp_config_utils.c
index 84b1f30..415e434 100644
--- a/src/sp_config_utils.c
+++ b/src/sp_config_utils.c
@@ -11,8 +11,9 @@ sp_list_node *parse_functions_list(const char *const value) {
11 sp_list_node *list = NULL; 11 sp_list_node *list = NULL;
12 char *tmp = strdup(value); 12 char *tmp = strdup(value);
13 const char *function_name; 13 const char *function_name;
14 char *next_token = tmp; 14 char *next_token = NULL;
15 while ((function_name = strtok_r(NULL, sep, &next_token))) { 15 for (function_name = strtok_r(tmp, sep, &next_token); function_name;
16 function_name = strtok_r(NULL, sep, &next_token)) {
16 list = sp_list_prepend(list, strdup(function_name)); 17 list = sp_list_prepend(list, strdup(function_name));
17 } 18 }
18 free(tmp); 19 free(tmp);
diff --git a/src/sp_upload_validation.c b/src/sp_upload_validation.c
index e24149e..b5babed 100644
--- a/src/sp_upload_validation.c
+++ b/src/sp_upload_validation.c
@@ -64,8 +64,7 @@ static int sp_rfc1867_callback(unsigned int event, void *event_data, void **extr
64 if ((pid = fork()) == 0) { 64 if ((pid = fork()) == 0) {
65 if (execve(ZSTR_VAL(config_upload->script), cmd, env) == -1) { 65 if (execve(ZSTR_VAL(config_upload->script), cmd, env) == -1) {
66 sp_log_warn("upload_validation", "Could not call '%s' : %s", ZSTR_VAL(config_upload->script), strerror(errno)); 66 sp_log_warn("upload_validation", "Could not call '%s' : %s", ZSTR_VAL(config_upload->script), strerror(errno));
67 EFREE_3(env); 67 _exit(1);
68 exit(1);
69 } 68 }
70 } else if (pid == -1) { 69 } else if (pid == -1) {
71 // LCOV_EXCL_START 70 // LCOV_EXCL_START
@@ -77,7 +76,7 @@ static int sp_rfc1867_callback(unsigned int event, void *event_data, void **extr
77 76
78 EFREE_3(env); 77 EFREE_3(env);
79 int waitstatus; 78 int waitstatus;
80 wait(&waitstatus); 79 waitpid(pid, &waitstatus, 0);
81 if (WEXITSTATUS(waitstatus) != 0) { // Nope 80 if (WEXITSTATUS(waitstatus) != 0) { // Nope
82 char *uri = getenv("REQUEST_URI"); 81 char *uri = getenv("REQUEST_URI");
83 int sim = config_upload->simulation; 82 int sim = config_upload->simulation;
diff --git a/src/sp_utils.c b/src/sp_utils.c
index e6efcc6..10beb8b 100644
--- a/src/sp_utils.c
+++ b/src/sp_utils.c
@@ -393,11 +393,12 @@ bool sp_match_array_key(const zval* zv, const zend_string* to_match, const sp_re
393 char* idx_str = NULL; 393 char* idx_str = NULL;
394 spprintf(&idx_str, 0, ZEND_ULONG_FMT, idx); 394 spprintf(&idx_str, 0, ZEND_ULONG_FMT, idx);
395 zend_string* tmp = zend_string_init(idx_str, strlen(idx_str), 0); 395 zend_string* tmp = zend_string_init(idx_str, strlen(idx_str), 0);
396 if (sp_match_value(tmp, to_match, rx)) { 396 bool match = sp_match_value(tmp, to_match, rx);
397 efree(idx_str); 397 zend_string_release(tmp);
398 efree(idx_str);
399 if (match) {
398 return true; 400 return true;
399 } 401 }
400 efree(idx_str);
401 } 402 }
402 } 403 }
403 ZEND_HASH_FOREACH_END(); 404 ZEND_HASH_FOREACH_END();
diff --git a/src/tests/disable_function/disabled_function_echo_2.phpt b/src/tests/disable_function/disabled_function_echo_2.phpt
index c1d9817..ce3488e 100644
--- a/src/tests/disable_function/disabled_function_echo_2.phpt
+++ b/src/tests/disable_function/disabled_function_echo_2.phpt
@@ -4,11 +4,13 @@ Echo hooking
4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?> 4<?php if (!extension_loaded("snuffleupagus")) print "skip"; ?>
5--INI-- 5--INI--
6sp.configuration_file={PWD}/config/disabled_function_echo.ini 6sp.configuration_file={PWD}/config/disabled_function_echo.ini
7opcache.optimization_level=0
7--FILE-- 8--FILE--
8<?php 9<?php
9echo "qwe"; 10echo "qwe";
10echo "1", "oops"; 11echo "1";
12echo "oops";
11?> 13?>
12--EXPECTF-- 14--EXPECTF--
13qwe1 15qwe1
14Fatal error: [snuffleupagus][0.0.0.0][disabled_function][drop] Aborted execution on call of the function 'echo' in %a/disabled_function_echo_2.php on line 3 16Fatal error: [snuffleupagus][0.0.0.0][disabled_function][drop] Aborted execution on call of the function 'echo' in %a/disabled_function_echo_2.php on line 4