From b1f755665993b7b98806b9e36de935b212e9765e Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sun, 17 Apr 2022 17:18:09 +0200 Subject: Fix dom-related test on Debian 11 on PHP7.4 --- src/tests/xxe/disable_xxe_dom_disabled.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/tests') diff --git a/src/tests/xxe/disable_xxe_dom_disabled.phpt b/src/tests/xxe/disable_xxe_dom_disabled.phpt index 107171c..4a888ed 100644 --- a/src/tests/xxe/disable_xxe_dom_disabled.phpt +++ b/src/tests/xxe/disable_xxe_dom_disabled.phpt @@ -1,7 +1,7 @@ --TEST-- Disable XXE (feature enabled) --SKIPIF-- - + = 80000) print "skip"; ?> --INI-- sp.configuration_file={PWD}/config/disable_xxe.ini -- cgit v1.3 From 5b25788a81bf7ad233d99cf3f5e9ce3dcc5e8602 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Mon, 2 May 2022 22:36:53 +0200 Subject: Add more tests for php8 --- .../deny_writable_execution_simulation.phpt | 1 - .../config_disabled_functions_name_type_php8.ini | 1 + ...led_functions_param_str_representation_php8.ini | 1 + .../disabled_functions_name_type_php8.phpt | 16 ++++++++++++++ ...ed_functions_param_str_representation_php8.phpt | 25 ++++++++++++++++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/tests/disable_function/config/config_disabled_functions_name_type_php8.ini create mode 100644 src/tests/disable_function/config/config_disabled_functions_param_str_representation_php8.ini create mode 100644 src/tests/disable_function/disabled_functions_name_type_php8.phpt create mode 100644 src/tests/disable_function/disabled_functions_param_str_representation_php8.phpt (limited to 'src/tests') diff --git a/src/tests/deny_writable/deny_writable_execution_simulation.phpt b/src/tests/deny_writable/deny_writable_execution_simulation.phpt index 1118dc0..e3460e4 100644 --- a/src/tests/deny_writable/deny_writable_execution_simulation.phpt +++ b/src/tests/deny_writable/deny_writable_execution_simulation.phpt @@ -1,7 +1,6 @@ --TEST-- Readonly execution attempt (simulation mode) --SKIPIF-- -= 80000) print "skip"; ?> + +--INI-- +sp.configuration_file={PWD}/config/config_disabled_functions_name_type_php8.ini +--FILE-- + +--EXPECTF-- +0 + +Fatal error: [snuffleupagus][0.0.0.0][disabled_function][drop] Aborted execution on call of the function 'strcmp', because its argument '$string1' content (?) matched a rule in %s/disabled_functions_name_type_php8.php on line 3 diff --git a/src/tests/disable_function/disabled_functions_param_str_representation_php8.phpt b/src/tests/disable_function/disabled_functions_param_str_representation_php8.phpt new file mode 100644 index 0000000..c06e612 --- /dev/null +++ b/src/tests/disable_function/disabled_functions_param_str_representation_php8.phpt @@ -0,0 +1,25 @@ +--TEST-- +Disable functions - casting various types to string internally in php8 +--SKIPIF-- + +--INI-- +sp.configuration_file={PWD}/config/config_disabled_functions_param_str_representation_php8.ini +--FILE-- + +--EXPECTF-- +true +false +NULL +1 +1.0 +123 -- cgit v1.3 From bee9da3cb2b47d7121ac3fe9cc945716aaaa5d21 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Mon, 16 May 2022 19:34:37 +0200 Subject: Don't run disabled_functions_param_str_representation_php8 on php7 --- .../disabled_functions_param_str_representation_php8.phpt | 1 + 1 file changed, 1 insertion(+) (limited to 'src/tests') diff --git a/src/tests/disable_function/disabled_functions_param_str_representation_php8.phpt b/src/tests/disable_function/disabled_functions_param_str_representation_php8.phpt index c06e612..aa5782b 100644 --- a/src/tests/disable_function/disabled_functions_param_str_representation_php8.phpt +++ b/src/tests/disable_function/disabled_functions_param_str_representation_php8.phpt @@ -2,6 +2,7 @@ Disable functions - casting various types to string internally in php8 --SKIPIF-- + --INI-- sp.configuration_file={PWD}/config/config_disabled_functions_param_str_representation_php8.ini --FILE-- -- cgit v1.3 From aef97b6b5cb130984ead1a0c3fbc3cdc2037320e Mon Sep 17 00:00:00 2001 From: jvoisin Date: Mon, 13 Jun 2022 23:22:26 +0200 Subject: Fix the CI on PHP8.0 and PHP8.1 --- src/tests/ini/ini_min_policy_drop.phpt | 2 +- src/tests/ini/ini_minmax.phpt | 2 +- src/tests/ini/ini_null.phpt | 2 +- src/tests/ini/ini_regexp.phpt | 2 +- src/tests/ini/ini_regexp_drop.phpt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/tests') diff --git a/src/tests/ini/ini_min_policy_drop.phpt b/src/tests/ini/ini_min_policy_drop.phpt index ef40ebc..1ec9f9a 100644 --- a/src/tests/ini/ini_min_policy_drop.phpt +++ b/src/tests/ini/ini_min_policy_drop.phpt @@ -10,4 +10,4 @@ var_dump(ini_set("max_execution_time", "29") === false); var_dump(ini_get("max_execution_time")); ?> --EXPECTF-- -Fatal error: [snuffleupagus][0.0.0.0][ini_protection][drop] INI value out of range in %a/ini_min_policy_drop.php on line 2 +Fatal error: [snuffleupagus][0.0.0.0][ini_protection][drop] INI value out of range in %a/ini_min_policy_drop.php on line 2%A diff --git a/src/tests/ini/ini_minmax.phpt b/src/tests/ini/ini_minmax.phpt index 4cd6bc4..facb73e 100644 --- a/src/tests/ini/ini_minmax.phpt +++ b/src/tests/ini/ini_minmax.phpt @@ -31,4 +31,4 @@ string(3) "300" Warning: [snuffleupagus][0.0.0.0][ini_protection][log] INI value out of range in %a/ini_minmax.php on line 11 bool(true) -string(3) "300" \ No newline at end of file +string(3) "300"%A diff --git a/src/tests/ini/ini_null.phpt b/src/tests/ini/ini_null.phpt index 32a12c1..dfc2555 100644 --- a/src/tests/ini/ini_null.phpt +++ b/src/tests/ini/ini_null.phpt @@ -23,4 +23,4 @@ string(0) "" Warning: [snuffleupagus][0.0.0.0][ini_protection][log] new INI value must not be NULL or empty in %a/ini_null.php on line 8 bool(true) -string(3) "def" \ No newline at end of file +string(3) "def"%A diff --git a/src/tests/ini/ini_regexp.phpt b/src/tests/ini/ini_regexp.phpt index f6c5198..c7cab35 100644 --- a/src/tests/ini/ini_regexp.phpt +++ b/src/tests/ini/ini_regexp.phpt @@ -16,4 +16,4 @@ var_dump(ini_get("highlight.comment")); string(7) "#000aBc" Warning: [snuffleupagus][0.0.0.0][ini_protection][log] INI value does not match regex in %a/ini_regexp.php on line 5 -string(7) "#000aBc" +string(7) "#000aBc"%A diff --git a/src/tests/ini/ini_regexp_drop.phpt b/src/tests/ini/ini_regexp_drop.phpt index 9225470..432be8d 100644 --- a/src/tests/ini/ini_regexp_drop.phpt +++ b/src/tests/ini/ini_regexp_drop.phpt @@ -10,4 +10,4 @@ var_dump(ini_set("user_agent", "Foo") === false); var_dump(ini_get("user_agent")); ?> --EXPECTF-- -Fatal error: [snuffleupagus][0.0.0.0][ini_protection][drop] INI value does not match regex in %a/ini_regexp_drop.php on line 2 +Fatal error: [snuffleupagus][0.0.0.0][ini_protection][drop] INI value does not match regex in %a/ini_regexp_drop.php on line 2%A%A%A%A -- cgit v1.3 From a5f070cd7d982ae96ad72fb79420407574e7682a Mon Sep 17 00:00:00 2001 From: jvoisin Date: Mon, 27 Jun 2022 20:55:20 +0200 Subject: Dump the eval'ed code --- src/php_snuffleupagus.h | 7 +++++++ src/sp_execute.c | 2 ++ src/sp_utils.c | 9 +++++++++ src/tests/dump_request/dump_eval_blacklist.phpt | 2 ++ 4 files changed, 20 insertions(+) (limited to 'src/tests') diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index 97fa0e4..a4a0ed4 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -148,6 +148,13 @@ u_long execution_depth; HashTable *disabled_functions_hook; HashTable *sp_internal_functions_hook; HashTable *sp_eval_blacklist_functions_hook; + +#if PHP_VERSION_ID >= 80000 +zend_string* eval_source_string; +#else +zval* eval_source_string; +#endif + ZEND_END_MODULE_GLOBALS(snuffleupagus) ZEND_EXTERN_MODULE_GLOBALS(snuffleupagus) diff --git a/src/sp_execute.c b/src/sp_execute.c index b81f408..a8798e4 100644 --- a/src/sp_execute.c +++ b/src/sp_execute.c @@ -302,6 +302,8 @@ ZEND_API zend_op_array* sp_compile_string(zend_string* source_string, #else ZEND_API zend_op_array* sp_compile_string(zval* source_string, char* filename) { #endif + // TODO(jvoisin) handle recursive calls to `eval` + SPG(eval_source_string) = source_string; zend_op_array* opline = orig_zend_compile_string(source_string, filename); sp_sloppy_modify_opcode(opline); return opline; diff --git a/src/sp_utils.c b/src/sp_utils.c index df2f0d6..d7200b1 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c @@ -177,6 +177,15 @@ int sp_log_request(const zend_string* restrict folder, const zend_string* restri ZEND_HASH_FOREACH_END(); fputs("\n", file); } + + if (UNEXPECTED(0 != SPG(in_eval))) { +#if PHP_VERSION_ID >= 80000 + fprintf(file, "EVAL_CODE: %s\n", ZSTR_VAL(SPG(eval_source_string))); +#else + fprintf(file, "EVAL_CODE: %s\n", ZSTR_VAL(zval_get_string(SPG(eval_source_string)))); +#endif + } + fclose(file); return 0; diff --git a/src/tests/dump_request/dump_eval_blacklist.phpt b/src/tests/dump_request/dump_eval_blacklist.phpt index c9f48e4..a8c1618 100644 --- a/src/tests/dump_request/dump_eval_blacklist.phpt +++ b/src/tests/dump_request/dump_eval_blacklist.phpt @@ -38,6 +38,8 @@ if ($res[3] != "GET:get_a='data_get_a' get_b='data_get_b' \n") { echo "Invalid POST"; } elseif ($res[5] != "COOKIE:cookie_a='data_cookie_a&cookie_b=data_cookie_b' \n") { echo "Invalid COOKIE"; +} elseif ($res[6] != "EVAL_CODE: \$a = strtoupper(\"1234\");\n") { + echo "Invalid EVAL_CODE"; } ?> --EXPECTF-- -- cgit v1.3 From 423e133c569b7d749cba3e1b97e9e138e5f0f892 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Tue, 12 Jul 2022 20:57:19 +0200 Subject: Log `eval` content when matching on its parameter --- src/sp_execute.c | 8 +++++--- .../config/config_disabled_functions_eval_param.ini | 1 + .../disable_function/disabled_functions_eval_param.phpt | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 src/tests/disable_function/config/config_disabled_functions_eval_param.ini create mode 100644 src/tests/disable_function/disabled_functions_eval_param.phpt (limited to 'src/tests') diff --git a/src/sp_execute.c b/src/sp_execute.c index a8798e4..2b8bb2e 100644 --- a/src/sp_execute.c +++ b/src/sp_execute.c @@ -136,9 +136,11 @@ static inline void sp_execute_handler(INTERNAL_FUNCTION_PARAMETERS, bool interna if (UNEXPECTED(EX(func)->op_array.type == ZEND_EVAL_CODE)) { const sp_list_node *config = zend_hash_str_find_ptr(SPCFG(disabled_functions), ZEND_STRL("eval")); - zend_string *filename = get_eval_filename(zend_get_executed_filename()); - is_builtin_matching(filename, "eval", NULL, config, SPCFG(disabled_functions)); - zend_string_release(filename); +#if PHP_VERSION_ID >= 80000 + is_builtin_matching(SPG(eval_source_string), "eval", "code", config, SPCFG(disabled_functions)); +#else + is_builtin_matching(Z_STR_P(SPG(eval_source_string)), "eval", "code", config, SPCFG(disabled_functions)); +#endif SPG(in_eval)++; sp_orig_execute(execute_data); diff --git a/src/tests/disable_function/config/config_disabled_functions_eval_param.ini b/src/tests/disable_function/config/config_disabled_functions_eval_param.ini new file mode 100644 index 0000000..b43faf1 --- /dev/null +++ b/src/tests/disable_function/config/config_disabled_functions_eval_param.ini @@ -0,0 +1 @@ +sp.disable_function.function("eval").param("code").drop(); diff --git a/src/tests/disable_function/disabled_functions_eval_param.phpt b/src/tests/disable_function/disabled_functions_eval_param.phpt new file mode 100644 index 0000000..4f3f1ef --- /dev/null +++ b/src/tests/disable_function/disabled_functions_eval_param.phpt @@ -0,0 +1,14 @@ +--TEST-- +Disable functions - eval, on matching parameter +--SKIPIF-- + +--INI-- +sp.configuration_file={PWD}/config/config_disabled_functions_eval_param.ini +--FILE-- + +--EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][disabled_function][drop] Aborted execution on call of the function 'eval', because its argument 'code' content ($var = 1337 + 1337;) matched a rule in %s/tests/disable_function/disabled_functions_eval_param.php(3) : eval()'d code on line 1 -- cgit v1.3 From 077e96b6319aaf26414d1d0eeb30eb4f144f0019 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Tue, 19 Apr 2022 12:43:18 +0200 Subject: allow file:// prefix in include() wich readonly_exec mode --- src/sp_execute.c | 13 +++++++++---- src/tests/deny_writable/deny_writable_execution.phpt | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'src/tests') diff --git a/src/sp_execute.c b/src/sp_execute.c index 2b8bb2e..cc401aa 100644 --- a/src/sp_execute.c +++ b/src/sp_execute.c @@ -17,9 +17,9 @@ ZEND_COLD static inline void terminate_if_writable(const char *filename) { sp_log_request(config_ro_exec->dump, config_ro_exec->textual_representation); } if (true == config_ro_exec->simulation) { - sp_log_simulation("readonly_exec", "Attempted execution of a writable file (%s).", filename); + sp_log_simulation("readonly_exec", "Attempted execution of a writable file (%s)", filename); } else { - sp_log_drop("readonly_exec", "Attempted execution of a writable file (%s).", filename); + sp_log_drop("readonly_exec", "Attempted execution of a writable file (%s)", filename); } } else { if (EACCES != errno) { @@ -226,13 +226,18 @@ static inline void sp_stream_open_checks(zend_string *zend_filename, zend_file_h return; } - // zend_string *zend_filename = zend_string_init(filename, strlen(filename), 0); const HashTable *disabled_functions_hooked = SPCFG(disabled_functions_hooked); switch (data->opline->opcode) { case ZEND_INCLUDE_OR_EVAL: if (SPCFG(readonly_exec).enable) { - terminate_if_writable(ZSTR_VAL(zend_filename)); + char *fn = ZSTR_VAL(zend_filename); + if (ZSTR_LEN(zend_filename) >= strlen("file://") && memcmp(fn, "file://", strlen("file://")) == 0) { + fn += strlen("file://"); + } else if (!php_memnstr(ZSTR_VAL(zend_filename), "://", strlen("://"), ZSTR_VAL(zend_filename) + ZSTR_LEN(zend_filename))) { + // ignore stream wrappers other than file:// for now + terminate_if_writable(fn); + } } switch (data->opline->extended_value) { case ZEND_INCLUDE: diff --git a/src/tests/deny_writable/deny_writable_execution.phpt b/src/tests/deny_writable/deny_writable_execution.phpt index e65dc32..a629479 100644 --- a/src/tests/deny_writable/deny_writable_execution.phpt +++ b/src/tests/deny_writable/deny_writable_execution.phpt @@ -40,4 +40,4 @@ unlink("$dir/non_writable_file.txt"); unlink("$dir/writable_file.txt"); ?> --EXPECTF-- -Fatal error: [snuffleupagus][0.0.0.0][readonly_exec][drop] Attempted execution of a writable file (%a/deny_writable_execution.php). in %a/deny_writable_execution.php on line 2 +Fatal error: [snuffleupagus][0.0.0.0][readonly_exec][drop] Attempted execution of a writable file (%a/deny_writable_execution.php) in %a/deny_writable_execution.php on line 2 -- cgit v1.3 From cd9031935ef2306f7ba2097856b20bf116f341ee Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Tue, 19 Apr 2022 19:01:52 +0200 Subject: extended checks for readonly_exec, enabled by default introduced config options: readonly_exec.extended_checks() or xchecks() readonly_exec.no_extended_checks() or noxchecks() --- src/snuffleupagus.c | 2 + src/sp_config.h | 1 + src/sp_config_keywords.c | 7 +- src/sp_execute.c | 77 ++++++++++++++++++---- .../deny_writable_execution_simulation.phpt | 10 ++- 5 files changed, 80 insertions(+), 17 deletions(-) (limited to 'src/tests') diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 5bcd57c..448fd76 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -340,6 +340,7 @@ static void dump_config() { add_assoc_bool(&arr, "readonly_exec.enable", SPCFG(readonly_exec).enable); add_assoc_bool(&arr, "readonly_exec.sim", SPCFG(readonly_exec).simulation); ADD_ASSOC_ZSTR(&arr, SP_TOKEN_READONLY_EXEC "." SP_TOKEN_DUMP, SPCFG(readonly_exec).dump); + add_assoc_bool(&arr, "readonly_exec.extended_checks", SPCFG(readonly_exec).extended_checks); add_assoc_bool(&arr, "global_strict.enable", SPCFG(global_strict).enable); @@ -494,6 +495,7 @@ static PHP_INI_MH(OnUpdateConfiguration) { // set some defaults SPCFG(show_old_php_warning) = true; + SPCFG(readonly_exec).extended_checks = true; char *str = new_value->val; diff --git a/src/sp_config.h b/src/sp_config.h index 3d92f2f..ec73310 100644 --- a/src/sp_config.h +++ b/src/sp_config.h @@ -35,6 +35,7 @@ typedef struct { typedef struct { bool enable; bool simulation; + bool extended_checks; zend_string *dump; zend_string *textual_representation; } sp_config_readonly_exec; diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index f7be731..e0e5166 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -96,7 +96,7 @@ SP_PARSE_FN(parse_unserialize) { } SP_PARSE_FN(parse_readonly_exec) { - bool enable = false, disable = false; + bool enable = false, disable = false, xchecks = false, no_xchecks = false; sp_config_readonly_exec *cfg = (sp_config_readonly_exec*)retval; sp_config_keyword config_keywords[] = { @@ -105,6 +105,10 @@ SP_PARSE_FN(parse_readonly_exec) { {parse_empty, SP_TOKEN_SIMULATION, &(cfg->simulation)}, {parse_empty, SP_TOKEN_SIM, &(cfg->simulation)}, {parse_str, SP_TOKEN_DUMP, &(cfg->dump)}, + {parse_empty, "extended_checks", &(xchecks)}, + {parse_empty, "xchecks", &(xchecks)}, + {parse_empty, "no_extended_checks", &(no_xchecks)}, + {parse_empty, "noxchecks", &(no_xchecks)}, {0, 0, 0}}; SP_PROCESS_CONFIG_KEYWORDS_ERR(); @@ -112,6 +116,7 @@ SP_PARSE_FN(parse_readonly_exec) { cfg->textual_representation = sp_get_textual_representation(parsed_rule); SP_SET_ENABLE_DISABLE(enable, disable, cfg->enable); + if (xchecks) { cfg->extended_checks = true; } else if (no_xchecks) { cfg->extended_checks = false; } return SP_PARSER_STOP; } diff --git a/src/sp_execute.c b/src/sp_execute.c index cc401aa..56d25c5 100644 --- a/src/sp_execute.c +++ b/src/sp_execute.c @@ -1,4 +1,5 @@ #include "php_snuffleupagus.h" +#include "ext/standard/php_string.h" static void (*orig_execute_ex)(zend_execute_data *execute_data) = NULL; static void (*orig_zend_execute_internal)(zend_execute_data *execute_data, @@ -12,22 +13,72 @@ static zend_result (*orig_zend_stream_open)(zend_file_handle *handle) = NULL; // FIXME handle symlink ZEND_COLD static inline void terminate_if_writable(const char *filename) { const sp_config_readonly_exec *config_ro_exec = &(SPCFG(readonly_exec)); + char *errmsg = "unknown access problem"; + + // check write access if (0 == access(filename, W_OK)) { - if (config_ro_exec->dump) { - sp_log_request(config_ro_exec->dump, config_ro_exec->textual_representation); - } - if (true == config_ro_exec->simulation) { - sp_log_simulation("readonly_exec", "Attempted execution of a writable file (%s)", filename); - } else { - sp_log_drop("readonly_exec", "Attempted execution of a writable file (%s)", filename); - } + errmsg = "Attempted execution of a writable file"; + goto violation; + } + if (errno != EACCES) { + goto err; + } + + // other checks are 'extended checks' that can be enabled/disabled via config + if (!config_ro_exec->extended_checks) { + return; + } + + // check effective uid + struct stat buf; + if (0 != stat(filename, &buf)) { + goto err; + } + if (buf.st_uid == geteuid()) { + errmsg = "Attempted execution of file owned by process"; + goto violation; + } + + // check write access on directory + char *dirname = estrndup(filename, strlen(filename)); + php_dirname(dirname, strlen(dirname)); + if (0 == access(dirname, W_OK)) { + errmsg = "Attempted execution of file in writable directory"; + efree(dirname); + goto violation; + } + if (errno != EACCES) { + efree(dirname); + goto err; + } + + // check effecite uid of directory + if (0 != stat(dirname, &buf)) { + efree(dirname); + goto err; + } + efree(dirname); + if (buf.st_uid == geteuid()) { + errmsg = "Attempted execution of file in directory owned by process"; + goto violation; + } + + // we would actually need to check all parent directories as well, but that task is left for other tools + return; + +violation: + if (config_ro_exec->dump) { + sp_log_request(config_ro_exec->dump, config_ro_exec->textual_representation); + } + if (config_ro_exec->simulation) { + sp_log_simulation("readonly_exec", "%s (%s)", errmsg, filename); } else { - if (EACCES != errno) { - // LCOV_EXCL_START - sp_log_err("Writable execution", "Error while accessing %s: %s", filename, strerror(errno)); - // LCOV_EXCL_STOP - } + sp_log_drop("readonly_exec", "%s (%s)", errmsg, filename); } + return; + +err: + sp_log_err("readonly_exec", "Error while accessing %s: %s", filename, strerror(errno)); } inline static void is_builtin_matching( diff --git a/src/tests/deny_writable/deny_writable_execution_simulation.phpt b/src/tests/deny_writable/deny_writable_execution_simulation.phpt index e3460e4..abc276f 100644 --- a/src/tests/deny_writable/deny_writable_execution_simulation.phpt +++ b/src/tests/deny_writable/deny_writable_execution_simulation.phpt @@ -41,10 +41,14 @@ unlink("$dir/non_writable_file.txt"); unlink("$dir/writable_file.txt"); ?> --EXPECTF-- -Warning: [snuffleupagus][0.0.0.0][readonly_exec][simulation] Attempted execution of a writable file (%a/deny_writable_execution_simulation.php). in %a/deny_writable_execution_simulation.php on line 2 +Warning: [snuffleupagus][0.0.0.0][readonly_exec][simulation] Attempted execution of a writable file (%a/deny_writable_execution_simulation.php) in %a/deny_writable_execution_simulation.php on line 2 -Warning: [snuffleupagus][0.0.0.0][readonly_exec][simulation] Attempted execution of a writable file (%a/writable_file.txt). in %a/deny_writable_execution_simulation.php on line 12 +Warning: [snuffleupagus][0.0.0.0][readonly_exec][simulation] Attempted execution of a writable file (%a/writable_file.txt) in %a/deny_writable_execution_simulation.php on line 12 -Warning: [snuffleupagus][0.0.0.0][readonly_exec][simulation] Attempted execution of a writable file (%a/writable_file.txt). in %a/writable_file.txt on line 1 +Warning: [snuffleupagus][0.0.0.0][readonly_exec][simulation] Attempted execution of a writable file (%a/writable_file.txt) in %a/writable_file.txt on line 1 Code execution within a writable file. + +Warning: [snuffleupagus][0.0.0.0][readonly_exec][simulation] Attempted execution of file owned by process (%s/tests/deny_writable/non_writable_file.txt) in %s/tests/deny_writable/deny_writable_execution_simulation.php on line 13 + +Warning: [snuffleupagus][0.0.0.0][readonly_exec][simulation] Attempted execution of file owned by process (%s/tests/deny_writable/non_writable_file.txt) in %src/tests/deny_writable/non_writable_file.txt on line 1 Code execution within a non-writable file. -- cgit v1.3 From 08e87202676a4676e66a27625522374faa70704c Mon Sep 17 00:00:00 2001 From: jvoisin Date: Tue, 12 Jul 2022 22:52:13 +0200 Subject: Disable extended checks for readonly_exec by default --- src/snuffleupagus.c | 1 - src/tests/deny_writable/config/config_disable_writable_simulation.ini | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'src/tests') diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 448fd76..1f5b660 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -495,7 +495,6 @@ static PHP_INI_MH(OnUpdateConfiguration) { // set some defaults SPCFG(show_old_php_warning) = true; - SPCFG(readonly_exec).extended_checks = true; char *str = new_value->val; diff --git a/src/tests/deny_writable/config/config_disable_writable_simulation.ini b/src/tests/deny_writable/config/config_disable_writable_simulation.ini index 52a43ba..3aafe3f 100644 --- a/src/tests/deny_writable/config/config_disable_writable_simulation.ini +++ b/src/tests/deny_writable/config/config_disable_writable_simulation.ini @@ -1 +1 @@ - sp.readonly_exec.enable().simulation(); + sp.readonly_exec.enable().extended_checks().simulation(); -- cgit v1.3 From 8d6496efcab420267a228c35f9f627fec209d031 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Tue, 12 Jul 2022 23:03:46 +0200 Subject: Refactoring of the previous commit --- src/php_snuffleupagus.h | 1 + src/sp_execute.c | 20 +++++++------------- .../deny_writable_execution_simulation.phpt | 4 ++-- 3 files changed, 10 insertions(+), 15 deletions(-) (limited to 'src/tests') diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index 95caa65..3eeb9db 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -38,6 +38,7 @@ #include "ext/standard/head.h" #include "ext/standard/info.h" #include "ext/standard/url.h" +#include "ext/standard/php_string.h" #include "ext/standard/php_var.h" #include "ext/session/php_session.h" #include "php.h" diff --git a/src/sp_execute.c b/src/sp_execute.c index 56d25c5..65a32db 100644 --- a/src/sp_execute.c +++ b/src/sp_execute.c @@ -1,5 +1,4 @@ #include "php_snuffleupagus.h" -#include "ext/standard/php_string.h" static void (*orig_execute_ex)(zend_execute_data *execute_data) = NULL; static void (*orig_zend_execute_internal)(zend_execute_data *execute_data, @@ -11,11 +10,10 @@ static zend_result (*orig_zend_stream_open)(zend_file_handle *handle) = NULL; #endif // FIXME handle symlink -ZEND_COLD static inline void terminate_if_writable(const char *filename) { - const sp_config_readonly_exec *config_ro_exec = &(SPCFG(readonly_exec)); - char *errmsg = "unknown access problem"; +ZEND_COLD static inline void terminate_if_writable(char const* const filename) { + sp_config_readonly_exec const* const config_ro_exec = &(SPCFG(readonly_exec)); + char const *errmsg = "unknown access problem"; - // check write access if (0 == access(filename, W_OK)) { errmsg = "Attempted execution of a writable file"; goto violation; @@ -29,21 +27,19 @@ ZEND_COLD static inline void terminate_if_writable(const char *filename) { return; } - // check effective uid struct stat buf; if (0 != stat(filename, &buf)) { goto err; } if (buf.st_uid == geteuid()) { - errmsg = "Attempted execution of file owned by process"; + errmsg = "Attempted execution of a file owned by the PHP process"; goto violation; } - // check write access on directory - char *dirname = estrndup(filename, strlen(filename)); + char *const dirname = estrndup(filename, strlen(filename)); php_dirname(dirname, strlen(dirname)); if (0 == access(dirname, W_OK)) { - errmsg = "Attempted execution of file in writable directory"; + errmsg = "Attempted execution of a file in a writable directory"; efree(dirname); goto violation; } @@ -52,18 +48,16 @@ ZEND_COLD static inline void terminate_if_writable(const char *filename) { goto err; } - // check effecite uid of directory if (0 != stat(dirname, &buf)) { efree(dirname); goto err; } efree(dirname); if (buf.st_uid == geteuid()) { - errmsg = "Attempted execution of file in directory owned by process"; + errmsg = "Attempted execution of a file in directory owned by the PHP process"; goto violation; } - // we would actually need to check all parent directories as well, but that task is left for other tools return; violation: diff --git a/src/tests/deny_writable/deny_writable_execution_simulation.phpt b/src/tests/deny_writable/deny_writable_execution_simulation.phpt index abc276f..d4e4801 100644 --- a/src/tests/deny_writable/deny_writable_execution_simulation.phpt +++ b/src/tests/deny_writable/deny_writable_execution_simulation.phpt @@ -48,7 +48,7 @@ Warning: [snuffleupagus][0.0.0.0][readonly_exec][simulation] Attempted execution Warning: [snuffleupagus][0.0.0.0][readonly_exec][simulation] Attempted execution of a writable file (%a/writable_file.txt) in %a/writable_file.txt on line 1 Code execution within a writable file. -Warning: [snuffleupagus][0.0.0.0][readonly_exec][simulation] Attempted execution of file owned by process (%s/tests/deny_writable/non_writable_file.txt) in %s/tests/deny_writable/deny_writable_execution_simulation.php on line 13 +Warning: [snuffleupagus][0.0.0.0][readonly_exec][simulation] Attempted execution of a file owned by the PHP process (%s/tests/deny_writable/non_writable_file.txt) in %s/tests/deny_writable/deny_writable_execution_simulation.php on line 13 -Warning: [snuffleupagus][0.0.0.0][readonly_exec][simulation] Attempted execution of file owned by process (%s/tests/deny_writable/non_writable_file.txt) in %src/tests/deny_writable/non_writable_file.txt on line 1 +Warning: [snuffleupagus][0.0.0.0][readonly_exec][simulation] Attempted execution of a file owned by the PHP process (%s/tests/deny_writable/non_writable_file.txt) in %src/tests/deny_writable/non_writable_file.txt on line 1 Code execution within a non-writable file. -- cgit v1.3