From 3ab467100883adedab71a28e1699799e45ab0b2d Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Wed, 19 Jun 2019 11:04:17 +0200 Subject: fix snufflepagus_globals linking issues and one mac compatibility issue --- src/php_snuffleupagus.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/php_snuffleupagus.h') diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index c9313f8..43131fe 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -99,6 +99,7 @@ HashTable *sp_internal_functions_hook; HashTable *sp_eval_blacklist_functions_hook; ZEND_END_MODULE_GLOBALS(snuffleupagus) +ZEND_EXTERN_MODULE_GLOBALS(snuffleupagus) #define SNUFFLEUPAGUS_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(snuffleupagus, v) #if defined(ZTS) && defined(COMPILE_DL_SNUFFLEUPAGUS) -- cgit v1.3 From 8776410692bf336a104fa19442f0fb761ecf0b5d Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Mon, 15 Jun 2020 11:27:30 +0200 Subject: clobal config.h + better debug log --- src/php_snuffleupagus.h | 4 ++++ src/snuffleupagus.c | 4 ---- src/sp_utils.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/php_snuffleupagus.h') diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index 43131fe..dae2154 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -7,6 +7,10 @@ #define PHP_SNUFFLEUPAGUS_URL "https://github.com/nbs-system/snuffleupagus" #define PHP_SNUFFLEUPAGUS_COPYRIGHT "LGPLv2" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index ff2d2b6..d62069c 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -4,10 +4,6 @@ #include #endif -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "php_snuffleupagus.h" #ifndef ZEND_EXT_API diff --git a/src/sp_utils.h b/src/sp_utils.h index 200e82c..9df196c 100644 --- a/src/sp_utils.h +++ b/src/sp_utils.h @@ -37,7 +37,7 @@ #define sp_log_err(feature, ...) sp_log_msg(feature, SP_LOG_ERROR, __VA_ARGS__) #define sp_log_warn(feature, ...) sp_log_msg(feature, SP_LOG_WARN, __VA_ARGS__) #ifdef SP_DEBUG -#define sp_log_debug(...) sp_log_msg("DEBUG", SP_LOG_DEBUG, __VA_ARGS__) +#define sp_log_debug(fmt, ...) sp_log_msg("DEBUG", SP_LOG_DEBUG, "%s(): " fmt, __FUNCTION__, ##__VA_ARGS__) #else #define sp_log_debug(...) #endif -- cgit v1.3 From 2392c46836ceea520fa2a45369c8d638aadb943c Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Fri, 6 Aug 2021 20:23:52 +0200 Subject: implemented ini settings protection --- src/config.m4 | 1 + src/php_snuffleupagus.h | 1 + src/snuffleupagus.c | 46 ++++++++++++----- src/sp_config.c | 13 +++++ src/sp_config.h | 26 +++++++++- src/sp_config_keywords.c | 77 +++++++++++++++++++++++++++++ src/sp_config_keywords.h | 2 + src/sp_ini.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++ src/sp_ini.h | 2 + 9 files changed, 281 insertions(+), 13 deletions(-) create mode 100644 src/sp_ini.c create mode 100644 src/sp_ini.h (limited to 'src/php_snuffleupagus.h') diff --git a/src/config.m4 b/src/config.m4 index e4cc1f5..1410565 100644 --- a/src/config.m4 +++ b/src/config.m4 @@ -7,6 +7,7 @@ sources="$sources sp_disabled_functions.c sp_execute.c sp_upload_validation.c" sources="$sources sp_cookie_encryption.c sp_network_utils.c tweetnacl.c" sources="$sources sp_config_keywords.c sp_var_parser.c sp_var_value.c sp_tree.c" sources="$sources sp_pcre_compat.c sp_crypt.c sp_session.c sp_sloppy.c sp_wrapper.c" +sources="$sources sp_ini.c" PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support, [ --enable-snuffleupagus Enable snuffleupagus support]) diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index 5b2b414..be4d306 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -85,6 +85,7 @@ typedef void (*zif_handler)(INTERNAL_FUNCTION_PARAMETERS); #include "sp_session.h" #include "sp_sloppy.h" #include "sp_wrapper.h" +#include "sp_ini.h" extern zend_module_entry snuffleupagus_module_entry; #define phpext_snuffleupagus_ptr &snuffleupagus_module_entry diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 8c7ecbf..2ee94a1 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -81,18 +81,6 @@ static PHP_GINIT_FUNCTION(snuffleupagus) { snuffleupagus_globals->is_config_valid = SP_CONFIG_NONE; snuffleupagus_globals->in_eval = 0; -#define SP_INIT_HT(F) \ - snuffleupagus_globals->F = pemalloc(sizeof(*(snuffleupagus_globals->F)), 1); \ - zend_hash_init(snuffleupagus_globals->F, 10, NULL, NULL, 1); - SP_INIT_HT(disabled_functions_hook); - SP_INIT_HT(sp_internal_functions_hook); - SP_INIT_HT(sp_eval_blacklist_functions_hook); - SP_INIT_HT(config.config_disabled_functions); - SP_INIT_HT(config.config_disabled_functions_hooked); - SP_INIT_HT(config.config_disabled_functions_ret); - SP_INIT_HT(config.config_disabled_functions_ret_hooked); -#undef SP_INIT_HT - #define SP_INIT(F) \ snuffleupagus_globals->config.F = \ pecalloc(sizeof(*(snuffleupagus_globals->config.F)), 1, 1); @@ -109,10 +97,24 @@ static PHP_GINIT_FUNCTION(snuffleupagus) { SP_INIT(config_eval); SP_INIT(config_wrapper); SP_INIT(config_session); + SP_INIT(config_ini); SP_INIT(config_disabled_functions_reg); SP_INIT(config_disabled_functions_reg_ret); #undef SP_INIT +#define SP_INIT_HT(F) \ + snuffleupagus_globals->F = pemalloc(sizeof(*(snuffleupagus_globals->F)), 1); \ + zend_hash_init(snuffleupagus_globals->F, 10, NULL, NULL, 1); + SP_INIT_HT(disabled_functions_hook); + SP_INIT_HT(sp_internal_functions_hook); + SP_INIT_HT(sp_eval_blacklist_functions_hook); + SP_INIT_HT(config.config_disabled_functions); + SP_INIT_HT(config.config_disabled_functions_hooked); + SP_INIT_HT(config.config_disabled_functions_ret); + SP_INIT_HT(config.config_disabled_functions_ret_hooked); + SP_INIT_HT(config.config_ini->entries); +#undef SP_INIT_HT + #define SP_INIT_NULL(F) snuffleupagus_globals->config.F = NULL; SP_INIT_NULL(config_disabled_functions_reg->disabled_functions); SP_INIT_NULL(config_disabled_functions_reg_ret->disabled_functions); @@ -131,6 +133,11 @@ PHP_MINIT_FUNCTION(snuffleupagus) { } PHP_MSHUTDOWN_FUNCTION(snuffleupagus) { + sp_log_debug("(MSHUTDOWN)"); + unhook_functions(SNUFFLEUPAGUS_G(sp_internal_functions_hook)); + unhook_functions(SNUFFLEUPAGUS_G(disabled_functions_hook)); + unhook_functions(SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook)); + if (SNUFFLEUPAGUS_G(config).config_ini->enable) { sp_unhook_ini(); } UNREGISTER_INI_ENTRIES(); return SUCCESS; @@ -142,6 +149,12 @@ static inline void free_disabled_functions_hashtable(HashTable *const ht) { ZEND_HASH_FOREACH_END(); } +static inline void free_config_ini_entries(HashTable *const ht) { + void *ptr = NULL; + ZEND_HASH_FOREACH_PTR(ht, ptr) { sp_free_ini_entry(ptr); pefree(ptr, 1); } + ZEND_HASH_FOREACH_END(); +} + static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) { sp_log_debug("(GSHUTDOWN)"); #define FREE_HT(F) \ @@ -158,6 +171,9 @@ static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) { FREE_HT_LIST(config_disabled_functions_ret); FREE_HT_LIST(config_disabled_functions_ret_hooked); #undef FREE_HT_LIST + + free_config_ini_entries(snuffleupagus_globals->config.config_ini->entries); + FREE_HT(config.config_ini->entries); #undef FREE_HT #define FREE_LST_DISABLE(L) \ @@ -174,6 +190,7 @@ static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) { FREE_LST(config_wrapper->whitelist); #undef FREE_LST + #define FREE_CFG(C) pefree(snuffleupagus_globals->config.C, 1); #define FREE_CFG_ZSTR(C) sp_free_zstr(snuffleupagus_globals->config.C); FREE_CFG(config_random); @@ -194,6 +211,7 @@ static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) { FREE_CFG(config_eval); FREE_CFG(config_wrapper); FREE_CFG(config_session); + FREE_CFG(config_ini); FREE_CFG(config_disabled_functions_reg); FREE_CFG(config_disabled_functions_reg_ret); #undef FREE_CFG @@ -332,6 +350,10 @@ static PHP_INI_MH(OnUpdateConfiguration) { hook_execute(); hook_cookies(); + if (SNUFFLEUPAGUS_G(config).config_ini->enable) { + sp_hook_ini(); + } + if (true == SNUFFLEUPAGUS_G(config).config_global_strict->enable) { if (!zend_get_extension(PHP_SNUFFLEUPAGUS_EXTNAME)) { zend_extension_entry.startup = NULL; diff --git a/src/sp_config.c b/src/sp_config.c index db3f12d..667867b 100644 --- a/src/sp_config.c +++ b/src/sp_config.c @@ -23,6 +23,8 @@ static sp_config_tokens const sp_func[] = { {.func = parse_session, .token = SP_TOKEN_SESSION_ENCRYPTION}, {.func = parse_sloppy_comparison, .token = SP_TOKEN_SLOPPY_COMPARISON}, {.func = parse_wrapper_whitelist, .token = SP_TOKEN_ALLOW_WRAPPERS}, + {.func = parse_ini_protection, .token = ".ini_protection"}, + {.func = parse_ini_entry, .token = ".ini"}, {NULL, NULL}}; /* Top level keyword parsing */ @@ -281,3 +283,14 @@ void sp_free_zstr(void *data) { zend_string_release_ex((zend_string*)data, 1); } } + +void sp_free_ini_entry(void *data) { + sp_ini_entry *entry = data; + + sp_free_zstr(entry->key); + sp_free_zstr(entry->min); + sp_free_zstr(entry->max); + sp_pcre_free(entry->regexp); + sp_free_zstr(entry->msg); + sp_free_zstr(entry->set); +} \ No newline at end of file diff --git a/src/sp_config.h b/src/sp_config.h index f3b64a6..bd2530a 100644 --- a/src/sp_config.h +++ b/src/sp_config.h @@ -30,6 +30,8 @@ typedef enum { typedef enum { SP_ZEND = 0, SP_SYSLOG = 1 } sp_log_media; +typedef enum { SP_UNSET = 0, SP_READONLY = 1, SP_READWRITE = -1 } sp_ini_permission; + typedef struct { int ip_version; union { @@ -162,6 +164,26 @@ typedef struct { bool enable; } sp_config_upload_validation; +typedef struct { + zend_string *key; + sp_ini_permission access; + zend_string *min; + zend_string *max; + sp_pcre *regexp; + bool simulation; + zend_string *msg; + zend_string *set; + PHP_INI_MH((*orig_onmodify)); +} sp_ini_entry; + +typedef struct { + bool enable; + bool simulation; + // sp_ini_permission access_policy; + bool policy_readonly; + HashTable *entries; // ht of sp_ini_entry +} sp_config_ini; + typedef struct { sp_config_random *config_random; sp_config_sloppy *config_sloppy; @@ -176,6 +198,7 @@ typedef struct { sp_config_eval *config_eval; sp_config_wrapper *config_wrapper; sp_config_session *config_session; + sp_config_ini *config_ini; bool hook_execute; char log_media; @@ -215,6 +238,7 @@ typedef struct { #define SP_TOKEN_EVAL_WHITELIST ".eval_whitelist" #define SP_TOKEN_SLOPPY_COMPARISON ".sloppy_comparison" #define SP_TOKEN_ALLOW_WRAPPERS ".wrappers_whitelist" +#define SP_TOKEN_INI ".ini" // common tokens #define SP_TOKEN_ENABLE ".enable(" @@ -284,6 +308,6 @@ int parse_list(char *restrict, char *restrict, void *); void sp_free_disabled_function(void *data); void sp_free_cookie(void *data); void sp_free_zstr(void *data); - +void sp_free_ini_entry(void *data); #endif /* SP_CONFIG_H */ diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index 8080eec..e6eb05e 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -562,3 +562,80 @@ int parse_upload_validation(char *line) { return ret; } + +int parse_ini_protection(char *line) { + bool disable = false, enable = false; + bool rw = false, ro = false; // rw is ignored, but declaring .policy_rw is valid for readability + sp_config_functions sp_config_ini_protection[] = { + {parse_empty, SP_TOKEN_ENABLE, &(enable)}, + {parse_empty, SP_TOKEN_DISABLE, &(disable)}, + {parse_empty, SP_TOKEN_SIMULATION, &(SNUFFLEUPAGUS_G(config).config_ini->simulation)}, + {parse_empty, ".policy_readonly(", &ro}, + {parse_empty, ".policy_ro(", &ro}, + {parse_empty, ".policy_readwrite(", &rw}, + {parse_empty, ".policy_rw(", &rw}, + {0, 0, 0}}; + + int ret = parse_keywords(sp_config_ini_protection, line); + if (ret) { return ret; } + + if (enable && disable) { + sp_log_err("config", "A rule can't be enabled and disabled on line %zu", + sp_line_no); + return -1; + } + if (enable || disable) { + SNUFFLEUPAGUS_G(config).config_ini->enable = (enable || !disable); + } + + if (ro && rw) { + sp_log_err("config", "rule cannot be both read-write and read-only on line %zu", sp_line_no); + return -1; + } + SNUFFLEUPAGUS_G(config).config_ini->policy_readonly = ro; + + return ret; +} + +int parse_ini_entry(char *line) { + sp_ini_entry *entry = pecalloc(sizeof(sp_ini_entry), 1, 1); + bool rw = false, ro = false; + + sp_config_functions sp_config_ini_protection[] = { + {parse_empty, SP_TOKEN_SIMULATION, &entry->simulation}, + {parse_str, ".key(", &entry->key}, + {parse_str, ".msg(", &entry->msg}, + {parse_str, ".set(", &entry->set}, + {parse_str, ".min(", &entry->min}, + {parse_str, ".max(", &entry->max}, + {parse_regexp, ".regexp(", &entry->regexp}, + {parse_empty, ".readonly(", &ro}, + {parse_empty, ".ro(", &ro}, + {parse_empty, ".readwrite()", &rw}, + {parse_empty, ".rw()", &rw}, + {0, 0, 0}}; + + int ret = parse_keywords(sp_config_ini_protection, line); + if (ret) { goto err; } + + if (!entry->key) { + sp_log_err("config", "A .key() must be provided on line %zu", sp_line_no); + ret = -1; goto err; + } + + if (ro && rw) { + sp_log_err("config", "rule cannot be both read-write and read-only on line %zu", sp_line_no); + ret = -1; goto err; + } + entry->access = ro - rw; + + zend_hash_add_ptr(SNUFFLEUPAGUS_G(config).config_ini->entries, entry->key, entry); + return ret; + +err: + if (entry) { + sp_free_ini_entry(entry); + pefree(entry, 1); + } + return ret; +} \ No newline at end of file diff --git a/src/sp_config_keywords.h b/src/sp_config_keywords.h index a279cc9..b90c06c 100644 --- a/src/sp_config_keywords.h +++ b/src/sp_config_keywords.h @@ -18,5 +18,7 @@ int parse_session(char *line); int parse_sloppy_comparison(char *line); int parse_wrapper_whitelist(char *line); int parse_log_media(char *line); +int parse_ini_protection(char *line); +int parse_ini_entry(char *line); #endif // __SP_CONFIG_KEYWORDS_H diff --git a/src/sp_ini.c b/src/sp_ini.c new file mode 100644 index 0000000..05d7d99 --- /dev/null +++ b/src/sp_ini.c @@ -0,0 +1,126 @@ +#include "php_snuffleupagus.h" + +#define SP_INI_HAS_CHECKS_COND(entry) (entry->min || entry->max || entry->regexp) +#define SP_INI_ACCESS_READONLY_COND(entry, cfg) (entry->access == SP_READONLY || (!entry->access && cfg->policy_readonly)) + +static bool /* success */ sp_ini_check(zend_string *varname, zend_string *new_value, sp_ini_entry **sp_entry_p) { + if (!varname || ZSTR_LEN(varname) == 0) { + return false; + } + + sp_config_ini *cfg = SNUFFLEUPAGUS_G(config).config_ini; + sp_ini_entry *entry = zend_hash_find_ptr(cfg->entries, varname); + if (sp_entry_p) { + *sp_entry_p = entry; + } + bool simulation = (cfg->simulation || (entry && entry->simulation)); + + if (!entry) { + if (cfg->policy_readonly) { + sp_log_auto("ini_protection", simulation, "INI setting is read-only"); + if (simulation) { return true; } + return false; + } + return true; + } + + if (SP_INI_ACCESS_READONLY_COND(entry, cfg)) { + sp_log_auto("ini_protection", simulation, "%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI setting is read-only")); + if (simulation) { return true; } + return false; + } + + if (!new_value && SP_INI_HAS_CHECKS_COND(entry)) { + sp_log_auto("ini_protection", simulation, "new INI value must not be NULL"); + if (simulation) { return true; } + return false; + } + + if (entry->min || entry->max) { + zend_long lvalue = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value)); + if ((entry->min && zend_atol(ZSTR_VAL(entry->min), ZSTR_LEN(entry->min)) > lvalue) || + (entry->max && zend_atol(ZSTR_VAL(entry->max), ZSTR_LEN(entry->max)) < lvalue)) { + sp_log_auto("ini_protection", simulation, "%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI value out of range")); + if (simulation) { return true; } + return false; + } + } + + if (entry->regexp) { + if (!sp_is_regexp_matching_len(entry->regexp, ZSTR_VAL(new_value), ZSTR_LEN(new_value))) { + sp_log_auto("ini_protection", simulation, "%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI value does not match regex")); + if (simulation) { return true; } + return false; + } + } + + return true; +} + +static PHP_INI_MH(sp_ini_onmodify) { + zend_ini_entry *ini_entry = entry; + sp_ini_entry *sp_entry = NULL; + + sp_log_debug("%s =? %s", ZSTR_VAL(ini_entry->name), ZSTR_VAL(new_value)); + if (!sp_ini_check(ini_entry->name, new_value, &sp_entry)) { + return FAILURE; + } + + if (sp_entry && sp_entry->orig_onmodify) { + return sp_entry->orig_onmodify(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage); + } + + return SUCCESS; +} + +void sp_hook_ini() { + sp_config_ini *cfg = SNUFFLEUPAGUS_G(config).config_ini; + sp_ini_entry *sp_entry; + zend_ini_entry *ini_entry; + ZEND_HASH_FOREACH_PTR(cfg->entries, sp_entry) + sp_log_debug("hook entry `%s`", ZSTR_VAL(sp_entry->key)); + if ((ini_entry = zend_hash_find_ptr(EG(ini_directives), sp_entry->key)) == NULL) { + sp_log_warn("ini_protection", "Cannot hook INI var `%s`. Maybe a typo or the PHP extension providing this var is not loaded yet.", ZSTR_VAL(sp_entry->key)); + continue; + } + if (SP_INI_ACCESS_READONLY_COND(sp_entry, cfg)) { + ini_entry->modifiable = ini_entry->orig_modifiable = 0; + } + PHP_INI_MH((*orig_onmodify)) = ini_entry->on_modify; + + if (SP_INI_HAS_CHECKS_COND(sp_entry) || SP_INI_ACCESS_READONLY_COND(sp_entry, cfg)) { + // only hook on_modify if there is any check to perform + sp_entry->orig_onmodify = ini_entry->on_modify; + ini_entry->on_modify = sp_ini_onmodify; + } + + if (sp_entry->set) { + zend_string *duplicate = zend_string_copy(sp_entry->set); + + if (!orig_onmodify || orig_onmodify(ini_entry, duplicate, ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, ZEND_INI_STAGE_STARTUP) == SUCCESS) { + ini_entry->value = duplicate; + } else { + zend_string_release(duplicate); + sp_log_warn("ini_protection", "Failed to set INI var `%s`.", ZSTR_VAL(sp_entry->key)); + continue; + } + } + ZEND_HASH_FOREACH_END(); +} + +void sp_unhook_ini() { + sp_ini_entry *sp_entry; + zend_ini_entry *ini_entry; + ZEND_HASH_FOREACH_PTR(SNUFFLEUPAGUS_G(config).config_ini->entries, sp_entry) + if (!sp_entry->orig_onmodify) { + // not hooked or no original onmodify + continue; + } + if ((ini_entry = zend_hash_find_ptr(EG(ini_directives), sp_entry->key)) == NULL) { + // unusual. ini entry is missing. + continue; + } + ini_entry->on_modify = sp_entry->orig_onmodify; + sp_entry->orig_onmodify = NULL; + ZEND_HASH_FOREACH_END(); +} diff --git a/src/sp_ini.h b/src/sp_ini.h new file mode 100644 index 0000000..5869539 --- /dev/null +++ b/src/sp_ini.h @@ -0,0 +1,2 @@ +void sp_hook_ini(); +void sp_unhook_ini(); \ No newline at end of file -- cgit v1.3 From 26ee817a0e5a2bed4994fd4efc13e7f5106ca55c Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Sat, 7 Aug 2021 22:33:21 +0200 Subject: PHP7 compatibility --- src/config.m4 | 2 +- src/php_snuffleupagus.h | 1 + src/sp_php_compat.c | 22 ++++++++++++++++++++++ src/sp_php_compat.h | 12 ++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/sp_php_compat.c create mode 100644 src/sp_php_compat.h (limited to 'src/php_snuffleupagus.h') diff --git a/src/config.m4 b/src/config.m4 index 1410565..9778820 100644 --- a/src/config.m4 +++ b/src/config.m4 @@ -7,7 +7,7 @@ sources="$sources sp_disabled_functions.c sp_execute.c sp_upload_validation.c" sources="$sources sp_cookie_encryption.c sp_network_utils.c tweetnacl.c" sources="$sources sp_config_keywords.c sp_var_parser.c sp_var_value.c sp_tree.c" sources="$sources sp_pcre_compat.c sp_crypt.c sp_session.c sp_sloppy.c sp_wrapper.c" -sources="$sources sp_ini.c" +sources="$sources sp_ini.c sp_php_compat.c" PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support, [ --enable-snuffleupagus Enable snuffleupagus support]) diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index be4d306..928095d 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -65,6 +65,7 @@ typedef void (*zif_handler)(INTERNAL_FUNCTION_PARAMETERS); #define SP_CONFIG_INVALID 0 #define SP_CONFIG_NONE -1 +#include "sp_php_compat.h" #include "sp_pcre_compat.h" #include "sp_list.h" #include "sp_tree.h" diff --git a/src/sp_php_compat.c b/src/sp_php_compat.c new file mode 100644 index 0000000..933acd8 --- /dev/null +++ b/src/sp_php_compat.c @@ -0,0 +1,22 @@ +#include "php_snuffleupagus.h" + +#if PHP_VERSION_ID < 80000 + +// zend_string_concat2 taken from PHP 8.0.9 zend_string.c +// TODO: license clarification + +ZEND_API zend_string *zend_string_concat2( + const char *str1, size_t str1_len, + const char *str2, size_t str2_len) +{ + size_t len = str1_len + str2_len; + zend_string *res = zend_string_alloc(len, 0); + + memcpy(ZSTR_VAL(res), str1, str1_len); + memcpy(ZSTR_VAL(res) + str1_len, str2, str2_len); + ZSTR_VAL(res)[len] = '\0'; + + return res; +} + +#endif diff --git a/src/sp_php_compat.h b/src/sp_php_compat.h new file mode 100644 index 0000000..380abe4 --- /dev/null +++ b/src/sp_php_compat.h @@ -0,0 +1,12 @@ +#if PHP_VERSION_ID < 80000 +ZEND_API zend_string *zend_string_concat2( + const char *str1, size_t str1_len, + const char *str2, size_t str2_len); + +#define ZEND_HASH_REVERSE_FOREACH_KEY_PTR(ht, _h, _key, _ptr) \ + ZEND_HASH_REVERSE_FOREACH(ht, 0); \ + _h = _p->h; \ + _key = _p->key; \ + _ptr = Z_PTR_P(_z); + +#endif \ No newline at end of file -- cgit v1.3 From 5148ded7268b569fd5e720f90b44645c83ac3e9e Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Mon, 16 Aug 2021 15:47:01 +0200 Subject: fincy new scanner/parser for config rules + fixed a few bugs along the way + fixed related unittests --- src/Makefile.frag | 2 + src/config.m4 | 5 +- src/php_snuffleupagus.h | 1 + src/sp_config.c | 311 ++++++----- src/sp_config.h | 171 +++--- src/sp_config_keywords.c | 606 ++++++++------------- src/sp_config_keywords.h | 31 +- src/sp_config_scanner.h | 25 + src/sp_config_scanner.re | 139 +++++ src/sp_config_utils.c | 103 ---- src/sp_config_utils.h | 3 - src/sp_disabled_functions.c | 33 +- src/sp_execute.c | 6 +- src/sp_network_utils.c | 6 +- src/sp_pcre_compat.c | 3 +- src/sp_unserialize.c | 3 +- src/sp_utils.c | 13 +- src/sp_utils.h | 4 +- .../encrypt_regexp_cookies_bad_regexp.phpt | 4 +- .../broken_configuration_php8/broken_conf.phpt | 3 +- .../broken_configuration_php8/broken_conf2.phpt | 3 +- .../broken_conf_allow_broken_disabled.phpt | 2 +- .../broken_conf_allow_broken_enabled.phpt | 2 +- .../broken_conf_config_regexp.phpt | 5 +- ...broken_conf_config_regexp_no_closing_paren.phpt | 5 +- ...f_cookie_encryption_without_encryption_key.phpt | 3 +- ...ken_conf_cookie_encryption_without_env_var.phpt | 3 +- .../broken_conf_eval.phpt | 2 +- .../broken_conf_expecting_bool.phpt | 3 +- .../broken_conf_invalid_cidr_value.phpt | 5 +- .../broken_conf_invalid_filename.phpt | 3 +- .../broken_conf_invalid_log_media.phpt | 3 +- .../broken_conf_invalid_type.phpt | 3 +- .../broken_conf_key_value.phpt | 4 +- .../broken_conf_line_empty_string.phpt | 3 +- .../broken_conf_line_no_closing.phpt | 3 +- .../broken_conf_lots_of_quotes.phpt | 3 +- .../broken_conf_missing_script.phpt | 3 +- .../broken_conf_mutually_exclusive.phpt | 5 +- .../broken_conf_mutually_exclusive11.phpt | 5 +- .../broken_conf_mutually_exclusive12.phpt | 5 +- .../broken_conf_mutually_exclusive2.phpt | 5 +- .../broken_conf_mutually_exclusive3.phpt | 5 +- .../broken_conf_mutually_exclusive4.phpt | 4 +- .../broken_conf_mutually_exclusive5.phpt | 4 +- .../broken_conf_mutually_exclusive6.phpt | 5 +- .../broken_conf_mutually_exclusive7.phpt | 5 +- .../broken_conf_mutually_exclusive8.phpt | 5 +- .../broken_conf_readonly_exec.phpt | 3 +- .../broken_conf_samesite.phpt | 3 +- .../broken_conf_session_encryption.phpt | 3 +- .../broken_conf_shown_in_phpinfo.phpt | 5 +- .../broken_conf_truncated.phpt | 3 +- .../broken_conf_unserialize.phpt | 5 +- .../broken_conf_upload_validation.phpt | 3 +- .../broken_conf_weird_keyword.phpt | 3 +- .../broken_conf_wrapper_whitelist.phpt | 3 +- .../broken_conf_wrong_quotes.phpt | 3 +- .../broken_configuration_php8/broken_regexp.phpt | 5 +- .../encrypt_regexp_cookies_bad_regexp.phpt | 4 +- .../encrypt_cookies_no_env.phpt | 2 +- .../encrypt_cookies_no_key.phpt | 2 +- .../encrypt_regexp_cookies_no_env.phpt | 2 +- .../encrypt_regexp_cookies_no_key.phpt | 2 +- src/tests/dump_request/dump_eval_blacklist.phpt | 2 +- src/tests/eval_blacklist/eval_backlist.phpt | 2 +- .../eval_backlist_call_user_func.phpt | 2 +- .../eval_blacklist/eval_backlist_chained.phpt | 2 +- src/tests/eval_blacklist/eval_backlist_list.phpt | 2 +- .../eval_blacklist/eval_backlist_simulation.phpt | 2 +- .../eval_blacklist/nested_eval_blacklist.phpt | 2 +- .../eval_blacklist/nested_eval_blacklist2.phpt | 2 +- 72 files changed, 766 insertions(+), 879 deletions(-) create mode 100644 src/Makefile.frag create mode 100644 src/sp_config_scanner.h create mode 100644 src/sp_config_scanner.re (limited to 'src/php_snuffleupagus.h') diff --git a/src/Makefile.frag b/src/Makefile.frag new file mode 100644 index 0000000..c8458ea --- /dev/null +++ b/src/Makefile.frag @@ -0,0 +1,2 @@ +$(srcdir)/sp_config_scanner.c: $(srcdir)/sp_config_scanner.re + @$(RE2C) $(RE2C_FLAGS) --no-generation-date -bc -o $@ $< diff --git a/src/config.m4 b/src/config.m4 index 9778820..6f462af 100644 --- a/src/config.m4 +++ b/src/config.m4 @@ -7,7 +7,7 @@ sources="$sources sp_disabled_functions.c sp_execute.c sp_upload_validation.c" sources="$sources sp_cookie_encryption.c sp_network_utils.c tweetnacl.c" sources="$sources sp_config_keywords.c sp_var_parser.c sp_var_value.c sp_tree.c" sources="$sources sp_pcre_compat.c sp_crypt.c sp_session.c sp_sloppy.c sp_wrapper.c" -sources="$sources sp_ini.c sp_php_compat.c" +sources="$sources sp_ini.c sp_php_compat.c sp_config_scanner.c" PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support, [ --enable-snuffleupagus Enable snuffleupagus support]) @@ -40,3 +40,6 @@ if test "$PHP_SNUFFLEUPAGUS" = "yes"; then fi PHP_NEW_EXTENSION(snuffleupagus, $sources, $ext_shared,-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) fi + +PHP_PROG_RE2C() +PHP_ADD_MAKEFILE_FRAGMENT() diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index 928095d..91ee8a6 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -70,6 +70,7 @@ typedef void (*zif_handler)(INTERNAL_FUNCTION_PARAMETERS); #include "sp_list.h" #include "sp_tree.h" #include "sp_var_parser.h" +#include "sp_config_scanner.h" #include "sp_config.h" #include "sp_config_utils.h" #include "sp_config_keywords.h" diff --git a/src/sp_config.c b/src/sp_config.c index 37c749b..4d96bbe 100644 --- a/src/sp_config.c +++ b/src/sp_config.c @@ -4,102 +4,140 @@ #include "php_snuffleupagus.h" -size_t sp_line_no; - -static sp_config_tokens const sp_func[] = { - {.func = parse_unserialize, .token = SP_TOKEN_UNSERIALIZE_HMAC}, - {.func = parse_random, .token = SP_TOKEN_HARDEN_RANDOM}, - {.func = parse_log_media, .token = SP_TOKEN_LOG_MEDIA}, - {.func = parse_disabled_functions, .token = SP_TOKEN_DISABLE_FUNC}, - {.func = parse_readonly_exec, .token = SP_TOKEN_READONLY_EXEC}, - {.func = parse_global_strict, .token = SP_TOKEN_GLOBAL_STRICT}, - {.func = parse_upload_validation, .token = SP_TOKEN_UPLOAD_VALIDATION}, - {.func = parse_cookie, .token = SP_TOKEN_COOKIE_ENCRYPTION}, - {.func = parse_global, .token = SP_TOKEN_GLOBAL}, - {.func = parse_auto_cookie_secure, .token = SP_TOKEN_AUTO_COOKIE_SECURE}, - {.func = parse_disable_xxe, .token = SP_TOKEN_DISABLE_XXE}, - {.func = parse_eval_blacklist, .token = SP_TOKEN_EVAL_BLACKLIST}, - {.func = parse_eval_whitelist, .token = SP_TOKEN_EVAL_WHITELIST}, - {.func = parse_session, .token = SP_TOKEN_SESSION_ENCRYPTION}, - {.func = parse_sloppy_comparison, .token = SP_TOKEN_SLOPPY_COMPARISON}, - {.func = parse_wrapper_whitelist, .token = SP_TOKEN_ALLOW_WRAPPERS}, - {.func = parse_ini_protection, .token = ".ini_protection"}, - {.func = parse_ini_entry, .token = ".ini"}, - {NULL, NULL}}; - -/* Top level keyword parsing */ - -static int parse_line(char *line) { - char *ptr = line; - - while (*ptr == ' ' || *ptr == '\t') { - ++ptr; - } - if (!*ptr || *ptr == '#' || *ptr == ';') { - return 0; +static zend_result sp_process_config_root(sp_parsed_keyword *parsed_rule) { + sp_config_keyword sp_func[] = { + {parse_unserialize, SP_TOKEN_UNSERIALIZE_HMAC, SNUFFLEUPAGUS_G(config).config_unserialize}, + {parse_enable, SP_TOKEN_HARDEN_RANDOM, &(SNUFFLEUPAGUS_G(config).config_random->enable)}, + {parse_log_media, SP_TOKEN_LOG_MEDIA, &(SNUFFLEUPAGUS_G(config).log_media)}, + {parse_disabled_functions, SP_TOKEN_DISABLE_FUNC, NULL}, + {parse_readonly_exec, SP_TOKEN_READONLY_EXEC, SNUFFLEUPAGUS_G(config).config_readonly_exec}, + {parse_enable, SP_TOKEN_GLOBAL_STRICT, &(SNUFFLEUPAGUS_G(config).config_global_strict->enable)}, + {parse_upload_validation, SP_TOKEN_UPLOAD_VALIDATION, SNUFFLEUPAGUS_G(config).config_upload_validation}, + {parse_cookie, SP_TOKEN_COOKIE_ENCRYPTION, NULL}, + {parse_global, SP_TOKEN_GLOBAL, NULL}, + {parse_enable, SP_TOKEN_AUTO_COOKIE_SECURE, &(SNUFFLEUPAGUS_G(config).config_auto_cookie_secure->enable)}, + {parse_enable, SP_TOKEN_DISABLE_XXE, &(SNUFFLEUPAGUS_G(config).config_disable_xxe->enable)}, + {parse_eval_filter_conf, SP_TOKEN_EVAL_BLACKLIST, &(SNUFFLEUPAGUS_G(config).config_eval->blacklist)}, + {parse_eval_filter_conf, SP_TOKEN_EVAL_WHITELIST, &(SNUFFLEUPAGUS_G(config).config_eval->whitelist)}, + {parse_session, SP_TOKEN_SESSION_ENCRYPTION, SNUFFLEUPAGUS_G(config).config_session}, + {parse_enable, SP_TOKEN_SLOPPY_COMPARISON, &(SNUFFLEUPAGUS_G(config).config_sloppy->enable)}, + {parse_wrapper_whitelist, SP_TOKEN_ALLOW_WRAPPERS, SNUFFLEUPAGUS_G(config).config_wrapper}, + {parse_ini_protection, SP_TOKEN_INI_PROTECTION, SNUFFLEUPAGUS_G(config).config_ini}, + {parse_ini_entry, SP_TOKEN_INI, SNUFFLEUPAGUS_G(config).config_unserialize}, + {NULL, NULL, NULL}}; + return sp_process_rule(parsed_rule, sp_func); +} + +zend_result sp_parse_config(const char *filename) { + FILE *fd = fopen(filename, "rb"); + if (fd == NULL) { + sp_log_err("config", "Could not open configuration file %s : %s", filename, strerror(errno)); + return FAILURE; } - if (strncmp(ptr, SP_TOKEN_BASE, strlen(SP_TOKEN_BASE))) { - sp_log_err("config", "Invalid configuration prefix for '%s' on line %zu", - line, sp_line_no); - return -1; + size_t step = 8192; + size_t max_len = step, len = 0; + zend_string *data = zend_string_alloc(max_len, 0); + char *ptr = ZSTR_VAL(data); + + size_t bytes; + while ((bytes = fread(ptr, 1, max_len - len, fd))) { + len += bytes; + if (max_len - len <= 0) { + max_len += step; + data = zend_string_extend(data, max_len, 0); + ptr = ZSTR_VAL(data) + len; + } else { + ptr += bytes; + } } - ptr += strlen(SP_TOKEN_BASE); + fclose(fd); + + data = zend_string_truncate(data, len, 0); + ZSTR_VAL(data)[len] = 0; + + int ret = sp_config_scan(ZSTR_VAL(data), sp_process_config_root); + + zend_string_release_ex(data, 0); + + return ret; +} + - for (size_t i = 0; sp_func[i].func; i++) { - if (!strncmp(sp_func[i].token, ptr, strlen(sp_func[i].token))) { - return sp_func[i].func(ptr + strlen(sp_func[i].token)); +zend_result sp_process_rule(sp_parsed_keyword *parsed_rule, sp_config_keyword *config_keywords) { + for (sp_parsed_keyword *kw = parsed_rule; kw->kw; kw++) { + bool found_kw = false; + for (sp_config_keyword *ckw = config_keywords; ckw->func; ckw++) { + if (kw->kwlen == strlen(ckw->token) && !strncmp(kw->kw, ckw->token, kw->kwlen)) { + if (ckw->func) { + int ret = ckw->func(ckw->token, kw, ckw->retval); + switch (ret) { + case SP_PARSER_SUCCESS: + break; + case SP_PARSER_ERROR: + return FAILURE; + case SP_PARSER_STOP: + return SUCCESS; + } + } + found_kw = true; + break; + } + } + + if (!found_kw) { + zend_string *kwname = zend_string_init(kw->kw, kw->kwlen, 0); + sp_log_err("config", "Unexpected keyword '%s' on line %d", ZSTR_VAL(kwname), kw->lineno); + zend_string_release_ex(kwname, 0); + return FAILURE; } } - sp_log_err("config", "Invalid configuration section '%s' on line %zu", line, - sp_line_no); - return -1; + return SUCCESS; } -/* keyword parsing */ #define CHECK_DUPLICATE_KEYWORD(retval) \ if (*(void**)(retval)) { \ - sp_log_err("config", "duplicate %s) on line %zu near `%s`", keyword, sp_line_no, line); \ - return -1; } + sp_log_err("config", "duplicate keyword '%s' on line %zu", token, kw->lineno); \ + return SP_PARSER_ERROR; } -int parse_empty(char *restrict line, char *restrict keyword, void *retval) { +SP_PARSEKW_FN(parse_empty) { + if (kw->arglen) { + sp_log_err("config", "Unexpected argument for keyword '%s' - it should be '%s()' on line %zu", token, token, kw->lineno); + return SP_PARSER_ERROR; + } + if (kw->argtype != SP_ARGTYPE_EMPTY) { + sp_log_err("config", "Missing paranthesis for keyword '%s' - it should be '%s()' on line %zu", token, token, kw->lineno); + return SP_PARSER_ERROR; + } *(bool *)retval = true; - return 0; + return SP_PARSER_SUCCESS; } -int parse_list(char *restrict line, char *restrict keyword, void *list_ptr) { - CHECK_DUPLICATE_KEYWORD(list_ptr); - zend_string *value = NULL; - sp_list_node **list = list_ptr; - char *token, *tmp; +SP_PARSEKW_FN(parse_list) { + CHECK_DUPLICATE_KEYWORD(retval); - size_t consumed = 0; - value = get_param(&consumed, line, SP_TYPE_STR, keyword); - if (!value) { - return -1; - } + sp_list_node **list = retval; + char *tok, *tmp; + + SP_PARSE_ARG(value); tmp = ZSTR_VAL(value); while (1) { - token = strsep(&tmp, ","); - if (token == NULL) { + tok = strsep(&tmp, ","); + if (tok == NULL) { break; } - *list = sp_list_insert(*list, zend_string_init(token, strlen(token), 1)); + *list = sp_list_insert(*list, zend_string_init(tok, strlen(tok), 1)); } + zend_string_release(value); - pefree(value, 1); - return consumed; + return SP_PARSER_SUCCESS; } -int parse_php_type(char *restrict line, char *restrict keyword, void *retval) { - size_t consumed = 0; - zend_string *value = get_param(&consumed, line, SP_TYPE_STR, keyword); - if (!value) { - return -1; - } +SP_PARSEKW_FN(parse_php_type) { + SP_PARSE_ARG(value); if (zend_string_equals_literal_ci(value, "undef")) { *(sp_php_type *)retval = SP_PHP_TYPE_UNDEF; @@ -124,113 +162,88 @@ int parse_php_type(char *restrict line, char *restrict keyword, void *retval) { } else if (zend_string_equals_literal_ci(value, "reference")) { *(sp_php_type *)retval = SP_PHP_TYPE_REFERENCE; } else { - pefree(value, 1); - sp_log_err("error", - "%s) is expecting a valid php type ('false', 'true'," + zend_string_release(value); + sp_log_err("error", ".%s() is expecting a valid php type ('false', 'true'," " 'array'. 'object', 'long', 'double', 'null', 'resource', " - "'reference', 'undef') on line %zu", - keyword, sp_line_no); - return -1; + "'reference', 'undef') on line %zu", token, kw->lineno); + return SP_PARSER_ERROR; } - pefree(value, 1); - return consumed; + zend_string_release(value); + return SP_PARSER_SUCCESS; } -int parse_str(char *restrict line, char *restrict keyword, void *retval) { + +SP_PARSEKW_FN(parse_str) { CHECK_DUPLICATE_KEYWORD(retval); - zend_string *value = NULL; + SP_PARSE_ARG(value); - size_t consumed = 0; - value = get_param(&consumed, line, SP_TYPE_STR, keyword); - if (value) { - *(zend_string **)retval = value; - return consumed; - } - return -1; + *(zend_string **)retval = value; + + return SP_PARSER_SUCCESS; } -int parse_cidr(char *restrict line, char *restrict keyword, void *retval) { - CHECK_DUPLICATE_KEYWORD(retval); +SP_PARSEKW_FN(parse_int) { + int ret = SP_PARSER_SUCCESS; + SP_PARSE_ARG(value); - size_t consumed = 0; - zend_string *value = get_param(&consumed, line, SP_TYPE_STR, keyword); + char *endptr; + errno = 0; + *(int*)retval = (int)strtoimax(ZSTR_VAL(value), &endptr, 10); + if (errno != 0 || !endptr || endptr == ZSTR_VAL(value)) { + sp_log_err("config", "Failed to parse arg '%s' of `%s` on line %zu", ZSTR_VAL(value), token, kw->lineno); + ret = SP_PARSER_ERROR; + } + zend_string_release(value); + return ret; +} + +SP_PARSEKW_FN(parse_ulong) { + int ret = SP_PARSER_SUCCESS; + SP_PARSE_ARG(value); - if (!value) { - sp_log_err("config", "%s doesn't contain a valid cidr on line %zu", line, sp_line_no); - return -1; + char *endptr; + errno = 0; + *(u_long*)retval = (u_long)strtoul(ZSTR_VAL(value), &endptr, 10); + if (errno != 0 || !endptr || endptr == ZSTR_VAL(value)) { + sp_log_err("config", "Failed to parse arg '%s' of `%s` on line %zu", ZSTR_VAL(value), token, kw->lineno); + ret = SP_PARSER_ERROR; } + zend_string_release(value); + return ret; +} + +SP_PARSEKW_FN(parse_cidr) { + CHECK_DUPLICATE_KEYWORD(retval); + SP_PARSE_ARG(value); sp_cidr *cidr = pecalloc(sizeof(sp_cidr), 1, 1); if (0 != get_ip_and_cidr(ZSTR_VAL(value), cidr)) { pefree(cidr, 1); - *(sp_cidr **)retval = NULL; - return -1; + cidr = NULL; } *(sp_cidr **)retval = cidr; - return consumed; + return cidr ? SP_PARSER_SUCCESS : SP_PARSER_ERROR; } -int parse_regexp(char *restrict line, char *restrict keyword, void *retval) { +SP_PARSEKW_FN(parse_regexp) { /* TODO: Do we want to use pcre_study? * (http://www.pcre.org/original/doc/html/pcre_study.html) * maybe not: http://sljit.sourceforge.net/pcre.html*/ CHECK_DUPLICATE_KEYWORD(retval); + SP_PARSE_ARG(value); - size_t consumed = 0; - zend_string *value = get_param(&consumed, line, SP_TYPE_STR, keyword); - - if (value) { - sp_pcre *compiled_re = sp_pcre_compile(ZSTR_VAL(value)); - if (NULL != compiled_re) { - *(sp_pcre **)retval = compiled_re; - return consumed; - } - } - char *closing_paren = strchr(line, ')'); - if (NULL != closing_paren) { - closing_paren[0] = '\0'; + sp_pcre *compiled_re = sp_pcre_compile(ZSTR_VAL(value)); + if (!compiled_re) { + sp_log_err("config", "Invalid regexp '%s' for '.%s()' on line %zu", ZSTR_VAL(value), token, kw->lineno); + zend_string_release_ex(value, 1); + return SP_PARSER_ERROR; } - sp_log_err("config", - "'%s)' is expecting a valid regexp, and not '%s' on line %zu", - keyword, line, sp_line_no); - return -1; -} -int sp_parse_config(const char *conf_file) { - FILE *fd = fopen(conf_file, "r"); - char *lineptr = NULL; - size_t n = 0; - sp_line_no = 1; + *(sp_pcre **)retval = compiled_re; - if (fd == NULL) { - sp_log_err("config", "Could not open configuration file %s : %s", conf_file, - strerror(errno)); - return FAILURE; - } - - while (getline(&lineptr, &n, fd) > 0) { - /* We trash the terminal `\n`. This simplify the display of logs. */ - if (lineptr[strlen(lineptr) - 1] == '\n') { - if (strlen(lineptr) >= 2 && lineptr[strlen(lineptr) - 2] == '\r') { - lineptr[strlen(lineptr) - 2] = '\0'; - } else { - lineptr[strlen(lineptr) - 1] = '\0'; - } - } - if (parse_line(lineptr) == -1) { - fclose(fd); - free(lineptr); - return FAILURE; - } - free(lineptr); - lineptr = NULL; - n = 0; - sp_line_no++; - } - fclose(fd); - return SUCCESS; + return SP_PARSER_SUCCESS; } void sp_free_disabled_function(void *data) { @@ -292,4 +305,4 @@ void sp_free_ini_entry(void *data) { sp_pcre_free(entry->regexp); sp_free_zstr(entry->msg); sp_free_zstr(entry->set); -} \ No newline at end of file +} diff --git a/src/sp_config.h b/src/sp_config.h index 0ba2e7f..fd6dc15 100644 --- a/src/sp_config.h +++ b/src/sp_config.h @@ -5,15 +5,6 @@ #include #include -extern size_t sp_line_no; - -typedef enum { - SP_TYPE_STR = 0, - SP_TYPE_REGEXP, - SP_TYPE_INT, - SP_TYPE_EMPTY -} sp_type; - typedef enum { SP_PHP_TYPE_UNDEF = IS_UNDEF, SP_PHP_TYPE_NULL = IS_NULL, @@ -214,99 +205,115 @@ typedef struct { sp_config_disabled_functions *config_disabled_functions_reg_ret; } sp_config; -typedef struct { - int (*func)(char *, char *, void *); - char *token; - void *retval; -} sp_config_functions; +#define SP_PARSE_FN_(fname, kwvar) int fname(char *token, sp_parsed_keyword *kwvar, void *retval) +#define SP_PARSE_FN(fname) SP_PARSE_FN_(fname, parsed_rule) +#define SP_PARSEKW_FN(fname) SP_PARSE_FN_(fname, kw) typedef struct { - int (*func)(char *); + SP_PARSE_FN((*func)); char *token; -} sp_config_tokens; - -#define SP_TOKEN_BASE "sp" - -#define SP_TOKEN_AUTO_COOKIE_SECURE ".auto_cookie_secure" -#define SP_TOKEN_COOKIE_ENCRYPTION ".cookie" -#define SP_TOKEN_SESSION_ENCRYPTION ".session" -#define SP_TOKEN_DISABLE_FUNC ".disable_function" -#define SP_TOKEN_GLOBAL ".global" -#define SP_TOKEN_GLOBAL_STRICT ".global_strict" -#define SP_TOKEN_HARDEN_RANDOM ".harden_random" -#define SP_TOKEN_READONLY_EXEC ".readonly_exec" -#define SP_TOKEN_UNSERIALIZE_HMAC ".unserialize_hmac" -#define SP_TOKEN_UPLOAD_VALIDATION ".upload_validation" -#define SP_TOKEN_DISABLE_XXE ".disable_xxe" -#define SP_TOKEN_EVAL_BLACKLIST ".eval_blacklist" -#define SP_TOKEN_EVAL_WHITELIST ".eval_whitelist" -#define SP_TOKEN_SLOPPY_COMPARISON ".sloppy_comparison" -#define SP_TOKEN_ALLOW_WRAPPERS ".wrappers_whitelist" -#define SP_TOKEN_INI ".ini" + void *retval; +} sp_config_keyword; + +#define SP_PARSER_SUCCESS 0 +#define SP_PARSER_ERROR -1 +#define SP_PARSER_STOP 1 + +// #define SP_TOKEN_BASE "sp" + +#define SP_TOKEN_AUTO_COOKIE_SECURE "auto_cookie_secure" +#define SP_TOKEN_COOKIE_ENCRYPTION "cookie" +#define SP_TOKEN_SESSION_ENCRYPTION "session" +#define SP_TOKEN_DISABLE_FUNC "disable_function" +#define SP_TOKEN_GLOBAL "global" +#define SP_TOKEN_GLOBAL_STRICT "global_strict" +#define SP_TOKEN_HARDEN_RANDOM "harden_random" +#define SP_TOKEN_READONLY_EXEC "readonly_exec" +#define SP_TOKEN_UNSERIALIZE_HMAC "unserialize_hmac" +#define SP_TOKEN_UPLOAD_VALIDATION "upload_validation" +#define SP_TOKEN_DISABLE_XXE "disable_xxe" +#define SP_TOKEN_EVAL_BLACKLIST "eval_blacklist" +#define SP_TOKEN_EVAL_WHITELIST "eval_whitelist" +#define SP_TOKEN_SLOPPY_COMPARISON "sloppy_comparison" +#define SP_TOKEN_ALLOW_WRAPPERS "wrappers_whitelist" +#define SP_TOKEN_INI_PROTECTION "ini_protection" +#define SP_TOKEN_INI "ini" // common tokens -#define SP_TOKEN_ENABLE ".enable(" -#define SP_TOKEN_DISABLE ".disable(" -#define SP_TOKEN_SIMULATION ".simulation(" -#define SP_TOKEN_TRUE "1" -#define SP_TOKEN_FALSE "0" -#define SP_TOKEN_DUMP ".dump(" -#define SP_TOKEN_ALIAS ".alias(" -#define SP_TOKEN_ALLOW ".allow(" -#define SP_TOKEN_DROP ".drop(" - -#define SP_TOKEN_END_PARAM ')' +#define SP_TOKEN_ENABLE "enable" +#define SP_TOKEN_DISABLE "disable" +#define SP_TOKEN_SIMULATION "simulation" +#define SP_TOKEN_SIM "sim" +// #define SP_TOKEN_TRUE "1" +// #define SP_TOKEN_FALSE "0" +#define SP_TOKEN_DUMP "dump" +#define SP_TOKEN_ALIAS "alias" +#define SP_TOKEN_ALLOW "allow" +#define SP_TOKEN_DROP "drop" // disable_function -#define SP_TOKEN_CIDR ".cidr(" -#define SP_TOKEN_FILENAME ".filename(" -#define SP_TOKEN_FILENAME_REGEXP ".filename_r(" -#define SP_TOKEN_FUNCTION ".function(" -#define SP_TOKEN_FUNCTION_REGEXP ".function_r(" -#define SP_TOKEN_HASH ".hash(" -#define SP_TOKEN_LOCAL_VAR ".var(" -#define SP_TOKEN_PARAM ".param(" -#define SP_TOKEN_PARAM_REGEXP ".param_r(" -#define SP_TOKEN_PARAM_TYPE ".param_type(" -#define SP_TOKEN_RET ".ret(" -#define SP_TOKEN_RET_REGEXP ".ret_r(" -#define SP_TOKEN_RET_TYPE ".ret_type(" -#define SP_TOKEN_VALUE ".value(" -#define SP_TOKEN_VALUE_REGEXP ".value_r(" -#define SP_TOKEN_KEY ".key(" -#define SP_TOKEN_KEY_REGEXP ".key_r(" -#define SP_TOKEN_VALUE_ARG_POS ".pos(" -#define SP_TOKEN_LINE_NUMBER ".line(" +#define SP_TOKEN_CIDR "cidr" +#define SP_TOKEN_FILENAME "filename" +#define SP_TOKEN_FILENAME_REGEXP "filename_r" +#define SP_TOKEN_FUNCTION "function" +#define SP_TOKEN_FUNCTION_REGEXP "function_r" +#define SP_TOKEN_HASH "hash" +#define SP_TOKEN_LOCAL_VAR "var" +#define SP_TOKEN_PARAM "param" +#define SP_TOKEN_PARAM_REGEXP "param_r" +#define SP_TOKEN_PARAM_TYPE "param_type" +#define SP_TOKEN_RET "ret" +#define SP_TOKEN_RET_REGEXP "ret_r" +#define SP_TOKEN_RET_TYPE "ret_type" +#define SP_TOKEN_VALUE "value" +#define SP_TOKEN_VALUE_REGEXP "value_r" +#define SP_TOKEN_KEY "key" +#define SP_TOKEN_KEY_REGEXP "key_r" +#define SP_TOKEN_VALUE_ARG_POS "pos" +#define SP_TOKEN_LINE_NUMBER "line" // cookies encryption -#define SP_TOKEN_NAME ".name(" -#define SP_TOKEN_NAME_REGEXP ".name_r(" +#define SP_TOKEN_NAME "name" +#define SP_TOKEN_NAME_REGEXP "name_r" // cookies samesite -#define SP_TOKEN_SAMESITE ".samesite(" -#define SP_TOKEN_ENCRYPT ".encrypt(" +#define SP_TOKEN_SAMESITE "samesite" +#define SP_TOKEN_ENCRYPT "encrypt" #define SP_TOKEN_SAMESITE_LAX "Lax" #define SP_TOKEN_SAMESITE_STRICT "Strict" // Global configuration options -#define SP_TOKEN_ENCRYPTION_KEY ".secret_key(" -#define SP_TOKEN_ENV_VAR ".cookie_env_var(" -#define SP_TOKEN_LOG_MEDIA ".log_media(" +#define SP_TOKEN_ENCRYPTION_KEY "secret_key" +#define SP_TOKEN_ENV_VAR "cookie_env_var" +#define SP_TOKEN_LOG_MEDIA "log_media" // upload_validator -#define SP_TOKEN_UPLOAD_SCRIPT ".script(" +#define SP_TOKEN_UPLOAD_SCRIPT "script" + +#define SP_TOKEN_LIST "list" + +zend_result sp_process_rule(sp_parsed_keyword *parsed_rule, sp_config_keyword *config_keywords); + +zend_result sp_parse_config(const char *filename); -#define SP_TOKEN_LIST ".list(" +#define SP_PARSE_CHECK_ARG_EXISTS(value) \ +if (!value) { \ + sp_log_err("config", "Missing argument to keyword '%s' - it should be '%s(\"...\")' on line %zu", token, token, kw->lineno); \ + return SP_PARSER_ERROR; \ +} -int sp_parse_config(const char *); -int parse_array(sp_disabled_function *); +#define SP_PARSE_ARG(value) \ + zend_string *value = sp_get_arg_string(kw); \ + SP_PARSE_CHECK_ARG_EXISTS(value); -int parse_str(char *restrict, char *restrict, void *); -int parse_regexp(char *restrict, char *restrict, void *); -int parse_empty(char *restrict, char *restrict, void *); -int parse_cidr(char *restrict, char *restrict, void *); -int parse_php_type(char *restrict, char *restrict, void *); -int parse_list(char *restrict, char *restrict, void *); +SP_PARSEKW_FN(parse_str); +SP_PARSEKW_FN(parse_regexp); +SP_PARSEKW_FN(parse_empty); +SP_PARSEKW_FN(parse_int); +SP_PARSEKW_FN(parse_ulong); +SP_PARSEKW_FN(parse_php_type); +SP_PARSEKW_FN(parse_cidr); +SP_PARSEKW_FN(parse_list); // cleanup void sp_free_disabled_function(void *data); diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index a177a5e..8084698 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -2,311 +2,236 @@ #define SP_SET_ENABLE_DISABLE(enable, disable, varname) \ if (((varname) || enable) && disable) { \ - sp_log_err("config", "A rule can't be enabled and disabled on line %zu", sp_line_no); \ - return -1; \ + sp_log_err("config", "A rule can't be enabled and disabled on line %zu", parsed_rule->lineno); \ + return SP_PARSER_ERROR; \ } \ if (enable || disable) { \ (varname) = (enable || !disable); \ } -static int parse_enable(char *line, bool *restrict retval, - bool *restrict simulation) { +#define SP_PROCESS_CONFIG_KEYWORDS(CMD) if (sp_process_rule(&(parsed_rule[1]), config_keywords) != SUCCESS) { CMD; } +#define SP_PROCESS_CONFIG_KEYWORDS_ERR() SP_PROCESS_CONFIG_KEYWORDS(return SP_PARSER_ERROR) + +SP_PARSE_FN(parse_enable) { bool enable = false, disable = false; - sp_config_functions sp_config_funcs[] = { + sp_config_keyword config_keywords[] = { {parse_empty, SP_TOKEN_ENABLE, &(enable)}, {parse_empty, SP_TOKEN_DISABLE, &(disable)}, - {parse_empty, SP_TOKEN_SIMULATION, simulation}, {0, 0, 0}}; - int ret = parse_keywords(sp_config_funcs, line); - - if (0 != ret) { - return ret; - } + SP_PROCESS_CONFIG_KEYWORDS_ERR(); - SP_SET_ENABLE_DISABLE(enable, disable, *retval); + SP_SET_ENABLE_DISABLE(enable, disable, *(bool*)retval); - return ret; + return SP_PARSER_STOP; } -int parse_session(char *line) { - sp_config_session *session = pecalloc(sizeof(sp_config_session), 1, 0); +SP_PARSE_FN(parse_session) { + sp_config_session *cfg = retval; - sp_config_functions sp_config_funcs_session_encryption[] = { - {parse_empty, SP_TOKEN_ENCRYPT, &(session->encrypt)}, - {parse_empty, SP_TOKEN_SIMULATION, &(session->simulation)}, + sp_config_keyword config_keywords[] = { + {parse_empty, SP_TOKEN_ENCRYPT, &(cfg->encrypt)}, + {parse_empty, SP_TOKEN_SIMULATION, &(cfg->simulation)}, + {parse_empty, SP_TOKEN_SIM, &(cfg->simulation)}, {0, 0, 0}}; - int ret = parse_keywords(sp_config_funcs_session_encryption, line); - if (0 != ret) { - return ret; - } + + SP_PROCESS_CONFIG_KEYWORDS_ERR(); #if (!HAVE_PHP_SESSION || defined(COMPILE_DL_SESSION)) - sp_log_err( - "config", + sp_log_err("config", "You're trying to use the session cookie encryption feature " "on line %zu without having session support statically built into PHP. " "This isn't supported, see " - "https://github.com/jvoisin/snuffleupagus/issues/278 for details.", - sp_line_no); - pefree(session, 0); - return -1; + "https://github.com/jvoisin/snuffleupagus/issues/278 for details.", parsed_rule->lineno); + return SP_PARSER_ERROR; #endif - if (session->encrypt) { - if (0 == (SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var)) { - sp_log_err( - "config", - "You're trying to use the session cookie encryption feature " - "on line %zu without having set the `.cookie_env_var` option in" - "`sp.global`: please set it first", - sp_line_no); - pefree(session, 0); - return -1; - } else if (0 == - (SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)) { - sp_log_err("config", - "You're trying to use the session cookie encryption feature " - "on line %zu without having set the `.secret_key` option in" - "`sp.global`: please set it first", - sp_line_no); - pefree(session, 0); - return -1; + if (cfg->encrypt) { + if (!SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var) { + sp_log_err("config", "You're trying to use the session cookie encryption feature " + "on line %zu without having set the `.cookie_env_var` option in " + "`sp.global`: please set it first", parsed_rule->lineno); + return SP_PARSER_ERROR; + } else if (!SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key) { + sp_log_err("config", "You're trying to use the session cookie encryption feature " + "on line %zu without having set the `.secret_key` option in " + "`sp.global`: please set it first", parsed_rule->lineno); + return SP_PARSER_ERROR; } } - SNUFFLEUPAGUS_G(config).config_session->encrypt = session->encrypt; - SNUFFLEUPAGUS_G(config).config_session->simulation = session->simulation; - pefree(session, 0); - return ret; -} - -int parse_random(char *line) { - return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_random->enable), - NULL); + return SP_PARSER_STOP; } -int parse_log_media(char *line) { - size_t consumed = 0; - zend_string *value = - get_param(&consumed, line, SP_TYPE_STR, SP_TOKEN_LOG_MEDIA); - - if (value) { - if (!strcmp(ZSTR_VAL(value), "php")) { - SNUFFLEUPAGUS_G(config).log_media = SP_ZEND; - return 0; - } else if (!strcmp(ZSTR_VAL(value), "syslog")) { - SNUFFLEUPAGUS_G(config).log_media = SP_SYSLOG; - return 0; - } +SP_PARSEKW_FN(parse_log_media) { + SP_PARSE_ARG(value); + + if (!strcmp(ZSTR_VAL(value), "php")) { + *(char*)retval = SP_ZEND; + zend_string_release_ex(value, 1); + return SP_PARSER_SUCCESS; + } else if (!strcmp(ZSTR_VAL(value), "syslog")) { + *(char*)retval = SP_SYSLOG; + zend_string_release_ex(value, 1); + return SP_PARSER_SUCCESS; } - sp_log_err("config", "%s) only supports 'syslog' or 'php', on line %zu", - SP_TOKEN_LOG_MEDIA, sp_line_no); - return -1; -} - -int parse_sloppy_comparison(char *line) { - return parse_enable(line, &(SNUFFLEUPAGUS_G(config).config_sloppy->enable), - NULL); -} -int parse_disable_xxe(char *line) { - return parse_enable( - line, &(SNUFFLEUPAGUS_G(config).config_disable_xxe->enable), NULL); -} - -int parse_auto_cookie_secure(char *line) { - return parse_enable( - line, &(SNUFFLEUPAGUS_G(config).config_auto_cookie_secure->enable), NULL); -} + sp_log_err("config", "." SP_TOKEN_LOG_MEDIA "() only supports 'syslog' or 'php' on line %zu", kw->lineno); -int parse_global_strict(char *line) { - return parse_enable( - line, &(SNUFFLEUPAGUS_G(config).config_global_strict->enable), NULL); + return SP_PARSER_ERROR; } -int parse_unserialize(char *line) { +SP_PARSE_FN(parse_unserialize) { bool enable = false, disable = false; - sp_config_unserialize *unserialize = - SNUFFLEUPAGUS_G(config).config_unserialize; + sp_config_unserialize *cfg = (sp_config_unserialize*)retval; - sp_config_functions sp_config_funcs[] = { + sp_config_keyword config_keywords[] = { {parse_empty, SP_TOKEN_ENABLE, &(enable)}, {parse_empty, SP_TOKEN_DISABLE, &(disable)}, - {parse_empty, SP_TOKEN_SIMULATION, &(unserialize->simulation)}, - {parse_str, SP_TOKEN_DUMP, &(unserialize->dump)}, + {parse_empty, SP_TOKEN_SIMULATION, &(cfg->simulation)}, + {parse_empty, SP_TOKEN_SIM, &(cfg->simulation)}, + {parse_str, SP_TOKEN_DUMP, &(cfg->dump)}, {0, 0, 0}}; - unserialize->textual_representation = zend_string_init(line, strlen(line), 1); + SP_PROCESS_CONFIG_KEYWORDS_ERR(); - int ret = parse_keywords(sp_config_funcs, line); - if (0 != ret) { - return ret; - } + SP_SET_ENABLE_DISABLE(enable, disable, cfg->enable); - SP_SET_ENABLE_DISABLE(enable, disable, SNUFFLEUPAGUS_G(config).config_unserialize->enable); + cfg->textual_representation = sp_get_textual_representation(parsed_rule); - return ret; + return SP_PARSER_STOP; } -int parse_readonly_exec(char *line) { +SP_PARSE_FN(parse_readonly_exec) { bool enable = false, disable = false; - sp_config_readonly_exec *readonly_exec = - SNUFFLEUPAGUS_G(config).config_readonly_exec; + sp_config_readonly_exec *cfg = (sp_config_readonly_exec*)retval; - sp_config_functions sp_config_funcs[] = { + sp_config_keyword config_keywords[] = { {parse_empty, SP_TOKEN_ENABLE, &(enable)}, {parse_empty, SP_TOKEN_DISABLE, &(disable)}, - {parse_empty, SP_TOKEN_SIMULATION, &(readonly_exec->simulation)}, - {parse_str, SP_TOKEN_DUMP, &(readonly_exec->dump)}, + {parse_empty, SP_TOKEN_SIMULATION, &(cfg->simulation)}, + {parse_empty, SP_TOKEN_SIM, &(cfg->simulation)}, + {parse_str, SP_TOKEN_DUMP, &(cfg->dump)}, {0, 0, 0}}; - readonly_exec->textual_representation = - zend_string_init(line, strlen(line), 1); - int ret = parse_keywords(sp_config_funcs, line); + SP_PROCESS_CONFIG_KEYWORDS_ERR(); - if (0 != ret) { - return ret; - } + cfg->textual_representation = sp_get_textual_representation(parsed_rule); - SP_SET_ENABLE_DISABLE(enable, disable, SNUFFLEUPAGUS_G(config).config_readonly_exec->enable); + SP_SET_ENABLE_DISABLE(enable, disable, cfg->enable); - return ret; + return SP_PARSER_STOP; } -int parse_global(char *line) { - sp_config_functions sp_config_funcs_global[] = { - {parse_str, SP_TOKEN_ENCRYPTION_KEY, - &(SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)}, - {parse_str, SP_TOKEN_ENV_VAR, - &(SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var)}, +SP_PARSE_FN(parse_global) { + sp_config_keyword config_keywords[] = { + {parse_str, SP_TOKEN_ENCRYPTION_KEY, &(SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)}, + {parse_str, SP_TOKEN_ENV_VAR, &(SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var)}, + {parse_log_media, SP_TOKEN_LOG_MEDIA, &(SNUFFLEUPAGUS_G(config).log_media)}, {0, 0, 0}}; - return parse_keywords(sp_config_funcs_global, line); + + SP_PROCESS_CONFIG_KEYWORDS_ERR(); + return SP_PARSER_STOP; } -static int parse_eval_filter_conf(char *line, sp_list_node **list) { - sp_config_eval *eval = SNUFFLEUPAGUS_G(config).config_eval; +SP_PARSE_FN(parse_eval_filter_conf) { + sp_config_eval *cfg = SNUFFLEUPAGUS_G(config).config_eval; - sp_config_functions sp_config_funcs[] = { - {parse_list, SP_TOKEN_LIST, list}, - {parse_empty, SP_TOKEN_SIMULATION, - &(SNUFFLEUPAGUS_G(config).config_eval->simulation)}, - {parse_str, SP_TOKEN_DUMP, &(SNUFFLEUPAGUS_G(config).config_eval->dump)}, + sp_config_keyword config_keywords[] = { + {parse_list, SP_TOKEN_LIST, retval}, + {parse_empty, SP_TOKEN_SIMULATION, &(cfg->simulation)}, + {parse_empty, SP_TOKEN_SIM, &(cfg->simulation)}, + {parse_str, SP_TOKEN_DUMP, &(cfg->dump)}, {0, 0, 0}}; - eval->textual_representation = zend_string_init(line, strlen(line), 1); + SP_PROCESS_CONFIG_KEYWORDS_ERR(); - int ret = parse_keywords(sp_config_funcs, line); - if (0 != ret) { - return ret; - } + cfg->textual_representation = sp_get_textual_representation(parsed_rule); - return SUCCESS; + return SP_PARSER_STOP; } -int parse_wrapper_whitelist(char *line) { - SNUFFLEUPAGUS_G(config).config_wrapper->enabled = true; - sp_config_functions sp_config_funcs[] = { - {parse_list, SP_TOKEN_LIST, - &SNUFFLEUPAGUS_G(config).config_wrapper->whitelist}, +SP_PARSE_FN(parse_wrapper_whitelist) { + sp_config_wrapper *cfg = (sp_config_wrapper*)retval; + + sp_config_keyword config_keywords[] = { + {parse_list, SP_TOKEN_LIST, &cfg->whitelist}, {0, 0, 0}}; - int ret = parse_keywords(sp_config_funcs, line); - if (0 != ret) { - return ret; - } - return SUCCESS; -} -int parse_eval_blacklist(char *line) { - return parse_eval_filter_conf( - line, &SNUFFLEUPAGUS_G(config).config_eval->blacklist); -} + SP_PROCESS_CONFIG_KEYWORDS_ERR(); + + cfg->enabled = true; -int parse_eval_whitelist(char *line) { - return parse_eval_filter_conf( - line, &SNUFFLEUPAGUS_G(config).config_eval->whitelist); + return SP_PARSER_STOP; } -int parse_cookie(char *line) { +SP_PARSE_FN(parse_cookie) { int ret = 0; zend_string *samesite = NULL; sp_cookie *cookie = pecalloc(sizeof(sp_cookie), 1, 1); - sp_config_functions sp_config_funcs_cookie_encryption[] = { + sp_config_keyword config_keywords[] = { {parse_str, SP_TOKEN_NAME, &(cookie->name)}, {parse_regexp, SP_TOKEN_NAME_REGEXP, &(cookie->name_r)}, {parse_str, SP_TOKEN_SAMESITE, &samesite}, {parse_empty, SP_TOKEN_ENCRYPT, &cookie->encrypt}, {parse_empty, SP_TOKEN_SIMULATION, &cookie->simulation}, + {parse_empty, SP_TOKEN_SIM, &cookie->simulation}, {0, 0, 0}}; - ret = parse_keywords(sp_config_funcs_cookie_encryption, line); - if (0 != ret) { - return ret; - } + SP_PROCESS_CONFIG_KEYWORDS(goto err); if (cookie->encrypt) { - if (0 == (SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var)) { - sp_log_err( - "config", - "You're trying to use the cookie encryption feature" - "on line %zu without having set the `.cookie_env_var` option in" - "`sp.global`: please set it first", - sp_line_no); - return -1; - } else if (0 == - (SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)) { - sp_log_err( - "config", - "You're trying to use the cookie encryption feature" - "on line %zu without having set the `.encryption_key` option in" - "`sp.global`: please set it first", - sp_line_no); - return -1; + if (!SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var) { + sp_log_err("config", "You're trying to use the cookie encryption feature on line %zu " + "without having set the `." SP_TOKEN_ENV_VAR "` option in`sp.global`: please set it first", parsed_rule->lineno); + goto err; + } else if (!SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key) { + sp_log_err("config", "You're trying to use the cookie encryption feature " + "on line %zu without having set the `." SP_TOKEN_ENCRYPTION_KEY "` option in " + "`sp." SP_TOKEN_GLOBAL "`: please set it first", parsed_rule->lineno); + goto err; } } else if (!samesite) { - sp_log_err("config", - "You must specify a at least one action to a cookie on line " - "%zu", - sp_line_no); - return -1; + sp_log_err("config", "You must specify a at least one action to a cookie on line %zu", parsed_rule->lineno); + goto err; } if ((!cookie->name || 0 == ZSTR_LEN(cookie->name)) && !cookie->name_r) { - sp_log_err("config", - "You must specify a cookie name/regexp on line " - "%zu", - sp_line_no); - return -1; + sp_log_err("config", "You must specify a cookie name/regexp on line %zu", parsed_rule->lineno); + goto err; } if (cookie->name && cookie->name_r) { - sp_log_err("config", - "name and name_r are mutually exclusive on line " - "%zu", - sp_line_no); - return -1; + sp_log_err("config", "name and name_r are mutually exclusive on line %zu", parsed_rule->lineno); + goto err; } if (samesite) { if (zend_string_equals_literal_ci(samesite, SP_TOKEN_SAMESITE_LAX)) { cookie->samesite = lax; - } else if (zend_string_equals_literal_ci(samesite, - SP_TOKEN_SAMESITE_STRICT)) { + } else if (zend_string_equals_literal_ci(samesite, SP_TOKEN_SAMESITE_STRICT)) { cookie->samesite = strict; } else { - sp_log_err( - "config", - "%s is an invalid value to samesite (expected %s or %s) on line " - "%zu", - ZSTR_VAL(samesite), SP_TOKEN_SAMESITE_LAX, SP_TOKEN_SAMESITE_STRICT, - sp_line_no); - return -1; + sp_log_err("config", "'%s' is an invalid value to samesite (expected " SP_TOKEN_SAMESITE_LAX " or " SP_TOKEN_SAMESITE_STRICT ") on line %zu", + ZSTR_VAL(samesite), parsed_rule->lineno); + goto err; } } - SNUFFLEUPAGUS_G(config).config_cookie->cookies = - sp_list_insert(SNUFFLEUPAGUS_G(config).config_cookie->cookies, cookie); - return SUCCESS; + + SNUFFLEUPAGUS_G(config).config_cookie->cookies = sp_list_insert(SNUFFLEUPAGUS_G(config).config_cookie->cookies, cookie); + + return SP_PARSER_STOP; + +err: + if (samesite) { + zend_string_release(samesite); + } + if (cookie) { + sp_free_cookie(cookie); + pefree(cookie, 1); + } + return SP_PARSER_ERROR; } -int add_df_to_hashtable(HashTable *ht, sp_disabled_function *df) { +static int add_df_to_hashtable(HashTable *ht, sp_disabled_function *df) { zval *list = zend_hash_find(ht, df->function); if (NULL == list) { @@ -317,19 +242,19 @@ int add_df_to_hashtable(HashTable *ht, sp_disabled_function *df) { return SUCCESS; } -int parse_disabled_functions(char *line) { - int ret = 0; - bool enable = true, disable = false, allow = false, drop = false; - zend_string *pos = NULL, *var = NULL, *param = NULL; - zend_string *line_number = NULL; +SP_PARSE_FN(parse_disabled_functions) { + int ret = SP_PARSER_ERROR; + bool enable = false, disable = false, allow = false, drop = false; + zend_string *var = NULL, *param = NULL; sp_disabled_function *df = pecalloc(sizeof(*df), 1, 1); df->pos = -1; - sp_config_functions sp_config_funcs_disabled_functions[] = { + sp_config_keyword config_keywords[] = { {parse_empty, SP_TOKEN_ENABLE, &(enable)}, {parse_empty, SP_TOKEN_DISABLE, &(disable)}, {parse_str, SP_TOKEN_ALIAS, &(df->alias)}, {parse_empty, SP_TOKEN_SIMULATION, &(df->simulation)}, + {parse_empty, SP_TOKEN_SIM, &(df->simulation)}, {parse_str, SP_TOKEN_FILENAME, &(df->filename)}, {parse_regexp, SP_TOKEN_FILENAME_REGEXP, &(df->r_filename)}, {parse_str, SP_TOKEN_FUNCTION, &(df->function)}, @@ -350,23 +275,21 @@ int parse_disabled_functions(char *line) { {parse_regexp, SP_TOKEN_RET_REGEXP, &(df->r_ret)}, {parse_php_type, SP_TOKEN_RET_TYPE, &(df->ret_type)}, {parse_str, SP_TOKEN_LOCAL_VAR, &(var)}, - {parse_str, SP_TOKEN_VALUE_ARG_POS, &(pos)}, - {parse_str, SP_TOKEN_LINE_NUMBER, &(line_number)}, + {parse_int, SP_TOKEN_VALUE_ARG_POS, &(df->pos)}, + {parse_ulong, SP_TOKEN_LINE_NUMBER, &(df->line)}, {0, 0, 0}}; - ret = parse_keywords(sp_config_funcs_disabled_functions, line); + SP_PROCESS_CONFIG_KEYWORDS(goto out); - if (0 != ret) { - goto out; + SP_SET_ENABLE_DISABLE(enable, disable, enable); + if (disable) { + ret = SP_PARSER_STOP; goto out; } #define MUTUALLY_EXCLUSIVE(X, Y, STR1, STR2) \ if (X && Y) { \ - sp_log_err("config", \ - "Invalid configuration line: 'sp.disabled_functions%s': " \ - "'.%s' and '.%s' are mutually exclusive on line %zu", \ - line, STR1, STR2, sp_line_no); \ - ret = -1; goto out; \ + sp_log_err("config", "Invalid configuration line for 'sp.disabled_functions': '.%s' and '.%s' are mutually exclusive on line %zu", STR1, STR2, parsed_rule->lineno); \ + goto out; \ } MUTUALLY_EXCLUSIVE(df->value, df->r_value, "value", "value_r"); @@ -374,8 +297,8 @@ int parse_disabled_functions(char *line) { MUTUALLY_EXCLUSIVE(df->filename, df->r_filename, "filename", "filename_r"); MUTUALLY_EXCLUSIVE(df->ret, df->r_ret, "ret", "ret_r"); MUTUALLY_EXCLUSIVE(df->key, df->r_key, "key", "key_r"); - MUTUALLY_EXCLUSIVE(pos, param, "pos", "param"); - MUTUALLY_EXCLUSIVE(pos, df->r_param, "pos", "param_r"); + MUTUALLY_EXCLUSIVE((df->pos >= 0), param, "pos", "param"); + MUTUALLY_EXCLUSIVE((df->pos >= 0), df->r_param, "pos", "param_r"); MUTUALLY_EXCLUSIVE(param, df->r_param, "param", "param_r"); MUTUALLY_EXCLUSIVE((df->r_key || df->key), (df->r_value || df->value), "key", "value"); MUTUALLY_EXCLUSIVE((df->r_ret || df->ret || df->ret_type), (df->r_param || param), "ret", "param"); @@ -385,52 +308,21 @@ int parse_disabled_functions(char *line) { #undef MUTUALLY_EXCLUSIVE if (!(df->r_function || df->function)) { - sp_log_err("config", - "Invalid configuration line: 'sp.disabled_functions%s':" - " must take a function name on line %zu", - line, sp_line_no); - ret = -1; goto out; + sp_log_err("config", "Invalid configuration line: 'sp.disabled_functions': must take a function name on line %zu", parsed_rule->lineno); + goto out; } if (df->filename && (*ZSTR_VAL(df->filename) != '/') && (0 != strncmp(ZSTR_VAL(df->filename), "phar://", strlen("phar://")))) { - sp_log_err( - "config", - "Invalid configuration line: 'sp.disabled_functions%s':" - "'.filename' must be an absolute path or a phar archive on line %zu", - line, sp_line_no); - ret = -1; goto out; + sp_log_err("config", "Invalid configuration line: 'sp.disabled_functions': '.filename' must be an absolute path or a phar archive on line %zu", parsed_rule->lineno); + goto out; } if (!(allow ^ drop)) { - sp_log_err("config", - "Invalid configuration line: 'sp.disabled_functions%s': The " - "rule must either be a `drop` or `allow` one on line %zu", - line, sp_line_no); - ret = -1; goto out; - } - - if (pos) { - errno = 0; - char *endptr; - df->pos = (int)strtol(ZSTR_VAL(pos), &endptr, 10); - if (errno != 0 || endptr == ZSTR_VAL(pos)) { - sp_log_err("config", "Failed to parse arg '%s' of `pos` on line %zu", - ZSTR_VAL(pos), sp_line_no); - ret = -1; goto out; - } + sp_log_err("config", "Invalid configuration line: 'sp.disabled_functions': The rule must either be a `drop` or `allow` one on line %zu", parsed_rule->lineno); + goto out; } - if (line_number) { - errno = 0; - char *endptr; - df->line = (unsigned int)strtoul(ZSTR_VAL(line_number), &endptr, 10); - if (errno != 0 || endptr == ZSTR_VAL(line_number)) { - sp_log_err("config", "Failed to parse arg '%s' of `line` on line %zu", - ZSTR_VAL(line_number), sp_line_no); - ret = -1; goto out; - } - } df->allow = allow; - df->textual_representation = zend_string_init(line, strlen(line), 1); + df->textual_representation = sp_get_textual_representation(parsed_rule); if (df->function) { df->functions_list = parse_functions_list(ZSTR_VAL(df->function)); @@ -450,33 +342,23 @@ int parse_disabled_functions(char *line) { df->param = sp_parse_var(ZSTR_VAL(param)); } if (!df->param) { - sp_log_err("config", "Invalid value '%s' for `param` on line %zu", - ZSTR_VAL(param), sp_line_no); - ret = -1; goto out; + sp_log_err("config", "Invalid value '%s' for `param` on line %zu", ZSTR_VAL(param), parsed_rule->lineno); + goto out; } } - if (var) { if (ZSTR_LEN(var)) { df->var = sp_parse_var(ZSTR_VAL(var)); if (!df->var) { - sp_log_err("config", "Invalid value '%s' for `var` on line %zu", - ZSTR_VAL(var), sp_line_no); - ret = -1; goto out; + sp_log_err("config", "Invalid value '%s' for `var` on line %zu", ZSTR_VAL(var), parsed_rule->lineno); + goto out; } } else { - sp_log_err("config", "Empty value in `var` on line %zu", sp_line_no); - ret = -1; goto out; + sp_log_err("config", "Empty value in `var` on line %zu", parsed_rule->lineno); + goto out; } } - if (true == disable || 0 != ret) { - out: - sp_free_disabled_function(df); - pefree(df, 1); - return ret; - } - if (df->function && zend_string_equals_literal(df->function, "print")) { zend_string_release(df->function); df->function = zend_string_init("echo", sizeof("echo") - 1, 1); @@ -484,148 +366,136 @@ int parse_disabled_functions(char *line) { if (df->function && !df->functions_list) { if (df->ret || df->r_ret || df->ret_type) { - add_df_to_hashtable(SNUFFLEUPAGUS_G(config).config_disabled_functions_ret, - df); + add_df_to_hashtable(SNUFFLEUPAGUS_G(config).config_disabled_functions_ret, df); } else { - add_df_to_hashtable(SNUFFLEUPAGUS_G(config).config_disabled_functions, - df); + add_df_to_hashtable(SNUFFLEUPAGUS_G(config).config_disabled_functions, df); } } else { if (df->ret || df->r_ret || df->ret_type) { - SNUFFLEUPAGUS_G(config) - .config_disabled_functions_reg_ret->disabled_functions = - sp_list_insert( - SNUFFLEUPAGUS_G(config) - .config_disabled_functions_reg_ret->disabled_functions, - df); + SNUFFLEUPAGUS_G(config).config_disabled_functions_reg_ret->disabled_functions = sp_list_insert(SNUFFLEUPAGUS_G(config).config_disabled_functions_reg_ret->disabled_functions, df); } else { - SNUFFLEUPAGUS_G(config) - .config_disabled_functions_reg->disabled_functions = - sp_list_insert(SNUFFLEUPAGUS_G(config) - .config_disabled_functions_reg->disabled_functions, - df); + SNUFFLEUPAGUS_G(config).config_disabled_functions_reg->disabled_functions = sp_list_insert(SNUFFLEUPAGUS_G(config).config_disabled_functions_reg->disabled_functions, df); } } + return SP_PARSER_STOP; + +out: + if (df) { + sp_free_disabled_function(df); + pefree(df, 1); + } + if (param) { zend_string_release(param); } + if (var) { zend_string_release(var); } + return ret; } -int parse_upload_validation(char *line) { +SP_PARSE_FN(parse_upload_validation) { bool disable = false, enable = false; - sp_config_functions sp_config_funcs_upload_validation[] = { - {parse_str, SP_TOKEN_UPLOAD_SCRIPT, - &(SNUFFLEUPAGUS_G(config).config_upload_validation->script)}, - {parse_empty, SP_TOKEN_SIMULATION, - &(SNUFFLEUPAGUS_G(config).config_upload_validation->simulation)}, + sp_config_upload_validation *cfg = (sp_config_upload_validation*)retval; + + sp_config_keyword config_keywords[] = { {parse_empty, SP_TOKEN_ENABLE, &(enable)}, {parse_empty, SP_TOKEN_DISABLE, &(disable)}, + {parse_str, SP_TOKEN_UPLOAD_SCRIPT, &(cfg->script)}, + {parse_empty, SP_TOKEN_SIMULATION, &(cfg->simulation)}, + {parse_empty, SP_TOKEN_SIM, &(cfg->simulation)}, {0, 0, 0}}; - int ret = parse_keywords(sp_config_funcs_upload_validation, line); - - if (0 != ret) { - return ret; - } + SP_PROCESS_CONFIG_KEYWORDS_ERR(); + SP_SET_ENABLE_DISABLE(enable, disable, cfg->enable); - SP_SET_ENABLE_DISABLE(enable, disable, SNUFFLEUPAGUS_G(config).config_upload_validation->enable); - - zend_string const *script = - SNUFFLEUPAGUS_G(config).config_upload_validation->script; - - if (!script) { - sp_log_err("config", - "The `script` directive is mandatory in '%s' on line %zu", line, - sp_line_no); - return -1; - } else if (-1 == access(ZSTR_VAL(script), F_OK)) { - sp_log_err("config", "The `script` (%s) doesn't exist on line %zu", - ZSTR_VAL(script), sp_line_no); - return -1; - } else if (-1 == access(ZSTR_VAL(script), X_OK)) { - sp_log_err("config", "The `script` (%s) isn't executable on line %zu", - ZSTR_VAL(script), sp_line_no); - return -1; + if (!cfg->script) { + sp_log_err("config", "The `script` directive is mandatory in '.%s' on line %zu", token, parsed_rule->lineno); + return SP_PARSER_ERROR; + } else if (-1 == access(ZSTR_VAL(cfg->script), F_OK)) { + sp_log_err("config", "The `script` (%s) doesn't exist on line %zu", ZSTR_VAL(cfg->script), parsed_rule->lineno); + return SP_PARSER_ERROR; + } else if (-1 == access(ZSTR_VAL(cfg->script), X_OK)) { + sp_log_err("config", "The `script` (%s) isn't executable on line %zu", ZSTR_VAL(cfg->script), parsed_rule->lineno); + return SP_PARSER_ERROR; } - return ret; + return SP_PARSER_STOP; } -int parse_ini_protection(char *line) { +SP_PARSE_FN(parse_ini_protection) { bool disable = false, enable = false; bool rw = false, ro = false; // rw is ignored, but declaring .policy_rw is valid for readability - sp_config_ini *cfg = SNUFFLEUPAGUS_G(config).config_ini; - sp_config_functions sp_config_ini_protection[] = { - {parse_empty, SP_TOKEN_ENABLE, &(enable)}, - {parse_empty, SP_TOKEN_DISABLE, &(disable)}, - {parse_empty, SP_TOKEN_SIMULATION, &cfg->simulation}, - {parse_empty, ".policy_readonly(", &ro}, - {parse_empty, ".policy_ro(", &ro}, - {parse_empty, ".policy_readwrite(", &rw}, - {parse_empty, ".policy_rw(", &rw}, - {parse_empty, ".policy_silent_ro(", &cfg->policy_silent_ro}, - {parse_empty, ".policy_silent_fail(", &cfg->policy_silent_fail}, - {parse_empty, ".policy_no_log(", &cfg->policy_silent_fail}, - {parse_empty, ".policy_drop(", &cfg->policy_drop}, + sp_config_ini *cfg = (sp_config_ini*)retval; + sp_config_keyword config_keywords[] = { + {parse_empty, "enable", &(enable)}, + {parse_empty, "disable", &(disable)}, + {parse_empty, "simulation", &cfg->simulation}, + {parse_empty, "sim", &cfg->simulation}, + {parse_empty, "policy_readonly", &ro}, + {parse_empty, "policy_ro", &ro}, + {parse_empty, "policy_readwrite", &rw}, + {parse_empty, "policy_rw", &rw}, + {parse_empty, "policy_silent_ro", &cfg->policy_silent_ro}, + {parse_empty, "policy_silent_fail", &cfg->policy_silent_fail}, + {parse_empty, "policy_no_log", &cfg->policy_silent_fail}, + {parse_empty, "policy_drop", &cfg->policy_drop}, {0, 0, 0}}; - int ret = parse_keywords(sp_config_ini_protection, line); - if (ret) { return ret; } + SP_PROCESS_CONFIG_KEYWORDS_ERR(); SP_SET_ENABLE_DISABLE(enable, disable, cfg->enable); if (ro && rw) { - sp_log_err("config", "rule cannot be both read-write and read-only on line %zu", sp_line_no); - return -1; + sp_log_err("config", "rule cannot be both read-write and read-only on line %zu", parsed_rule->lineno); + return SP_PARSER_ERROR; } cfg->policy_readonly = ro; if (cfg->policy_silent_fail && cfg->policy_drop) { - sp_log_err("config", "policy cannot be drop and silent at the same time on line %zu", sp_line_no); - return -1; + sp_log_err("config", "policy cannot be drop and silent at the same time on line %zu", parsed_rule->lineno); + return SP_PARSER_ERROR; } - return ret; + return SP_PARSER_STOP; } -int parse_ini_entry(char *line) { +SP_PARSE_FN(parse_ini_entry) { sp_ini_entry *entry = pecalloc(sizeof(sp_ini_entry), 1, 1); bool rw = false, ro = false; - sp_config_functions sp_config_ini_protection[] = { - {parse_empty, SP_TOKEN_SIMULATION, &entry->simulation}, - {parse_str, ".key(", &entry->key}, - {parse_str, ".msg(", &entry->msg}, - {parse_str, ".set(", &entry->set}, - {parse_str, ".min(", &entry->min}, - {parse_str, ".max(", &entry->max}, - {parse_regexp, ".regexp(", &entry->regexp}, - {parse_empty, ".readonly(", &ro}, - {parse_empty, ".ro(", &ro}, - {parse_empty, ".readwrite(", &rw}, - {parse_empty, ".rw(", &rw}, - {parse_empty, ".drop(", &entry->drop}, - {parse_empty, ".allow_null(", &entry->allow_null}, + sp_config_keyword config_keywords[] = { + {parse_empty, "simulation", &entry->simulation}, + {parse_empty, "sim", &entry->simulation}, + {parse_str, "key", &entry->key}, + {parse_str, "msg", &entry->msg}, + {parse_str, "set", &entry->set}, + {parse_str, "min", &entry->min}, + {parse_str, "max", &entry->max}, + {parse_regexp, "regexp", &entry->regexp}, + {parse_empty, "readonly", &ro}, + {parse_empty, "ro", &ro}, + {parse_empty, "readwrite", &rw}, + {parse_empty, "rw", &rw}, + {parse_empty, "drop", &entry->drop}, + {parse_empty, "allow_null", &entry->allow_null}, {0, 0, 0}}; - int ret = parse_keywords(sp_config_ini_protection, line); - if (ret) { goto err; } + SP_PROCESS_CONFIG_KEYWORDS(goto err); - if (!entry->key) { - sp_log_err("config", "A .key() must be provided on line %zu", sp_line_no); - ret = -1; goto err; + if (!entry->key) { + sp_log_err("config", "A .key() must be provided on line %zu", parsed_rule->lineno); + goto err; } if (ro && rw) { - sp_log_err("config", "rule cannot be both read-write and read-only on line %zu", sp_line_no); - ret = -1; goto err; + sp_log_err("config", "rule cannot be both read-write and read-only on line %zu", parsed_rule->lineno); + goto err; } entry->access = ro - rw; zend_hash_add_ptr(SNUFFLEUPAGUS_G(config).config_ini->entries, entry->key, entry); - return ret; + return SP_PARSER_STOP; err: if (entry) { sp_free_ini_entry(entry); pefree(entry, 1); } - return ret; + return SP_PARSER_ERROR; } \ No newline at end of file diff --git a/src/sp_config_keywords.h b/src/sp_config_keywords.h index b90c06c..01eb0d1 100644 --- a/src/sp_config_keywords.h +++ b/src/sp_config_keywords.h @@ -2,23 +2,18 @@ #define SP_CONFIG_KEYWORDS_H #include "php_snuffleupagus.h" -int parse_random(char *line); -int parse_disable_xxe(char *line); -int parse_auto_cookie_secure(char *line); -int parse_global_strict(char *line); -int parse_global(char *line); -int parse_cookie(char *line); -int parse_unserialize(char *line); -int parse_readonly_exec(char *line); -int parse_disabled_functions(char *line); -int parse_upload_validation(char *line); -int parse_eval_blacklist(char *line); -int parse_eval_whitelist(char *line); -int parse_session(char *line); -int parse_sloppy_comparison(char *line); -int parse_wrapper_whitelist(char *line); -int parse_log_media(char *line); -int parse_ini_protection(char *line); -int parse_ini_entry(char *line); +SP_PARSE_FN(parse_enable); +SP_PARSE_FN(parse_global); +SP_PARSE_FN(parse_cookie); +SP_PARSE_FN(parse_unserialize); +SP_PARSE_FN(parse_readonly_exec); +SP_PARSE_FN(parse_disabled_functions); +SP_PARSE_FN(parse_upload_validation); +SP_PARSE_FN(parse_eval_filter_conf); +SP_PARSE_FN(parse_session); +SP_PARSE_FN(parse_wrapper_whitelist); +SP_PARSE_FN(parse_log_media); +SP_PARSE_FN(parse_ini_protection); +SP_PARSE_FN(parse_ini_entry); #endif // __SP_CONFIG_KEYWORDS_H diff --git a/src/sp_config_scanner.h b/src/sp_config_scanner.h new file mode 100644 index 0000000..3284713 --- /dev/null +++ b/src/sp_config_scanner.h @@ -0,0 +1,25 @@ + +#ifndef SP_CONFIG_SCANNER_H +#define SP_CONFIG_SCANNER_H + +typedef enum { + SP_ARGTYPE_UNKNOWN = 0, + SP_ARGTYPE_NONE, + SP_ARGTYPE_EMPTY, + SP_ARGTYPE_STR +} sp_argtype; + +typedef struct { + char *kw; // keyword points directly to the parsed input text and as such is not null-terminated + size_t kwlen; + char *arg; // optional argument / can be not null terminated + size_t arglen; + sp_argtype argtype; + long lineno; +} sp_parsed_keyword; + +zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_keyword*)); +zend_string *sp_get_arg_string(sp_parsed_keyword *kw); +zend_string *sp_get_textual_representation(sp_parsed_keyword *parsed_rule); + +#endif \ No newline at end of file diff --git a/src/sp_config_scanner.re b/src/sp_config_scanner.re new file mode 100644 index 0000000..075c343 --- /dev/null +++ b/src/sp_config_scanner.re @@ -0,0 +1,139 @@ +#include "php_snuffleupagus.h" + +/*!types:re2c*/ + +#define cs_error_log(fmt, ...) sp_log_err("config", fmt, ##__VA_ARGS__) + +zend_string *sp_get_arg_string(sp_parsed_keyword *kw) { + if (!kw || !kw->arg) { + return NULL; + } + zend_string *ret = zend_string_init(kw->arg, kw->arglen, 1); + char *pin, *pout; + pin = pout = ZSTR_VAL(ret); + char *pend = pin + ZSTR_LEN(ret); + + while (pin < pend) { + if (*pin == '\\') { + pin++; + } + *pout = *pin; + pin++; pout++; + } + + if (pin != pout) { + size_t len = pout - ZSTR_VAL(ret); + ret = zend_string_truncate(ret, len, 1); + ZSTR_VAL(ret)[len] = 0; + } + + return ret; +} + +zend_string *sp_get_textual_representation(sp_parsed_keyword *parsed_rule) { + // a rule is "sp.keyword...keyword(arg);\0" + size_t len = 3; // sp + ; + sp_parsed_keyword *kw; + for (kw = parsed_rule; kw->kw; kw++) { + len++; // . + len += kw->kwlen; + if (kw->argtype == SP_ARGTYPE_EMPTY) { + len += 2; // () + } else if (kw->argtype == SP_ARGTYPE_STR) { + len += 4; + len += kw->arglen; + } + } + zend_string *ret = zend_string_alloc(len, 1); + char *ptr = ZSTR_VAL(ret); + memcpy(ptr, "sp", 2); ptr += 2; + for (kw = parsed_rule; kw->kw; kw++) { + *ptr++ = '.'; + memcpy(ptr, kw->kw, kw->kwlen); ptr += kw->kwlen; + if (kw->argtype == SP_ARGTYPE_EMPTY || kw->argtype == SP_ARGTYPE_STR || kw->argtype == SP_ARGTYPE_UNKNOWN) { + *ptr++ = '('; + } + if (kw->argtype == SP_ARGTYPE_STR && kw->arg) { + *ptr++ = '"'; + memcpy(ptr, kw->arg, kw->arglen); ptr += kw->arglen; + *ptr++ = '"'; + } + if (kw->argtype == SP_ARGTYPE_EMPTY || kw->argtype == SP_ARGTYPE_STR || kw->argtype == SP_ARGTYPE_UNKNOWN) { + *ptr++ = ')'; + } + } + *ptr++ = ';'; + *ptr = 0; + return ret; +} + +zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_keyword*)) +{ + const char *YYCURSOR = data; + const char *YYMARKER, *t1, *t2, *t3, *t4; + /*!stags:re2c format = 'const char *@@;\n'; */ + + const int max_keywords = 16; + sp_parsed_keyword parsed_rule[max_keywords+1]; + int kw_i = 0; + + int cond = yycinit; + long lineno = 1; + + /*!re2c + re2c:define:YYCTYPE = char; + // re2c:define:YYCURSOR = data; + re2c:yyfill:enable = 0; + re2c:flags:tags = 1; + re2c:api:style = free-form; + re2c:define:YYGETCONDITION = "cond"; + re2c:define:YYSETCONDITION = "cond = @@;"; + + end = "\x00"; + nl = "\r"?"\n"; + ws = [ \t]; + keyword = [a-zA-Z_][a-zA-Z0-9_]*; + string = "\"" ("\\\"" | [^"\r\n])* "\""; + + * { cs_error_log("Parser error on line %d", lineno); return FAILURE; } + ws+ { goto yyc_init; } + [;#] .* { goto yyc_init; } + nl { lineno++; goto yyc_init; } + "sp" { kw_i = 0; goto yyc_rule; } + end { return SUCCESS; } + + ws+ { goto yyc_rule; } + nl / ( nl | ws )* "." { lineno++; goto yyc_rule; } + "." @t1 keyword @t2 ( "(" @t3 string? @t4 ")" )? { + if (kw_i == max_keywords) { + cs_error_log("Too many keywords in rule (more than %d) on line %d", max_keywords, lineno); + return FAILURE; + } + sp_parsed_keyword kw = {.kw = (char*)t1, .kwlen = t2-t1, .arg = (char*)t3, .arglen = t4-t3, .argtype = SP_ARGTYPE_UNKNOWN, .lineno = lineno}; + if (t3 && t4) { + if (t3 == t4) { + kw.argtype = SP_ARGTYPE_EMPTY; + } else if (t4-t2 >= 2) { + kw.arg = (char*)t3 + 1; + kw.arglen = t4 - t3 - 2; + kw.argtype = SP_ARGTYPE_STR; + } + } else { + kw.argtype = SP_ARGTYPE_NONE; + } + parsed_rule[kw_i++] = kw; + goto yyc_rule; + } + ";" { + end_of_rule: + parsed_rule[kw_i++] = (sp_parsed_keyword){0, 0, 0, 0, 0, 0}; + if (process_rule && process_rule(parsed_rule) != SUCCESS) { + return FAILURE; + } + goto yyc_init; + } + * { goto end_of_rule; } + + */ + return FAILURE; +} \ No newline at end of file diff --git a/src/sp_config_utils.c b/src/sp_config_utils.c index bc7b405..e93ef31 100644 --- a/src/sp_config_utils.c +++ b/src/sp_config_utils.c @@ -1,108 +1,5 @@ #include "php_snuffleupagus.h" -int parse_keywords(sp_config_functions *funcs, char *line) { - int value_len = 0; - const char *original_line = line; - for (size_t i = 0; funcs[i].func; i++) { - if (!strncmp(funcs[i].token, line, strlen(funcs[i].token))) { - line += strlen(funcs[i].token); - value_len = funcs[i].func(line, funcs[i].token, funcs[i].retval) + 1; - if (value_len == 0) { // bad parameter - return -1; - } - line += value_len; - i = -1; // we start the loop again - } - } - while (*line == ';' || *line == '\t' || *line == ' ') { - line++; - } - - if (*line == '#') { - return 0; - } - - if (*line) { - sp_log_err("config", "Trailing chars '%s' at the end of '%s' on line %zu", - line, original_line, sp_line_no); - return -1; - } - return 0; -} - -zend_string *get_param(size_t *consumed, char *restrict line, sp_type type, - const char *restrict keyword) { - enum { IN_ESCAPE, NONE } state = NONE; - char *original_line = line; - size_t j = 0; - - zend_string *ret = NULL; - if (NULL == line || '\0' == *line) { - goto err; - } - - ret = zend_string_alloc(strlen(line) + 1, 1); - - /* The first char of a string is always '"', since they MUST be quoted. */ - if ('"' == *line) { - line++; - } else { - goto err; - } - - for (size_t i = 0; line[i] && j < strlen(original_line) - 2; i++) { - switch (line[i]) { - case '"': - /* A double quote at this point is either: - - at the very end of the string. - - escaped - */ - if ((state == NONE) && (line[i + 1] == SP_TOKEN_END_PARAM)) { - /* The `+2` if for - 1. the terminal double-quote - 2. the SP_TOKEN_END_PARAM - */ - *consumed = i + 2; - // Make sure that the string we return is the right size, - // as it can be smaller than strlen(line) - ret = zend_string_truncate(ret, j, 1); - // truncate does not add a \0 - ZSTR_VAL(ret)[ZSTR_LEN(ret)] = 0; - return ret; - } else if (state == IN_ESCAPE) { - break; // we're on an escped double quote - } else { - goto err; - } - case '\\': - if (state == NONE) { - state = IN_ESCAPE; - continue; - } - default: - break; - } - if (state == IN_ESCAPE) { - state = NONE; - } - ZSTR_VAL(ret)[j++] = line[i]; - } -err: - if (0 == j) { - sp_log_err("error", "A valid string as parameter is expected on line %zu", - sp_line_no); - } else { - sp_log_err("error", - "There is an issue with the parsing of '%s': it doesn't look " - "like a valid string on line %zu", - original_line ? original_line : "NULL", sp_line_no); - } - line = NULL; - if (ret) { - zend_string_release(ret); - } - return NULL; -} sp_list_node *parse_functions_list(char *value) { static const char *sep = ">"; diff --git a/src/sp_config_utils.h b/src/sp_config_utils.h index a63cadc..64817a0 100644 --- a/src/sp_config_utils.h +++ b/src/sp_config_utils.h @@ -1,9 +1,6 @@ #ifndef SP_CONFIG_UTILS #define SP_CONFIG_UTILS -int parse_keywords(sp_config_functions *, char *); -zend_string *get_param(size_t *, char *restrict, sp_type, const char *restrict); -int array_to_list(char **, sp_list_node **); sp_list_node *parse_functions_list(char *value); #endif /* SP_CONFIG_UTILS */ diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c index 84d8acf..ebb7d3f 100644 --- a/src/sp_disabled_functions.c +++ b/src/sp_disabled_functions.c @@ -69,28 +69,22 @@ static bool is_functions_list_matching(zend_execute_data* execute_data, return false; } -static bool is_local_var_matching( - zend_execute_data* execute_data, - const sp_disabled_function* const config_node) { +static bool is_local_var_matching(zend_execute_data* execute_data, const sp_disabled_function* const config_node) { zval* var_value = {0}; var_value = sp_get_var_value(execute_data, config_node->var, false); if (var_value) { if (Z_TYPE_P(var_value) == IS_ARRAY) { if (config_node->key || config_node->r_key) { - if (sp_match_array_key(var_value, config_node->key, - config_node->r_key)) { + if (sp_match_array_key(var_value, config_node->key, config_node->r_key)) { return true; } - } else if (sp_match_array_value(var_value, config_node->value, - config_node->r_value)) { + } else if (sp_match_array_value(var_value, config_node->value, config_node->r_value)) { return true; } } else { - zend_string const* const var_value_str = - sp_zval_to_zend_string(var_value); - bool match = sp_match_value(var_value_str, config_node->value, - config_node->r_value); + zend_string const* const var_value_str = sp_zval_to_zend_string(var_value); + bool match = sp_match_value(var_value_str, config_node->value, config_node->r_value); if (true == match) { return true; @@ -555,24 +549,19 @@ ZEND_FUNCTION(eval_blacklist_callback) { zend_string_release(tmp); if (SNUFFLEUPAGUS_G(in_eval) > 0) { - zend_string* filename = get_eval_filename(zend_get_executed_filename()); - const int line_number = zend_get_executed_lineno(TSRMLS_C); + // zend_string* filename = get_eval_filename(zend_get_executed_filename()); + // const int line_number = zend_get_executed_lineno(TSRMLS_C); const sp_config_eval* config_eval = SNUFFLEUPAGUS_G(config).config_eval; if (config_eval->dump) { - sp_log_request(config_eval->dump, config_eval->textual_representation, - SP_TOKEN_EVAL_BLACKLIST); + sp_log_request(config_eval->dump, config_eval->textual_representation); } if (config_eval->simulation) { - sp_log_simulation("eval", - "A call to %s was tried in eval, in %s:%d, logging it.", - current_function_name, ZSTR_VAL(filename), line_number); + sp_log_simulation("eval", "A call to '%s' was tried in eval. logging it.", current_function_name); } else { - sp_log_drop("eval", - "A call to %s was tried in eval, in %s:%d, dropping it.", - current_function_name, ZSTR_VAL(filename), line_number); + sp_log_drop("eval", "A call to '%s' was tried in eval. dropping it.", current_function_name); } - efree(filename); + // efree(filename); } whitelisted: diff --git a/src/sp_execute.c b/src/sp_execute.c index 7d078b0..8795e5f 100644 --- a/src/sp_execute.c +++ b/src/sp_execute.c @@ -14,8 +14,7 @@ ZEND_COLD static inline void terminate_if_writable(const char *filename) { if (0 == access(filename, W_OK)) { if (config_ro_exec->dump) { sp_log_request(config_ro_exec->dump, - config_ro_exec->textual_representation, - SP_TOKEN_READONLY_EXEC); + config_ro_exec->textual_representation); } if (true == config_ro_exec->simulation) { sp_log_simulation("readonly_exec", @@ -75,8 +74,7 @@ is_in_eval_and_whitelisted(const zend_execute_data *execute_data) { if (EXPECTED(NULL != current_function)) { if (UNEXPECTED(false == check_is_in_eval_whitelist(current_function))) { if (config_eval->dump) { - sp_log_request(config_eval->dump, config_eval->textual_representation, - SP_TOKEN_EVAL_WHITELIST); + sp_log_request(config_eval->dump, config_eval->textual_representation); } if (config_eval->simulation) { sp_log_simulation( diff --git a/src/sp_network_utils.c b/src/sp_network_utils.c index 5b4fd95..0a26254 100644 --- a/src/sp_network_utils.c +++ b/src/sp_network_utils.c @@ -85,9 +85,7 @@ int get_ip_and_cidr(char *ip, sp_cidr *cidr) { char *mask = strchr(ip, '/'); if (NULL == mask) { - sp_log_err( - "config", - "'%s' isn't a valid network mask, it seems that you forgot a '/'.", ip); + sp_log_err("config", "'%s' isn't a valid network mask, it seems that you forgot a '/'.", ip); return -1; } @@ -117,7 +115,7 @@ int get_ip_and_cidr(char *ip, sp_cidr *cidr) { ip[mask - ip] = '/'; if (cidr->ip_version < 0) { - sp_log_err("cidr_match", "Weird ip (%s) family", ip); + sp_log_err("config", "Weird ip (%s) family", ip); return -1; } diff --git a/src/sp_pcre_compat.c b/src/sp_pcre_compat.c index 2b9f08d..657e650 100644 --- a/src/sp_pcre_compat.c +++ b/src/sp_pcre_compat.c @@ -24,8 +24,7 @@ sp_pcre* sp_pcre_compile(const char* const pattern) { #endif if (NULL == ret) { - sp_log_err("config", "Failed to compile '%s': %s on line %zu.", pattern, - pcre_error, sp_line_no); + sp_log_err("config", "Failed to compile '%s': %s.", pattern, pcre_error); } return ret; } diff --git a/src/sp_unserialize.c b/src/sp_unserialize.c index 06636ad..82b2cef 100644 --- a/src/sp_unserialize.c +++ b/src/sp_unserialize.c @@ -89,8 +89,7 @@ PHP_FUNCTION(sp_unserialize) { } else { if (config_unserialize->dump) { sp_log_request(config_unserialize->dump, - config_unserialize->textual_representation, - SP_TOKEN_UNSERIALIZE_HMAC); + config_unserialize->textual_representation); } if (true == config_unserialize->simulation) { sp_log_simulation("unserialize", "Invalid HMAC for %s", serialized_str); diff --git a/src/sp_utils.c b/src/sp_utils.c index 949d6ba..c4209de 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c @@ -123,9 +123,7 @@ static int construct_filename(char* filename, return 0; } -int sp_log_request(const zend_string* restrict folder, - const zend_string* restrict text_repr, - char const* const from) { +int sp_log_request(const zend_string* restrict folder, const zend_string* restrict text_repr) { FILE* file; const char* current_filename = zend_get_executed_filename(TSRMLS_C); const int current_line = zend_get_executed_lineno(TSRMLS_C); @@ -146,7 +144,7 @@ int sp_log_request(const zend_string* restrict folder, return -1; } - fprintf(file, "RULE: sp%s%s\n", from, ZSTR_VAL(text_repr)); + fprintf(file, "RULE: %s\n", ZSTR_VAL(text_repr)); fprintf(file, "FILE: %s:%d\n", current_filename, current_line); @@ -285,8 +283,7 @@ void sp_log_disable(const char* restrict path, const char* restrict arg_name, const int sim = config_node->simulation; if (dump) { - sp_log_request(config_node->dump, config_node->textual_representation, - SP_TOKEN_DISABLE_FUNC); + sp_log_request(config_node->dump, config_node->textual_representation); } if (arg_name) { char* char_repr = NULL; @@ -329,8 +326,7 @@ void sp_log_disable_ret(const char* restrict path, char* char_repr = NULL; if (dump) { - sp_log_request(dump, config_node->textual_representation, - SP_TOKEN_DISABLE_FUNC); + sp_log_request(dump, config_node->textual_representation); } if (ret_value) { char_repr = zend_string_to_char(ret_value); @@ -479,7 +475,6 @@ void unhook_functions(HashTable *ht) { bool check_is_in_eval_whitelist(const zend_string* const function_name) { const sp_list_node* it = SNUFFLEUPAGUS_G(config).config_eval->whitelist; - if (!it) { return false; } diff --git a/src/sp_utils.h b/src/sp_utils.h index c0ddbe4..ef626a3 100644 --- a/src/sp_utils.h +++ b/src/sp_utils.h @@ -85,9 +85,7 @@ bool hook_function(const char *, HashTable *, zif_handler); void unhook_functions(HashTable *ht); int hook_regexp(const sp_pcre *, HashTable *, zif_handler); bool check_is_in_eval_whitelist(const zend_string *const function_name); -int sp_log_request(const zend_string *restrict folder, - const zend_string *restrict text_repr, - char const *const from); +int sp_log_request(const zend_string *restrict folder, const zend_string *restrict text_repr); bool sp_zend_string_equals(const zend_string *s1, const zend_string *s2); #endif /* SP_UTILS_H */ diff --git a/src/tests/broken_configuration/encrypt_regexp_cookies_bad_regexp.phpt b/src/tests/broken_configuration/encrypt_regexp_cookies_bad_regexp.phpt index 7a8c909..5383df6 100644 --- a/src/tests/broken_configuration/encrypt_regexp_cookies_bad_regexp.phpt +++ b/src/tests/broken_configuration/encrypt_regexp_cookies_bad_regexp.phpt @@ -17,6 +17,6 @@ EOF; --EXPECT-- Fatal error: [snuffleupagus][127.0.0.1][config][log] Invalid configuration file in Unknown on line 0 -Fatal error: [snuffleupagus][127.0.0.1][config][log] Failed to compile '^super_co[a-z+$': missing terminating ] for character class on line 2. in Unknown on line 0 +Fatal error: [snuffleupagus][127.0.0.1][config][log] Failed to compile '^super_co[a-z+$': missing terminating ] for character class. in Unknown on line 0 -Fatal error: [snuffleupagus][127.0.0.1][config][log] '.name_r()' is expecting a valid regexp, and not '"^super_co[a-z+$"' on line 2 in Unknown on line 0 +Fatal error: [snuffleupagus][127.0.0.1][config][log] Invalid regexp '^super_co[a-z+$' for '.name_r()' on line 2 in Unknown on line 0 diff --git a/src/tests/broken_configuration_php8/broken_conf.phpt b/src/tests/broken_configuration_php8/broken_conf.phpt index 7dde7d6..9a5a5ab 100644 --- a/src/tests/broken_configuration_php8/broken_conf.phpt +++ b/src/tests/broken_configuration_php8/broken_conf.phpt @@ -7,8 +7,7 @@ Broken configuration sp.configuration_file={PWD}/config/broken_conf.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration prefix for 'this is a broken line' on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Parser error on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf2.phpt b/src/tests/broken_configuration_php8/broken_conf2.phpt index bf337b4..94ebc01 100644 --- a/src/tests/broken_configuration_php8/broken_conf2.phpt +++ b/src/tests/broken_configuration_php8/broken_conf2.phpt @@ -7,8 +7,7 @@ Broken configuration sp.configuration_file={PWD}/config/broken_conf2.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration section 'sp.wrong' on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Unexpected keyword 'wrong' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_allow_broken_disabled.phpt b/src/tests/broken_configuration_php8/broken_conf_allow_broken_disabled.phpt index 9dd0c66..ad3aa08 100644 --- a/src/tests/broken_configuration_php8/broken_conf_allow_broken_disabled.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_allow_broken_disabled.phpt @@ -12,7 +12,7 @@ echo 1337; ?> --EXPECT-- -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration prefix for 'this is a broken line' on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Parser error on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_allow_broken_enabled.phpt b/src/tests/broken_configuration_php8/broken_conf_allow_broken_enabled.phpt index eccc8a8..0f71408 100644 --- a/src/tests/broken_configuration_php8/broken_conf_allow_broken_enabled.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_allow_broken_enabled.phpt @@ -12,5 +12,5 @@ echo 1337; ?> --EXPECT-- -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration prefix for 'this is a broken line' on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Parser error on line 1 in Unknown on line 0 1337 diff --git a/src/tests/broken_configuration_php8/broken_conf_config_regexp.phpt b/src/tests/broken_configuration_php8/broken_conf_config_regexp.phpt index 76ef208..c4eec17 100644 --- a/src/tests/broken_configuration_php8/broken_conf_config_regexp.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_config_regexp.phpt @@ -7,10 +7,9 @@ Broken configuration sp.configuration_file={PWD}/config/broken_config_regexp.ini --FILE-- --EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][config][log] Failed to compile '*.': quantifier does not follow a repeatable item. in Unknown on line 0 -Fatal error: [snuffleupagus][0.0.0.0][config][log] Failed to compile '*.': %s on line 1. in Unknown on line 0 - -Fatal error: [snuffleupagus][0.0.0.0][config][log] '.filename_r()' is expecting a valid regexp, and not '"*."' on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid regexp '*.' for '.filename_r()' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_config_regexp_no_closing_paren.phpt b/src/tests/broken_configuration_php8/broken_conf_config_regexp_no_closing_paren.phpt index 5bdca06..2629ba5 100644 --- a/src/tests/broken_configuration_php8/broken_conf_config_regexp_no_closing_paren.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_config_regexp_no_closing_paren.phpt @@ -7,10 +7,7 @@ Broken configuration - regexp without a closing parenthesis sp.configuration_file={PWD}/config/broken_config_regexp_no_closing_paren.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][error][log] There is an issue with the parsing of '"*."': it doesn't look like a valid string on line 1 in Unknown on line 0 - -Fatal error: [snuffleupagus][0.0.0.0][config][log] '.filename_r()' is expecting a valid regexp, and not '"*."' on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Missing argument to keyword 'filename_r' - it should be 'filename_r("...")' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_cookie_encryption_without_encryption_key.phpt b/src/tests/broken_configuration_php8/broken_conf_cookie_encryption_without_encryption_key.phpt index 0447320..6213041 100644 --- a/src/tests/broken_configuration_php8/broken_conf_cookie_encryption_without_encryption_key.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_cookie_encryption_without_encryption_key.phpt @@ -7,8 +7,7 @@ Broken configuration - encrypted cookie without encryption key sp.configuration_file={PWD}/config/broken_conf_cookie_encryption_without_encryption_key.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] You're trying to use the cookie encryption featureon line 2 without having set the `.encryption_key` option in`sp.global`: please set it first in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] You're trying to use the cookie encryption feature on line 2 without having set the `.secret_key` option in `sp.global`: please set it first in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_cookie_encryption_without_env_var.phpt b/src/tests/broken_configuration_php8/broken_conf_cookie_encryption_without_env_var.phpt index 204430d..25371dd 100644 --- a/src/tests/broken_configuration_php8/broken_conf_cookie_encryption_without_env_var.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_cookie_encryption_without_env_var.phpt @@ -7,8 +7,7 @@ Broken configuration - encrypted cookie with without cookie env var sp.configuration_file={PWD}/config/broken_conf_cookie_encryption_without_env_var.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] You're trying to use the cookie encryption featureon line 2 without having set the `.cookie_env_var` option in`sp.global`: please set it first in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] You're trying to use the cookie encryption feature on line 2 without having set the `.cookie_env_var` option in`sp.global`: please set it first in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_eval.phpt b/src/tests/broken_configuration_php8/broken_conf_eval.phpt index 1a6ad4d..f45aabf 100644 --- a/src/tests/broken_configuration_php8/broken_conf_eval.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_eval.phpt @@ -8,7 +8,7 @@ sp.configuration_file={PWD}/config/broken_conf_eval.ini --FILE-- --EXPECT-- -Fatal error: [snuffleupagus][0.0.0.0][error][log] There is an issue with the parsing of '"cos,sin': it doesn't look like a valid string on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Missing argument to keyword 'list' - it should be 'list("...")' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_expecting_bool.phpt b/src/tests/broken_configuration_php8/broken_conf_expecting_bool.phpt index 682a4f5..419d687 100644 --- a/src/tests/broken_configuration_php8/broken_conf_expecting_bool.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_expecting_bool.phpt @@ -7,8 +7,7 @@ Bad boolean value in configuration sp.configuration_file={PWD}/config/broken_conf_expecting_bool.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Trailing chars '337);' at the end of '.enable(1337);' on line 5 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Missing paranthesis for keyword 'enable' - it should be 'enable()' on line 5 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_invalid_cidr_value.phpt b/src/tests/broken_configuration_php8/broken_conf_invalid_cidr_value.phpt index dbe5414..31140dc 100644 --- a/src/tests/broken_configuration_php8/broken_conf_invalid_cidr_value.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_invalid_cidr_value.phpt @@ -8,10 +8,7 @@ Broken configuration, invalid cidr value sp.configuration_file={PWD}/config/broken_conf_invalid_cidr_value.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][error][log] A valid string as parameter is expected on line 1 in Unknown on line 0 - -Fatal error: [snuffleupagus][0.0.0.0][config][log] " doesn't contain a valid cidr on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Missing argument to keyword 'cidr' - it should be 'cidr("...")' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_invalid_filename.phpt b/src/tests/broken_configuration_php8/broken_conf_invalid_filename.phpt index cb78f85..da40235 100644 --- a/src/tests/broken_configuration_php8/broken_conf_invalid_filename.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_invalid_filename.phpt @@ -7,8 +7,7 @@ Broken configuration filename without absolute path sp.configuration_file={PWD}/config/broken_conf_invalid_filename.ini --FILE-- --EXPECTF-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line: 'sp.disabled_functions.function("sprintf").filename("wrong file name").drop();':'.filename' must be an absolute path or a phar archive on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line%a: '.filename' must be an absolute path or a phar archive on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_invalid_log_media.phpt b/src/tests/broken_configuration_php8/broken_conf_invalid_log_media.phpt index 68581b6..fda609d 100644 --- a/src/tests/broken_configuration_php8/broken_conf_invalid_log_media.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_invalid_log_media.phpt @@ -7,8 +7,7 @@ Broken configuration filename with improper log media sp.configuration_file={PWD}/config/broken_conf_invalid_log_media.ini --FILE-- --EXPECTF-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] .log_media() only supports 'syslog' or 'php', on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] .log_media() only supports 'syslog' or 'php' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_invalid_type.phpt b/src/tests/broken_configuration_php8/broken_conf_invalid_type.phpt index 188d610..9e35170 100644 --- a/src/tests/broken_configuration_php8/broken_conf_invalid_type.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_invalid_type.phpt @@ -7,8 +7,7 @@ Broken conf with wrong type sp.configuration_file={PWD}/config/broken_conf_invalid_type.ini --FILE-- --EXPECTF-- - -Fatal error: [snuffleupagus][0.0.0.0][error][log] There is an issue with the parsing of '"totally_wrong"_type")': it doesn't look like a valid string on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Missing argument to keyword 'ret_type' - it should be 'ret_type("...")' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_key_value.phpt b/src/tests/broken_configuration_php8/broken_conf_key_value.phpt index 24c60bc..909aae1 100644 --- a/src/tests/broken_configuration_php8/broken_conf_key_value.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_key_value.phpt @@ -6,8 +6,8 @@ Broken configuration --INI-- sp.configuration_file={PWD}/config/broken_conf_key_value.ini --FILE-- ---EXPECT-- -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line: 'sp.disabled_functions.function("system").var("").value("").key("").drop();': '.key' and '.value' are mutually exclusive on line 1 in Unknown on line 0 +--EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line%a: '.key' and '.value' are mutually exclusive on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_line_empty_string.phpt b/src/tests/broken_configuration_php8/broken_conf_line_empty_string.phpt index 2d370ac..5702f43 100644 --- a/src/tests/broken_configuration_php8/broken_conf_line_empty_string.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_line_empty_string.phpt @@ -7,8 +7,7 @@ Configuration line with an empty string sp.configuration_file={PWD}/config/broken_conf_line_empty_string.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][error][log] A valid string as parameter is expected on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Missing argument to keyword 'name' - it should be 'name("...")' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_line_no_closing.phpt b/src/tests/broken_configuration_php8/broken_conf_line_no_closing.phpt index d3c826f..1a0a392 100644 --- a/src/tests/broken_configuration_php8/broken_conf_line_no_closing.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_line_no_closing.phpt @@ -7,8 +7,7 @@ Configuration line without closing parenthese sp.configuration_file={PWD}/config/broken_conf_line_no_closing.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][error][log] There is an issue with the parsing of '"123"': it doesn't look like a valid string on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Missing argument to keyword 'name' - it should be 'name("...")' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_lots_of_quotes.phpt b/src/tests/broken_configuration_php8/broken_conf_lots_of_quotes.phpt index e599e62..27135ca 100644 --- a/src/tests/broken_configuration_php8/broken_conf_lots_of_quotes.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_lots_of_quotes.phpt @@ -7,8 +7,7 @@ Configuration line with too many quotes sp.configuration_file={PWD}/config/broken_conf_lots_of_quotes.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][error][log] There is an issue with the parsing of '"this\"is a weird\"\"\"cookie\"name"");': it doesn't look like a valid string on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Missing argument to keyword 'name' - it should be 'name("...")' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_missing_script.phpt b/src/tests/broken_configuration_php8/broken_conf_missing_script.phpt index 2ddb70f..bb44f15 100644 --- a/src/tests/broken_configuration_php8/broken_conf_missing_script.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_missing_script.phpt @@ -10,8 +10,7 @@ sp.configuration_file={PWD}/config/broken_conf_missing_script.ini echo 1; ?> --EXPECTF-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] The `script` directive is mandatory in '.enable();' on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] The `script` directive is mandatory in '.upload_validation' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive.phpt b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive.phpt index e362893..f331eee 100644 --- a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive.phpt @@ -6,9 +6,8 @@ Broken configuration --INI-- sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive.ini --FILE-- ---EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line: 'sp.disabled_functions.function("system").param("id").value("42").value_r("^id$").drop();': '.value' and '.value_r' are mutually exclusive on line 1 in Unknown on line 0 +--EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line%a: '.value' and '.value_r' are mutually exclusive on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive11.phpt b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive11.phpt index 39766e1..93fc581 100644 --- a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive11.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive11.phpt @@ -6,9 +6,8 @@ Broken configuration - ret and var are mutually exclusives --INI-- sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive11.ini --FILE-- ---EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line: 'sp.disabled_functions.function("strcmp").drop().ret("hip").var("hop");': '.ret' and '.var' are mutually exclusive on line 1 in Unknown on line 0 +--EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line for '%a': '.ret' and '.var' are mutually exclusive on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive12.phpt b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive12.phpt index ebca290..24162df 100644 --- a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive12.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive12.phpt @@ -6,9 +6,8 @@ Broken configuration - ret and value are mutually exclusive --INI-- sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive12.ini --FILE-- ---EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line: 'sp.disabled_functions.function("strcmp").drop().ret("hip").value("hop");': '.ret' and '.value' are mutually exclusive on line 1 in Unknown on line 0 +--EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line for '%a': '.ret' and '.value' are mutually exclusive on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive2.phpt b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive2.phpt index 52b36e0..35c4de1 100644 --- a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive2.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive2.phpt @@ -6,9 +6,8 @@ Broken configuration --INI-- sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive2.ini --FILE-- ---EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line: 'sp.disabled_functions.function("system").function_r("system").param("id").value("42").drop();': '.function' and '.function_r' are mutually exclusive on line 1 in Unknown on line 0 +--EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line%a: '.function' and '.function_r' are mutually exclusive on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive3.phpt b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive3.phpt index cf65e7d..fd6e0b4 100644 --- a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive3.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive3.phpt @@ -6,9 +6,8 @@ Broken configuration --INI-- sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive3.ini --FILE-- ---EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line: 'sp.disabled_functions.function("system").param("id").value("42").filename_r("^id$").filename("pouet.txt").drop();': '.filename' and '.filename_r' are mutually exclusive on line 1 in Unknown on line 0 +--EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line%a: '.filename' and '.filename_r' are mutually exclusive on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive4.phpt b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive4.phpt index 41dc60e..80370f6 100644 --- a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive4.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive4.phpt @@ -6,9 +6,9 @@ Broken configuration --INI-- sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive4.ini --FILE-- ---EXPECT-- +--EXPECTF-- -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line: 'sp.disabled_functions.function("system").param("id").value("42").param_r("^id$").drop();': '.param' and '.param_r' are mutually exclusive on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line%a: '.param' and '.param_r' are mutually exclusive on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive5.phpt b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive5.phpt index 9cab6cd..3087a17 100644 --- a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive5.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive5.phpt @@ -6,9 +6,9 @@ Broken configuration --INI-- sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive5.ini --FILE-- ---EXPECT-- +--EXPECTF-- -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line: 'sp.disabled_functions.function("system").ret("0").drop().ret_r("^0$");': '.ret' and '.ret_r' are mutually exclusive on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line%a: '.ret' and '.ret_r' are mutually exclusive on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive6.phpt b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive6.phpt index 406f818..2099a4b 100644 --- a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive6.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive6.phpt @@ -6,9 +6,8 @@ Broken configuration --INI-- sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive6.ini --FILE-- ---EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line: 'sp.disabled_functions.function("system").param("id").value("42").ret_r("^0$").drop();': '.ret' and '.param' are mutually exclusive on line 1 in Unknown on line 0 +--EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line for '%a': '.ret' and '.param' are mutually exclusive on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive7.phpt b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive7.phpt index ff7f415..f0b44da 100644 --- a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive7.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive7.phpt @@ -6,9 +6,8 @@ Broken configuration --INI-- sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive7.ini --FILE-- ---EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line: 'sp.disabled_functions.function("system").ret("0").drop().allow();': The rule must either be a `drop` or `allow` one on line 1 in Unknown on line 0 +--EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line: '%a': The rule must either be a `drop` or `allow` one on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive8.phpt b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive8.phpt index 6ccd508..8f6c246 100644 --- a/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive8.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_mutually_exclusive8.phpt @@ -6,9 +6,8 @@ Broken configuration --INI-- sp.configuration_file={PWD}/config/broken_conf_mutually_exclusive8.ini --FILE-- ---EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line: 'sp.disabled_functions.ret("0").drop();': must take a function name on line 1 in Unknown on line 0 +--EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration line: '%a': must take a function name on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_readonly_exec.phpt b/src/tests/broken_configuration_php8/broken_conf_readonly_exec.phpt index 7e74683..5107ede 100644 --- a/src/tests/broken_configuration_php8/broken_conf_readonly_exec.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_readonly_exec.phpt @@ -10,8 +10,7 @@ sp.configuration_file={PWD}/config/broken_conf_readonly_exec.ini echo 1; ?> --EXPECTF-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Trailing chars '234);' at the end of '.enable(1234);' on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Missing paranthesis for keyword 'enable' - it should be 'enable()' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_samesite.phpt b/src/tests/broken_configuration_php8/broken_conf_samesite.phpt index c905fd8..63075d0 100644 --- a/src/tests/broken_configuration_php8/broken_conf_samesite.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_samesite.phpt @@ -7,8 +7,7 @@ Bad config, invalid samesite type. sp.configuration_file={PWD}/config/broken_conf_cookie_samesite.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] nop is an invalid value to samesite (expected Lax or Strict) on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] 'nop' is an invalid value to samesite (expected Lax or Strict) on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_session_encryption.phpt b/src/tests/broken_configuration_php8/broken_conf_session_encryption.phpt index 886eb13..cc7369a 100644 --- a/src/tests/broken_configuration_php8/broken_conf_session_encryption.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_session_encryption.phpt @@ -7,8 +7,7 @@ Broken config, session encryption sp.configuration_file={PWD}/config/broken_conf_session_encryption.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Trailing chars 'nvalid value :/);' at the end of '.encrypt(invalid value :/);' on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Missing paranthesis for keyword 'encrypt' - it should be 'encrypt()' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_shown_in_phpinfo.phpt b/src/tests/broken_configuration_php8/broken_conf_shown_in_phpinfo.phpt index 2503943..23a8e53 100644 --- a/src/tests/broken_configuration_php8/broken_conf_shown_in_phpinfo.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_shown_in_phpinfo.phpt @@ -18,10 +18,9 @@ if (strstr($info, 'Valid config => no') !== FALSE) { } ?> --EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][config][log] Failed to compile '*.': quantifier does not follow a repeatable item. in Unknown on line 0 -Fatal error: [snuffleupagus][0.0.0.0][config][log] Failed to compile '*.': %s on line 1. in Unknown on line 0 - -Fatal error: [snuffleupagus][0.0.0.0][config][log] '.filename_r()' is expecting a valid regexp, and not '"*."' on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid regexp '*.' for '.filename_r()' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_truncated.phpt b/src/tests/broken_configuration_php8/broken_conf_truncated.phpt index 059dcac..ff821f4 100644 --- a/src/tests/broken_configuration_php8/broken_conf_truncated.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_truncated.phpt @@ -7,8 +7,7 @@ Bad boolean value in configuration sp.configuration_file={PWD}/config/config_broken_conf_truncated.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][error][log] A valid string as parameter is expected on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Missing argument to keyword 'param' - it should be 'param("...")' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_unserialize.phpt b/src/tests/broken_configuration_php8/broken_conf_unserialize.phpt index 327b622..5e6c28e 100644 --- a/src/tests/broken_configuration_php8/broken_conf_unserialize.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_unserialize.phpt @@ -9,9 +9,8 @@ sp.configuration_file={PWD}/config/broken_conf_unserialize.ini ---EXPECTF-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Trailing chars '234);' at the end of '.enable(1234);' on line 1 in Unknown on line 0 +--EXPECT-- +Fatal error: [snuffleupagus][0.0.0.0][config][log] Missing paranthesis for keyword 'enable' - it should be 'enable()' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_upload_validation.phpt b/src/tests/broken_configuration_php8/broken_conf_upload_validation.phpt index d022e3e..31afff9 100644 --- a/src/tests/broken_configuration_php8/broken_conf_upload_validation.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_upload_validation.phpt @@ -10,8 +10,7 @@ sp.configuration_file={PWD}/../broken_configuration/config/broken_conf_upload_va echo 1; ?> --EXPECTF-- - -Fatal error: [snuffleupagus][0.0.0.0][error][log] A valid string as parameter is expected on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Missing argument to keyword 'script' - it should be 'script("...")' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_weird_keyword.phpt b/src/tests/broken_configuration_php8/broken_conf_weird_keyword.phpt index 75c2e0e..6082f42 100644 --- a/src/tests/broken_configuration_php8/broken_conf_weird_keyword.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_weird_keyword.phpt @@ -7,8 +7,7 @@ Bad config, unknown keyword sp.configuration_file={PWD}/config/broken_conf_weird_keyword.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Trailing chars '.not_a_valid_keyword("test");' at the end of '.enable().not_a_valid_keyword("test");' on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Unexpected keyword 'not_a_valid_keyword' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_wrapper_whitelist.phpt b/src/tests/broken_configuration_php8/broken_conf_wrapper_whitelist.phpt index 0011a6e..1f2d9da 100644 --- a/src/tests/broken_configuration_php8/broken_conf_wrapper_whitelist.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_wrapper_whitelist.phpt @@ -11,8 +11,7 @@ sp.allow_broken_configuration=Off echo 1337; ?> --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Trailing chars '.invalid_param();' at the end of '.invalid_param();' on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Unexpected keyword 'invalid_param' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_conf_wrong_quotes.phpt b/src/tests/broken_configuration_php8/broken_conf_wrong_quotes.phpt index b073369..d3cf9e0 100644 --- a/src/tests/broken_configuration_php8/broken_conf_wrong_quotes.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_wrong_quotes.phpt @@ -7,8 +7,7 @@ Configuration line with too many quotes sp.configuration_file={PWD}/config/broken_conf_wrong_quotes.ini --FILE-- --EXPECT-- - -Fatal error: [snuffleupagus][0.0.0.0][error][log] There is an issue with the parsing of '"\)': it doesn't look like a valid string on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Missing argument to keyword 'name' - it should be 'name("...")' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/broken_regexp.phpt b/src/tests/broken_configuration_php8/broken_regexp.phpt index 877f801..7461d57 100644 --- a/src/tests/broken_configuration_php8/broken_regexp.phpt +++ b/src/tests/broken_configuration_php8/broken_regexp.phpt @@ -7,10 +7,9 @@ Broken regexp sp.configuration_file={PWD}/config/broken_regexp.ini --FILE-- --EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][config][log] Failed to compile '^$[': missing terminating ] for character class. in Unknown on line 0 -Fatal error: [snuffleupagus][0.0.0.0][config][log] Failed to compile '^$[': missing terminating ] for character class on line 1. in Unknown on line 0 - -Fatal error: [snuffleupagus][0.0.0.0][config][log] '.value_r()' is expecting a valid regexp, and not '"^$["' on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid regexp '^$[' for '.value_r()' on line 1 in Unknown on line 0 Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 Could not startup. diff --git a/src/tests/broken_configuration_php8/encrypt_regexp_cookies_bad_regexp.phpt b/src/tests/broken_configuration_php8/encrypt_regexp_cookies_bad_regexp.phpt index 7a8c909..5383df6 100644 --- a/src/tests/broken_configuration_php8/encrypt_regexp_cookies_bad_regexp.phpt +++ b/src/tests/broken_configuration_php8/encrypt_regexp_cookies_bad_regexp.phpt @@ -17,6 +17,6 @@ EOF; --EXPECT-- Fatal error: [snuffleupagus][127.0.0.1][config][log] Invalid configuration file in Unknown on line 0 -Fatal error: [snuffleupagus][127.0.0.1][config][log] Failed to compile '^super_co[a-z+$': missing terminating ] for character class on line 2. in Unknown on line 0 +Fatal error: [snuffleupagus][127.0.0.1][config][log] Failed to compile '^super_co[a-z+$': missing terminating ] for character class. in Unknown on line 0 -Fatal error: [snuffleupagus][127.0.0.1][config][log] '.name_r()' is expecting a valid regexp, and not '"^super_co[a-z+$"' on line 2 in Unknown on line 0 +Fatal error: [snuffleupagus][127.0.0.1][config][log] Invalid regexp '^super_co[a-z+$' for '.name_r()' on line 2 in Unknown on line 0 diff --git a/src/tests/cookies_encryption_warning/encrypt_cookies_no_env.phpt b/src/tests/cookies_encryption_warning/encrypt_cookies_no_env.phpt index 015c159..a01c352 100644 --- a/src/tests/cookies_encryption_warning/encrypt_cookies_no_env.phpt +++ b/src/tests/cookies_encryption_warning/encrypt_cookies_no_env.phpt @@ -18,4 +18,4 @@ EOF; --EXPECT-- Fatal error: [snuffleupagus][127.0.0.1][config][log] Invalid configuration file in Unknown on line 0 -Fatal error: [snuffleupagus][127.0.0.1][config][log] You're trying to use the cookie encryption featureon line 2 without having set the `.cookie_env_var` option in`sp.global`: please set it first in Unknown on line 0 +Fatal error: [snuffleupagus][127.0.0.1][config][log] You're trying to use the cookie encryption feature on line 2 without having set the `.cookie_env_var` option in`sp.global`: please set it first in Unknown on line 0 diff --git a/src/tests/cookies_encryption_warning/encrypt_cookies_no_key.phpt b/src/tests/cookies_encryption_warning/encrypt_cookies_no_key.phpt index 42f5509..c47389c 100644 --- a/src/tests/cookies_encryption_warning/encrypt_cookies_no_key.phpt +++ b/src/tests/cookies_encryption_warning/encrypt_cookies_no_key.phpt @@ -18,4 +18,4 @@ EOF; --EXPECT-- Fatal error: [snuffleupagus][127.0.0.1][config][log] Invalid configuration file in Unknown on line 0 -Fatal error: [snuffleupagus][127.0.0.1][config][log] You're trying to use the cookie encryption featureon line 2 without having set the `.encryption_key` option in`sp.global`: please set it first in Unknown on line 0 +Fatal error: [snuffleupagus][127.0.0.1][config][log] You're trying to use the cookie encryption feature on line 2 without having set the `.secret_key` option in `sp.global`: please set it first in Unknown on line 0 diff --git a/src/tests/cookies_encryption_warning/encrypt_regexp_cookies_no_env.phpt b/src/tests/cookies_encryption_warning/encrypt_regexp_cookies_no_env.phpt index 163cb26..1fe4074 100644 --- a/src/tests/cookies_encryption_warning/encrypt_regexp_cookies_no_env.phpt +++ b/src/tests/cookies_encryption_warning/encrypt_regexp_cookies_no_env.phpt @@ -18,4 +18,4 @@ EOF; --EXPECT-- Fatal error: [snuffleupagus][127.0.0.1][config][log] Invalid configuration file in Unknown on line 0 -Fatal error: [snuffleupagus][127.0.0.1][config][log] You're trying to use the cookie encryption featureon line 2 without having set the `.cookie_env_var` option in`sp.global`: please set it first in Unknown on line 0 +Fatal error: [snuffleupagus][127.0.0.1][config][log] You're trying to use the cookie encryption feature on line 2 without having set the `.cookie_env_var` option in`sp.global`: please set it first in Unknown on line 0 diff --git a/src/tests/cookies_encryption_warning/encrypt_regexp_cookies_no_key.phpt b/src/tests/cookies_encryption_warning/encrypt_regexp_cookies_no_key.phpt index df31f2e..0da0dbe 100644 --- a/src/tests/cookies_encryption_warning/encrypt_regexp_cookies_no_key.phpt +++ b/src/tests/cookies_encryption_warning/encrypt_regexp_cookies_no_key.phpt @@ -18,4 +18,4 @@ EOF; --EXPECT-- Fatal error: [snuffleupagus][127.0.0.1][config][log] Invalid configuration file in Unknown on line 0 -Fatal error: [snuffleupagus][127.0.0.1][config][log] You're trying to use the cookie encryption featureon line 2 without having set the `.encryption_key` option in`sp.global`: please set it first in Unknown on line 0 +Fatal error: [snuffleupagus][127.0.0.1][config][log] You're trying to use the cookie encryption feature on line 2 without having set the `.secret_key` option in `sp.global`: please set it first in Unknown on line 0 diff --git a/src/tests/dump_request/dump_eval_blacklist.phpt b/src/tests/dump_request/dump_eval_blacklist.phpt index 07c17f2..b8192a7 100644 --- a/src/tests/dump_request/dump_eval_blacklist.phpt +++ b/src/tests/dump_request/dump_eval_blacklist.phpt @@ -36,5 +36,5 @@ if ($res[3] != "GET:get_a='data_get_a' get_b='data_get_b' \n") { --EXPECTF-- Outside of eval: 1337 1337 1337 -Warning: [snuffleupagus][0.0.0.0][eval][simulation] A call to strtoupper was tried in eval, in %a/dump_eval_blacklist.php:1, logging it. in %a/dump_eval_blacklist.php(9) : eval()'d code on line 1 +Warning: [snuffleupagus][0.0.0.0][eval][simulation] A call to 'strtoupper' was tried in eval. logging it. in %a(9) : eval()'d code on line 1 After eval: 1234 diff --git a/src/tests/eval_blacklist/eval_backlist.phpt b/src/tests/eval_blacklist/eval_backlist.phpt index fa32b4b..2953efc 100644 --- a/src/tests/eval_blacklist/eval_backlist.phpt +++ b/src/tests/eval_blacklist/eval_backlist.phpt @@ -14,4 +14,4 @@ echo "After eval: $a\n"; --EXPECTF-- Outside of eval: 1337 1337 1337 -Fatal error: [snuffleupagus][0.0.0.0][eval][drop] A call to strtoupper was tried in eval, in %a/eval_backlist.php:1, dropping it. in %a/eval_backlist.php(4) : eval()'d code on line 1 +Fatal error: [snuffleupagus][0.0.0.0][eval][drop] A call to 'strtoupper' was tried in eval. dropping it. in %a/eval_backlist.php(4) : eval()'d code on line 1 diff --git a/src/tests/eval_blacklist/eval_backlist_call_user_func.phpt b/src/tests/eval_blacklist/eval_backlist_call_user_func.phpt index 4c37263..546a53a 100644 --- a/src/tests/eval_blacklist/eval_backlist_call_user_func.phpt +++ b/src/tests/eval_blacklist/eval_backlist_call_user_func.phpt @@ -11,4 +11,4 @@ eval(' ') ?> --EXPECTF-- -Fatal error: [snuffleupagus][0.0.0.0][eval][drop] A call to strtoupper was tried in eval, in %s/eval_backlist_call_user_func.php:%d, dropping it. in %s/eval_backlist_call_user_func.php(%d) : eval()'d code on line %d +Fatal error: [snuffleupagus][0.0.0.0][eval][drop] A call to 'strtoupper' was tried in eval. dropping it. in %s/eval_backlist_call_user_func.php(%d) : eval()'d code on line %d diff --git a/src/tests/eval_blacklist/eval_backlist_chained.phpt b/src/tests/eval_blacklist/eval_backlist_chained.phpt index 820ef1d..1afb860 100644 --- a/src/tests/eval_blacklist/eval_backlist_chained.phpt +++ b/src/tests/eval_blacklist/eval_backlist_chained.phpt @@ -13,4 +13,4 @@ eval(' ') ?> --EXPECTF-- -Fatal error: [snuffleupagus][0.0.0.0][eval][drop] A call to strtoupper was tried in eval, in %s/eval_backlist_chained.php:%d, dropping it. in %s/eval_backlist_chained.php(%d) : eval()'d code on line %d +Fatal error: [snuffleupagus][0.0.0.0][eval][drop] A call to 'strtoupper' was tried in eval. dropping it. in %s/eval_backlist_chained.php(%d) : eval()'d code on line %d diff --git a/src/tests/eval_blacklist/eval_backlist_list.phpt b/src/tests/eval_blacklist/eval_backlist_list.phpt index 725a9bb..1efd453 100644 --- a/src/tests/eval_blacklist/eval_backlist_list.phpt +++ b/src/tests/eval_blacklist/eval_backlist_list.phpt @@ -14,4 +14,4 @@ echo "After eval: $a\n"; --EXPECTF-- Outside of eval: 1337 1337 1337 -Fatal error: [snuffleupagus][0.0.0.0][eval][drop] A call to strtoupper was tried in eval, in %a/eval_backlist_list.php:1, dropping it. in %a/eval_backlist_list.php(4) : eval()'d code on line 1 +Fatal error: [snuffleupagus][0.0.0.0][eval][drop] A call to 'strtoupper' was tried in eval. dropping it. in %a/eval_backlist_list.php(4) : eval()'d code on line 1 diff --git a/src/tests/eval_blacklist/eval_backlist_simulation.phpt b/src/tests/eval_blacklist/eval_backlist_simulation.phpt index f09370d..0cc02b2 100644 --- a/src/tests/eval_blacklist/eval_backlist_simulation.phpt +++ b/src/tests/eval_blacklist/eval_backlist_simulation.phpt @@ -14,5 +14,5 @@ echo "After eval: $a\n"; --EXPECTF-- Outside of eval: 1337 1337 1337 -Warning: [snuffleupagus][0.0.0.0][eval][simulation] A call to strtoupper was tried in eval, in %a/eval_backlist_simulation.php:1, logging it. in %a/eval_backlist_simulation.php(4) : eval()'d code on line 1 +Warning: [snuffleupagus][0.0.0.0][eval][simulation] A call to 'strtoupper' was tried in eval. logging it. in %a/eval_backlist_simulation.php(4) : eval()'d code on line 1 After eval: 1234 diff --git a/src/tests/eval_blacklist/nested_eval_blacklist.phpt b/src/tests/eval_blacklist/nested_eval_blacklist.phpt index 8ff0b6d..a06b66b 100644 --- a/src/tests/eval_blacklist/nested_eval_blacklist.phpt +++ b/src/tests/eval_blacklist/nested_eval_blacklist.phpt @@ -26,4 +26,4 @@ Inception lvl 1... Inception lvl 2... Inception lvl 3... -Fatal error: [snuffleupagus][0.0.0.0][eval][drop] A call to strtoupper was tried in eval, in %a/nested_eval_blacklist.php(5) : eval()'d code(4) : eval()'d code:3, dropping it. in %a/nested_eval_blacklist.php(5) : eval()'d code(4) : eval()'d code(4) : eval()'d code on line 3 +Fatal error: [snuffleupagus][0.0.0.0][eval][drop] A call to 'strtoupper' was tried in eval. dropping it. in %a/nested_eval_blacklist.php(5) : eval()'d code(4) : eval()'d code(4) : eval()'d code on line 3 diff --git a/src/tests/eval_blacklist/nested_eval_blacklist2.phpt b/src/tests/eval_blacklist/nested_eval_blacklist2.phpt index 37f8967..63e56b1 100644 --- a/src/tests/eval_blacklist/nested_eval_blacklist2.phpt +++ b/src/tests/eval_blacklist/nested_eval_blacklist2.phpt @@ -26,4 +26,4 @@ Inception lvl 1... Inception lvl 2... Inception lvl 3... -Fatal error: [snuffleupagus][0.0.0.0][eval][drop] A call to strtoupper was tried in eval, in %a/nested_eval_blacklist2.php(5) : eval()'d code:7, dropping it. in %a/nested_eval_blacklist2.php(5) : eval()'d code(4) : eval()'d code on line 7 +Fatal error: [snuffleupagus][0.0.0.0][eval][drop] A call to 'strtoupper' was tried in eval. dropping it. in %a/nested_eval_blacklist2.php(5) : eval()'d code(4) : eval()'d code on line 7 -- cgit v1.3 From 8e42064026906f0f25caca237e4624b5b3c5087e Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Wed, 15 Sep 2021 20:25:33 +0200 Subject: changed version and version output in phpinfo --- src/php_snuffleupagus.h | 6 +++--- src/snuffleupagus.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/php_snuffleupagus.h') diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index 91ee8a6..e11f976 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -1,10 +1,10 @@ #ifndef PHP_SNUFFLEUPAGUS_H #define PHP_SNUFFLEUPAGUS_H -#define PHP_SNUFFLEUPAGUS_VERSION "0.7.0" +#define PHP_SNUFFLEUPAGUS_VERSION "0.8.0" #define PHP_SNUFFLEUPAGUS_EXTNAME "snuffleupagus" -#define PHP_SNUFFLEUPAGUS_AUTHOR "NBS System & Julien (jvoisin) Voisin" -#define PHP_SNUFFLEUPAGUS_URL "https://github.com/jvoisin/snuffleupagus" +#define PHP_SNUFFLEUPAGUS_AUTHOR "NBS System & Julien (jvoisin) Voisin | Suhosin-NG patches by SektionEins GmbH" +#define PHP_SNUFFLEUPAGUS_URL "https://github.com/sektioneins/snuffleupagus" #define PHP_SNUFFLEUPAGUS_COPYRIGHT "LGPLv2" #ifdef HAVE_CONFIG_H diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 650e5e4..dab5dca 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -302,7 +302,7 @@ PHP_MINFO_FUNCTION(snuffleupagus) { php_info_print_table_row( 2, "snuffleupagus support", SNUFFLEUPAGUS_G(is_config_valid) ? "enabled" : "disabled"); - php_info_print_table_row(2, "Version", PHP_SNUFFLEUPAGUS_VERSION); + php_info_print_table_row(2, "Version", PHP_SNUFFLEUPAGUS_VERSION "-sng (with Suhosin-NG patches)"); php_info_print_table_row(2, "Valid config", valid_config); php_info_print_table_end(); DISPLAY_INI_ENTRIES(); -- cgit v1.3 From 31d6a3cddd18cef447698ba2beaa7b5d9ab9dd94 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Wed, 15 Sep 2021 20:26:02 +0200 Subject: implemented execution depth limit --- src/php_snuffleupagus.h | 1 + src/snuffleupagus.c | 2 ++ src/sp_config.h | 2 ++ src/sp_config_keywords.c | 1 + src/sp_execute.c | 17 +++++++++++++---- 5 files changed, 19 insertions(+), 4 deletions(-) (limited to 'src/php_snuffleupagus.h') diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index e11f976..0c7dc4b 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -108,6 +108,7 @@ ZEND_BEGIN_MODULE_GLOBALS(snuffleupagus) size_t in_eval; sp_config config; int is_config_valid; // 1 = valid, 0 = invalid, -1 = none +u_long execution_depth; bool allow_broken_configuration; HashTable *disabled_functions_hook; HashTable *sp_internal_functions_hook; diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index dab5dca..d2f81ff 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -251,6 +251,8 @@ static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) { } PHP_RINIT_FUNCTION(snuffleupagus) { + SNUFFLEUPAGUS_G(execution_depth) = 0; + const sp_config_wrapper *const config_wrapper = SNUFFLEUPAGUS_G(config).config_wrapper; #if defined(COMPILE_DL_SNUFFLEUPAGUS) && defined(ZTS) diff --git a/src/sp_config.h b/src/sp_config.h index fd6dc15..ccf2318 100644 --- a/src/sp_config.h +++ b/src/sp_config.h @@ -196,6 +196,7 @@ typedef struct { sp_config_ini *config_ini; bool hook_execute; char log_media; + u_long max_execution_depth; HashTable *config_disabled_functions; HashTable *config_disabled_functions_hooked; @@ -286,6 +287,7 @@ typedef struct { #define SP_TOKEN_ENCRYPTION_KEY "secret_key" #define SP_TOKEN_ENV_VAR "cookie_env_var" #define SP_TOKEN_LOG_MEDIA "log_media" +#define SP_TOKEN_MAX_EXECUTION_DEPTH "max_execution_depth" // upload_validator #define SP_TOKEN_UPLOAD_SCRIPT "script" diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index 3b6bc0b..632f9bd 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -128,6 +128,7 @@ SP_PARSE_FN(parse_global) { {parse_str, SP_TOKEN_ENCRYPTION_KEY, &(SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)}, {parse_str, SP_TOKEN_ENV_VAR, &(SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var)}, {parse_log_media, SP_TOKEN_LOG_MEDIA, &(SNUFFLEUPAGUS_G(config).log_media)}, + {parse_ulong, SP_TOKEN_MAX_EXECUTION_DEPTH, &(SNUFFLEUPAGUS_G(config).max_execution_depth)}, {0, 0, 0}}; SP_PROCESS_CONFIG_KEYWORDS_ERR(); diff --git a/src/sp_execute.c b/src/sp_execute.c index 8795e5f..41257ad 100644 --- a/src/sp_execute.c +++ b/src/sp_execute.c @@ -112,6 +112,15 @@ zend_string *get_eval_filename(const char *const filename) { return clean_filename; } +static inline void sp_orig_execute(zend_execute_data *execute_data) { + SNUFFLEUPAGUS_G(execution_depth)++; + if (SNUFFLEUPAGUS_G(execution_depth) > SNUFFLEUPAGUS_G(config).max_execution_depth && SNUFFLEUPAGUS_G(config).max_execution_depth > 0) { + sp_log_drop("execute", "Maximum recursion limit reached. Script terminated."); + } + orig_execute_ex(execute_data); + SNUFFLEUPAGUS_G(execution_depth)--; +} + static void sp_execute_ex(zend_execute_data *execute_data) { is_in_eval_and_whitelisted(execute_data); const HashTable *config_disabled_functions = @@ -131,7 +140,7 @@ static void sp_execute_ex(zend_execute_data *execute_data) { zend_string_release(filename); SNUFFLEUPAGUS_G(in_eval)++; - orig_execute_ex(execute_data); + sp_orig_execute(execute_data); SNUFFLEUPAGUS_G(in_eval)--; return; } @@ -150,7 +159,7 @@ static void sp_execute_ex(zend_execute_data *execute_data) { .config_disabled_functions_reg->disabled_functions; if (!function_name) { - orig_execute_ex(execute_data); + sp_orig_execute(execute_data); return; } @@ -184,7 +193,7 @@ static void sp_execute_ex(zend_execute_data *execute_data) { EX(return_value) = &ret_val; } - orig_execute_ex(execute_data); + sp_orig_execute(execute_data); should_drop_on_ret_ht( EX(return_value), function_name, @@ -197,7 +206,7 @@ static void sp_execute_ex(zend_execute_data *execute_data) { EX(return_value) = NULL; } } else { - orig_execute_ex(execute_data); + sp_orig_execute(execute_data); } } -- cgit v1.3 From 6e07cdb870513270a3c08abc7ecdca64ad2af400 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Thu, 16 Sep 2021 11:32:41 +0200 Subject: ported server.strip and server.encode features from suhosin --- src/config.m4 | 2 +- src/php_snuffleupagus.h | 1 + src/snuffleupagus.c | 2 + src/sp_config.h | 4 ++ src/sp_config_keywords.c | 2 + src/sp_ifilter.c | 103 ++++++++++++++++++++++++++++++++++++ src/sp_ifilter.h | 3 ++ src/tests/filter/config/filter.ini | 3 ++ src/tests/filter/server_encode.phpt | 25 +++++++++ src/tests/filter/server_strip.phpt | 21 ++++++++ 10 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 src/sp_ifilter.c create mode 100644 src/sp_ifilter.h create mode 100644 src/tests/filter/config/filter.ini create mode 100644 src/tests/filter/server_encode.phpt create mode 100644 src/tests/filter/server_strip.phpt (limited to 'src/php_snuffleupagus.h') diff --git a/src/config.m4 b/src/config.m4 index a2301fd..ddbd7a1 100644 --- a/src/config.m4 +++ b/src/config.m4 @@ -7,7 +7,7 @@ sources="$sources sp_disabled_functions.c sp_execute.c sp_upload_validation.c" sources="$sources sp_cookie_encryption.c sp_network_utils.c tweetnacl.c" sources="$sources sp_config_keywords.c sp_var_parser.c sp_var_value.c sp_tree.c" sources="$sources sp_pcre_compat.c sp_crypt.c sp_session.c sp_sloppy.c sp_wrapper.c" -sources="$sources sp_ini.c sp_php_compat.c sp_config_scanner.c" +sources="$sources sp_ini.c sp_php_compat.c sp_config_scanner.c sp_ifilter.c" PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support, [ --enable-snuffleupagus Enable snuffleupagus support]) diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index 0c7dc4b..bcb613c 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -88,6 +88,7 @@ typedef void (*zif_handler)(INTERNAL_FUNCTION_PARAMETERS); #include "sp_sloppy.h" #include "sp_wrapper.h" #include "sp_ini.h" +#include "sp_ifilter.h" extern zend_module_entry snuffleupagus_module_entry; #define phpext_snuffleupagus_ptr &snuffleupagus_module_entry diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index d2f81ff..50711f0 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -383,6 +383,8 @@ static PHP_INI_MH(OnUpdateConfiguration) { sp_hook_ini(); } + sp_hook_register_server_variables(); + if (true == SNUFFLEUPAGUS_G(config).config_global_strict->enable) { if (!zend_get_extension(PHP_SNUFFLEUPAGUS_EXTNAME)) { zend_extension_entry.startup = NULL; diff --git a/src/sp_config.h b/src/sp_config.h index ccf2318..af9b905 100644 --- a/src/sp_config.h +++ b/src/sp_config.h @@ -197,6 +197,8 @@ typedef struct { bool hook_execute; char log_media; u_long max_execution_depth; + bool server_encode; + bool server_strip; HashTable *config_disabled_functions; HashTable *config_disabled_functions_hooked; @@ -288,6 +290,8 @@ typedef struct { #define SP_TOKEN_ENV_VAR "cookie_env_var" #define SP_TOKEN_LOG_MEDIA "log_media" #define SP_TOKEN_MAX_EXECUTION_DEPTH "max_execution_depth" +#define SP_TOKEN_SERVER_ENCODE "server_encode" +#define SP_TOKEN_SERVER_STRIP "server_strip" // upload_validator #define SP_TOKEN_UPLOAD_SCRIPT "script" diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index 632f9bd..38b8526 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -129,6 +129,8 @@ SP_PARSE_FN(parse_global) { {parse_str, SP_TOKEN_ENV_VAR, &(SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var)}, {parse_log_media, SP_TOKEN_LOG_MEDIA, &(SNUFFLEUPAGUS_G(config).log_media)}, {parse_ulong, SP_TOKEN_MAX_EXECUTION_DEPTH, &(SNUFFLEUPAGUS_G(config).max_execution_depth)}, + {parse_enable, SP_TOKEN_SERVER_ENCODE, &(SNUFFLEUPAGUS_G(config).server_encode)}, + {parse_enable, SP_TOKEN_SERVER_STRIP, &(SNUFFLEUPAGUS_G(config).server_strip)}, {0, 0, 0}}; SP_PROCESS_CONFIG_KEYWORDS_ERR(); diff --git a/src/sp_ifilter.c b/src/sp_ifilter.c new file mode 100644 index 0000000..171138f --- /dev/null +++ b/src/sp_ifilter.c @@ -0,0 +1,103 @@ +#include "php_snuffleupagus.h" + +static void (*orig_register_server_variables)(zval *track_vars_array) = NULL; + +static const unsigned char sp_hexchars[] = "0123456789ABCDEF"; + +static const char sp_is_dangerous_char[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static void sp_server_strip(HashTable *svars, char *key, int keylen) { + zval *value = zend_hash_str_find(svars, key, keylen); + if (!value || Z_TYPE_P(value) != IS_STRING) { return; } + + zend_string *tmp_zstr = Z_STR_P(value); + char *tmp = ZSTR_VAL(tmp_zstr); + char *tmpend = tmp + ZSTR_LEN(tmp_zstr); + + for (char *p = tmp; p < tmpend; p++) { + if (sp_is_dangerous_char[(int)*p]) { + *p = '_'; + } + } +} + +static void sp_server_encode(HashTable *svars, char *key, int keylen) { + zval *value = zend_hash_str_find(svars, key, keylen); + if (!value || Z_TYPE_P(value) != IS_STRING) { return; } + + zend_string *tmp_zstr = Z_STR_P(value); + char *tmp = ZSTR_VAL(tmp_zstr); + char *tmpend = tmp + ZSTR_LEN(tmp_zstr); + int extra = 0; + + for (char *p = tmp; p < tmpend; p++) { + extra += sp_is_dangerous_char[(int)*p] * 2; + } + if (!extra) { return; } + + zend_string *new_zstr = zend_string_alloc(ZSTR_LEN(tmp_zstr) + extra, 0); + char *n = ZSTR_VAL(new_zstr); + for (char *p = tmp; p < tmpend; p++, n++) { + if (sp_is_dangerous_char[(int)*p]) { + *n++ = '%'; + *n++ = sp_hexchars[*p >> 4]; + *n = sp_hexchars[*p & 15]; + } else { + *n = *p; + } + } + ZSTR_VAL(new_zstr)[ZSTR_LEN(new_zstr)] = 0; + Z_STR_P(value) = new_zstr; + + zend_string_release_ex(tmp_zstr, 0); +} + +static void sp_register_server_variables(zval *track_vars_array) { + orig_register_server_variables(track_vars_array); + + HashTable *svars; + svars = Z_ARRVAL_P(track_vars_array); + + + if (SNUFFLEUPAGUS_G(config).server_encode) { + sp_server_encode(svars, ZEND_STRL("REQUEST_URI")); + sp_server_encode(svars, ZEND_STRL("QUERY_STRING")); + } + + if (SNUFFLEUPAGUS_G(config).server_strip) { + sp_server_strip(svars, ZEND_STRL("PHP_SELF")); + sp_server_strip(svars, ZEND_STRL("HTTP_HOST")); + sp_server_strip(svars, ZEND_STRL("HTTP_USER_AGENT")); + + // for cgi + fpm + sp_server_strip(svars, ZEND_STRL("PATH_INFO")); + sp_server_strip(svars, ZEND_STRL("PATH_TRANSLATED")); + sp_server_strip(svars, ZEND_STRL("ORIG_PATH_TRANSLATED")); + sp_server_strip(svars, ZEND_STRL("ORIG_PATH_INFO")); + } +} + +void sp_hook_register_server_variables() +{ + if (sapi_module.register_server_variables) { + orig_register_server_variables = sapi_module.register_server_variables; + sapi_module.register_server_variables = sp_register_server_variables; + } +} diff --git a/src/sp_ifilter.h b/src/sp_ifilter.h new file mode 100644 index 0000000..527c41d --- /dev/null +++ b/src/sp_ifilter.h @@ -0,0 +1,3 @@ +#pragma once + +void sp_hook_register_server_variables(); diff --git a/src/tests/filter/config/filter.ini b/src/tests/filter/config/filter.ini new file mode 100644 index 0000000..5ebee61 --- /dev/null +++ b/src/tests/filter/config/filter.ini @@ -0,0 +1,3 @@ +sp.global.server_encode.enable(); +sp.global.server_strip.enable(); + diff --git a/src/tests/filter/server_encode.phpt b/src/tests/filter/server_encode.phpt new file mode 100644 index 0000000..f7cc233 --- /dev/null +++ b/src/tests/filter/server_encode.phpt @@ -0,0 +1,25 @@ +--TEST-- +input filter: server_encode +--SKIPIF-- + +--INI-- +sp.configuration_file={PWD}/config/filter.ini +display_errors=1 +display_startup_errors=1 +error_reporting=E_ALL +--ENV-- +return <<"'`!AAA +EOF; +--COOKIE-- +--GET-- +BBB<>"'`!BBB +--POST-- +--FILE-- + +--INI-- +sp.configuration_file={PWD}/config/filter.ini +display_errors=1 +display_startup_errors=1 +error_reporting=E_ALL +--ENV-- +return <<alert('123');Gecko/20100101 Firefox/29.0 +EOF; +--COOKIE-- +--GET-- +--POST-- +--FILE-- +filename || op->fn_flags & ZEND_ACC_STRICT_TYPES) { return; } else { - if (true == SNUFFLEUPAGUS_G(config).config_global_strict->enable) { + if (SPCFG(global_strict).enable) { op->fn_flags |= ZEND_ACC_STRICT_TYPES; } } @@ -41,16 +41,15 @@ ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) static PHP_INI_MH(StrictMode) { TSRMLS_FETCH(); - SNUFFLEUPAGUS_G(allow_broken_configuration) = false; + SPG(allow_broken_configuration) = false; if (new_value && zend_string_equals_literal(new_value, "1")) { - SNUFFLEUPAGUS_G(allow_broken_configuration) = true; + SPG(allow_broken_configuration) = true; } return SUCCESS; } PHP_INI_BEGIN() -PHP_INI_ENTRY("sp.configuration_file", "", PHP_INI_SYSTEM, - OnUpdateConfiguration) +PHP_INI_ENTRY("sp.configuration_file", "", PHP_INI_SYSTEM, OnUpdateConfiguration) PHP_INI_ENTRY("sp.allow_broken_configuration", "0", PHP_INI_SYSTEM, StrictMode) PHP_INI_END() @@ -106,47 +105,28 @@ static PHP_GINIT_FUNCTION(snuffleupagus) { snuffleupagus_globals->is_config_valid = SP_CONFIG_NONE; snuffleupagus_globals->in_eval = 0; -#define SP_INIT(F) \ - snuffleupagus_globals->config.F = \ - pecalloc(sizeof(*(snuffleupagus_globals->config.F)), 1, 1); - SP_INIT(config_random); - SP_INIT(config_sloppy); - SP_INIT(config_unserialize); - SP_INIT(config_readonly_exec); - SP_INIT(config_upload_validation); - SP_INIT(config_cookie); - SP_INIT(config_snuffleupagus); - SP_INIT(config_auto_cookie_secure); - SP_INIT(config_global_strict); - SP_INIT(config_disable_xxe); - SP_INIT(config_eval); - SP_INIT(config_wrapper); - SP_INIT(config_session); - SP_INIT(config_ini); - SP_INIT(config_disabled_functions_reg); - SP_INIT(config_disabled_functions_reg_ret); -#undef SP_INIT - #define SP_INIT_HT(F) \ snuffleupagus_globals->F = pemalloc(sizeof(*(snuffleupagus_globals->F)), 1); \ - zend_hash_init(snuffleupagus_globals->F, 10, NULL, NULL, 1); + zend_hash_init(snuffleupagus_globals->F, 10, NULL, NULL, 1); SP_INIT_HT(disabled_functions_hook); SP_INIT_HT(sp_internal_functions_hook); SP_INIT_HT(sp_eval_blacklist_functions_hook); - SP_INIT_HT(config.config_disabled_functions); - SP_INIT_HT(config.config_disabled_functions_hooked); - SP_INIT_HT(config.config_disabled_functions_ret); - SP_INIT_HT(config.config_disabled_functions_ret_hooked); - SP_INIT_HT(config.config_ini->entries); + SP_INIT_HT(config_disabled_functions); + SP_INIT_HT(config_disabled_functions_hooked); + SP_INIT_HT(config_disabled_functions_ret); + SP_INIT_HT(config_disabled_functions_ret_hooked); + SP_INIT_HT(config_ini.entries); #undef SP_INIT_HT -#define SP_INIT_NULL(F) snuffleupagus_globals->config.F = NULL; - SP_INIT_NULL(config_disabled_functions_reg->disabled_functions); - SP_INIT_NULL(config_disabled_functions_reg_ret->disabled_functions); - SP_INIT_NULL(config_cookie->cookies); - SP_INIT_NULL(config_eval->blacklist); - SP_INIT_NULL(config_eval->whitelist); - SP_INIT_NULL(config_wrapper->whitelist); +#define SP_INIT_NULL(F) snuffleupagus_globals->F = NULL; + SP_INIT_NULL(config_encryption_key); + SP_INIT_NULL(config_cookies_env_var); + SP_INIT_NULL(config_disabled_functions_reg.disabled_functions); + SP_INIT_NULL(config_disabled_functions_reg_ret.disabled_functions); + SP_INIT_NULL(config_cookie.cookies); + SP_INIT_NULL(config_eval.blacklist); + SP_INIT_NULL(config_eval.whitelist); + SP_INIT_NULL(config_wrapper.whitelist); #undef SP_INIT_NULL } @@ -159,10 +139,10 @@ PHP_MINIT_FUNCTION(snuffleupagus) { PHP_MSHUTDOWN_FUNCTION(snuffleupagus) { sp_log_debug("(MSHUTDOWN)"); - unhook_functions(SNUFFLEUPAGUS_G(sp_internal_functions_hook)); - unhook_functions(SNUFFLEUPAGUS_G(disabled_functions_hook)); - unhook_functions(SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook)); - if (SNUFFLEUPAGUS_G(config).config_ini->enable) { sp_unhook_ini(); } + unhook_functions(SPG(sp_internal_functions_hook)); + unhook_functions(SPG(disabled_functions_hook)); + unhook_functions(SPG(sp_eval_blacklist_functions_hook)); + if (SPCFG(ini).enable) { sp_unhook_ini(); } UNREGISTER_INI_ENTRIES(); return SUCCESS; @@ -189,57 +169,37 @@ static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) { FREE_HT(sp_eval_blacklist_functions_hook); #define FREE_HT_LIST(F) \ - free_disabled_functions_hashtable(snuffleupagus_globals->config.F); \ - FREE_HT(config.F); + free_disabled_functions_hashtable(snuffleupagus_globals->F); \ + FREE_HT(F); FREE_HT_LIST(config_disabled_functions); FREE_HT_LIST(config_disabled_functions_hooked); FREE_HT_LIST(config_disabled_functions_ret); FREE_HT_LIST(config_disabled_functions_ret_hooked); #undef FREE_HT_LIST - free_config_ini_entries(snuffleupagus_globals->config.config_ini->entries); - FREE_HT(config.config_ini->entries); + free_config_ini_entries(snuffleupagus_globals->config_ini.entries); + FREE_HT(config_ini.entries); #undef FREE_HT -#define FREE_LST_DISABLE(L) \ - sp_list_free(snuffleupagus_globals->config.L, sp_free_disabled_function); - FREE_LST_DISABLE(config_disabled_functions_reg->disabled_functions); - FREE_LST_DISABLE(config_disabled_functions_reg_ret->disabled_functions); -#undef FREE_LST_DISABLE - - sp_list_free(snuffleupagus_globals->config.config_cookie->cookies, sp_free_cookie); + sp_list_free(snuffleupagus_globals->config_disabled_functions_reg.disabled_functions, sp_free_disabled_function); + sp_list_free(snuffleupagus_globals->config_disabled_functions_reg_ret.disabled_functions, sp_free_disabled_function); + sp_list_free(snuffleupagus_globals->config_cookie.cookies, sp_free_cookie); -#define FREE_LST(L) sp_list_free(snuffleupagus_globals->config.L, sp_free_zstr); - FREE_LST(config_eval->blacklist); - FREE_LST(config_eval->whitelist); - FREE_LST(config_wrapper->whitelist); +#define FREE_LST(L) sp_list_free(snuffleupagus_globals->L, sp_free_zstr); + FREE_LST(config_eval.blacklist); + FREE_LST(config_eval.whitelist); + FREE_LST(config_wrapper.whitelist); #undef FREE_LST -#define FREE_CFG(C) pefree(snuffleupagus_globals->config.C, 1); -#define FREE_CFG_ZSTR(C) sp_free_zstr(snuffleupagus_globals->config.C); - FREE_CFG(config_random); - FREE_CFG(config_sloppy); - FREE_CFG_ZSTR(config_unserialize->dump); - FREE_CFG_ZSTR(config_unserialize->textual_representation); - FREE_CFG(config_unserialize); - FREE_CFG(config_readonly_exec); - FREE_CFG_ZSTR(config_upload_validation->script); - FREE_CFG(config_upload_validation); - FREE_CFG(config_cookie); - FREE_CFG(config_snuffleupagus); - FREE_CFG(config_auto_cookie_secure); - FREE_CFG(config_global_strict); - FREE_CFG(config_disable_xxe); - FREE_CFG_ZSTR(config_eval->dump); - FREE_CFG_ZSTR(config_eval->textual_representation); - FREE_CFG(config_eval); - FREE_CFG(config_wrapper); - FREE_CFG(config_session); - FREE_CFG(config_ini); - FREE_CFG(config_disabled_functions_reg); - FREE_CFG(config_disabled_functions_reg_ret); -#undef FREE_CFG +// #define FREE_CFG(C) pefree(snuffleupagus_globals->config.C, 1); +#define FREE_CFG_ZSTR(C) sp_free_zstr(snuffleupagus_globals->C); + FREE_CFG_ZSTR(config_unserialize.dump); + FREE_CFG_ZSTR(config_unserialize.textual_representation); + FREE_CFG_ZSTR(config_upload_validation.script); + FREE_CFG_ZSTR(config_eval.dump); + FREE_CFG_ZSTR(config_eval.textual_representation); +// #undef FREE_CFG #undef FREE_CFG_ZSTR #ifdef SP_DEBUG_STDERR @@ -251,35 +211,32 @@ static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) { } PHP_RINIT_FUNCTION(snuffleupagus) { - SNUFFLEUPAGUS_G(execution_depth) = 0; + SPG(execution_depth) = 0; + SPG(in_eval) = 0; - const sp_config_wrapper *const config_wrapper = - SNUFFLEUPAGUS_G(config).config_wrapper; + const sp_config_wrapper *const config_wrapper = &(SPCFG(wrapper)); #if defined(COMPILE_DL_SNUFFLEUPAGUS) && defined(ZTS) ZEND_TSRMLS_CACHE_UPDATE(); #endif - if (!SNUFFLEUPAGUS_G(allow_broken_configuration)) { - if (SNUFFLEUPAGUS_G(is_config_valid) == SP_CONFIG_INVALID) { + if (!SPG(allow_broken_configuration)) { + if (SPG(is_config_valid) == SP_CONFIG_INVALID) { sp_log_err("config", "Invalid configuration file"); - } else if (SNUFFLEUPAGUS_G(is_config_valid) == SP_CONFIG_NONE) { + } else if (SPG(is_config_valid) == SP_CONFIG_NONE) { sp_log_warn("config", "No configuration specificed via sp.configuration_file"); } } - // We need to disable wrappers loaded by extensions loaded after - // SNUFFLEUPAGUS. + // We need to disable wrappers loaded by extensions loaded after SNUFFLEUPAGUS. if (config_wrapper->enabled && - zend_hash_num_elements(php_stream_get_url_stream_wrappers_hash()) != - config_wrapper->num_wrapper) { + zend_hash_num_elements(php_stream_get_url_stream_wrappers_hash()) != config_wrapper->num_wrapper) { sp_disable_wrapper(); } - if (NULL != SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key) { - if (NULL != SNUFFLEUPAGUS_G(config).config_cookie->cookies) { - zend_hash_apply_with_arguments( - Z_ARRVAL(PG(http_globals)[TRACK_VARS_COOKIE]), decrypt_cookie, 0); + if (NULL != SPCFG(encryption_key)) { + if (NULL != SPCFG(cookie).cookies) { + zend_hash_apply_with_arguments(Z_ARRVAL(PG(http_globals)[TRACK_VARS_COOKIE]), decrypt_cookie, 0); } } return SUCCESS; @@ -289,7 +246,7 @@ PHP_RSHUTDOWN_FUNCTION(snuffleupagus) { return SUCCESS; } PHP_MINFO_FUNCTION(snuffleupagus) { const char *valid_config; - switch (SNUFFLEUPAGUS_G(is_config_valid)) { + switch (SPG(is_config_valid)) { case SP_CONFIG_VALID: valid_config = "yes"; break; @@ -303,7 +260,7 @@ PHP_MINFO_FUNCTION(snuffleupagus) { php_info_print_table_start(); php_info_print_table_row( 2, "snuffleupagus support", - SNUFFLEUPAGUS_G(is_config_valid) ? "enabled" : "disabled"); + SPG(is_config_valid) ? "enabled" : "disabled"); php_info_print_table_row(2, "Version", PHP_SNUFFLEUPAGUS_VERSION "-sng (with Suhosin-NG patches)"); php_info_print_table_row(2, "Valid config", valid_config); php_info_print_table_end(); @@ -328,14 +285,14 @@ static PHP_INI_MH(OnUpdateConfiguration) { glob_t globbuf; if (0 != glob(config_file, GLOB_NOCHECK, NULL, &globbuf)) { - SNUFFLEUPAGUS_G(is_config_valid) = SP_CONFIG_INVALID; + SPG(is_config_valid) = SP_CONFIG_INVALID; globfree(&globbuf); return FAILURE; } for (size_t i = 0; globbuf.gl_pathv[i]; i++) { if (sp_parse_config(globbuf.gl_pathv[i]) != SUCCESS) { - SNUFFLEUPAGUS_G(is_config_valid) = SP_CONFIG_INVALID; + SPG(is_config_valid) = SP_CONFIG_INVALID; globfree(&globbuf); return FAILURE; } @@ -343,34 +300,34 @@ static PHP_INI_MH(OnUpdateConfiguration) { globfree(&globbuf); } - SNUFFLEUPAGUS_G(is_config_valid) = SP_CONFIG_VALID; + SPG(is_config_valid) = SP_CONFIG_VALID; - if ((SNUFFLEUPAGUS_G(config).config_sloppy->enable)) { + if (SPCFG(sloppy).enable) { hook_sloppy(); } - if (SNUFFLEUPAGUS_G(config).config_random->enable) { + if (SPCFG(random).enable) { hook_rand(); } - if (SNUFFLEUPAGUS_G(config).config_upload_validation->enable) { + if (SPCFG(upload_validation).enable) { hook_upload(); } - if (SNUFFLEUPAGUS_G(config).config_disable_xxe->enable == 0) { + if (SPCFG(disable_xxe).enable == 0) { hook_libxml_disable_entity_loader(); } - if (SNUFFLEUPAGUS_G(config).config_wrapper->enabled) { + if (SPCFG(wrapper).enabled) { hook_stream_wrappers(); } - if (SNUFFLEUPAGUS_G(config).config_session->encrypt || SNUFFLEUPAGUS_G(config).config_session->sid_min_length || SNUFFLEUPAGUS_G(config).config_session->sid_max_length) { + if (SPCFG(session).encrypt || SPCFG(session).sid_min_length || SPCFG(session).sid_max_length) { hook_session(); } - if (NULL != SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key) { - if (SNUFFLEUPAGUS_G(config).config_unserialize->enable) { + if (NULL != SPCFG(encryption_key)) { + if (SPCFG(unserialize).enable) { hook_serialize(); } } @@ -379,13 +336,13 @@ static PHP_INI_MH(OnUpdateConfiguration) { hook_execute(); hook_cookies(); - if (SNUFFLEUPAGUS_G(config).config_ini->enable) { + if (SPCFG(ini).enable) { sp_hook_ini(); } sp_hook_register_server_variables(); - if (true == SNUFFLEUPAGUS_G(config).config_global_strict->enable) { + if (SPCFG(global_strict).enable) { if (!zend_get_extension(PHP_SNUFFLEUPAGUS_EXTNAME)) { zend_extension_entry.startup = NULL; zend_register_extension(&zend_extension_entry, NULL); @@ -395,26 +352,18 @@ static PHP_INI_MH(OnUpdateConfiguration) { } // If `zend_write_default` is not NULL it is already hooked. - if ((zend_hash_str_find( - SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked, "echo", - sizeof("echo") - 1) || - zend_hash_str_find( - SNUFFLEUPAGUS_G(config).config_disabled_functions_ret_hooked, "echo", - sizeof("echo") - 1)) && + if ((zend_hash_str_find(SPCFG(disabled_functions_hooked), ZEND_STRL("echo")) || + zend_hash_str_find(SPCFG(disabled_functions_ret_hooked), ZEND_STRL("echo"))) && NULL == zend_write_default && zend_write != hook_echo) { zend_write_default = zend_write; zend_write = hook_echo; } - SNUFFLEUPAGUS_G(config).hook_execute = - SNUFFLEUPAGUS_G(config) - .config_disabled_functions_reg->disabled_functions || - SNUFFLEUPAGUS_G(config) - .config_disabled_functions_reg_ret->disabled_functions || - zend_hash_num_elements( - SNUFFLEUPAGUS_G(config).config_disabled_functions) || - zend_hash_num_elements( - SNUFFLEUPAGUS_G(config).config_disabled_functions_ret); + SPG(hook_execute) = SPCFG(max_execution_depth) > 0 || + SPCFG(disabled_functions_reg).disabled_functions || + SPCFG(disabled_functions_reg_ret).disabled_functions || + (SPCFG(disabled_functions) && zend_hash_num_elements(SPCFG(disabled_functions))) || + (SPCFG(disabled_functions) && zend_hash_num_elements(SPCFG(disabled_functions_ret))); return SUCCESS; } diff --git a/src/sp_config.c b/src/sp_config.c index 4d96bbe..ec6c5a8 100644 --- a/src/sp_config.c +++ b/src/sp_config.c @@ -7,24 +7,24 @@ static zend_result sp_process_config_root(sp_parsed_keyword *parsed_rule) { sp_config_keyword sp_func[] = { - {parse_unserialize, SP_TOKEN_UNSERIALIZE_HMAC, SNUFFLEUPAGUS_G(config).config_unserialize}, - {parse_enable, SP_TOKEN_HARDEN_RANDOM, &(SNUFFLEUPAGUS_G(config).config_random->enable)}, - {parse_log_media, SP_TOKEN_LOG_MEDIA, &(SNUFFLEUPAGUS_G(config).log_media)}, + {parse_unserialize, SP_TOKEN_UNSERIALIZE_HMAC, &(SPCFG(unserialize))}, + {parse_enable, SP_TOKEN_HARDEN_RANDOM, &(SPCFG(random).enable)}, + {parse_log_media, SP_TOKEN_LOG_MEDIA, &(SPCFG(log_media))}, {parse_disabled_functions, SP_TOKEN_DISABLE_FUNC, NULL}, - {parse_readonly_exec, SP_TOKEN_READONLY_EXEC, SNUFFLEUPAGUS_G(config).config_readonly_exec}, - {parse_enable, SP_TOKEN_GLOBAL_STRICT, &(SNUFFLEUPAGUS_G(config).config_global_strict->enable)}, - {parse_upload_validation, SP_TOKEN_UPLOAD_VALIDATION, SNUFFLEUPAGUS_G(config).config_upload_validation}, + {parse_readonly_exec, SP_TOKEN_READONLY_EXEC, &(SPCFG(readonly_exec))}, + {parse_enable, SP_TOKEN_GLOBAL_STRICT, &(SPCFG(global_strict).enable)}, + {parse_upload_validation, SP_TOKEN_UPLOAD_VALIDATION, &(SPCFG(upload_validation))}, {parse_cookie, SP_TOKEN_COOKIE_ENCRYPTION, NULL}, {parse_global, SP_TOKEN_GLOBAL, NULL}, - {parse_enable, SP_TOKEN_AUTO_COOKIE_SECURE, &(SNUFFLEUPAGUS_G(config).config_auto_cookie_secure->enable)}, - {parse_enable, SP_TOKEN_DISABLE_XXE, &(SNUFFLEUPAGUS_G(config).config_disable_xxe->enable)}, - {parse_eval_filter_conf, SP_TOKEN_EVAL_BLACKLIST, &(SNUFFLEUPAGUS_G(config).config_eval->blacklist)}, - {parse_eval_filter_conf, SP_TOKEN_EVAL_WHITELIST, &(SNUFFLEUPAGUS_G(config).config_eval->whitelist)}, - {parse_session, SP_TOKEN_SESSION_ENCRYPTION, SNUFFLEUPAGUS_G(config).config_session}, - {parse_enable, SP_TOKEN_SLOPPY_COMPARISON, &(SNUFFLEUPAGUS_G(config).config_sloppy->enable)}, - {parse_wrapper_whitelist, SP_TOKEN_ALLOW_WRAPPERS, SNUFFLEUPAGUS_G(config).config_wrapper}, - {parse_ini_protection, SP_TOKEN_INI_PROTECTION, SNUFFLEUPAGUS_G(config).config_ini}, - {parse_ini_entry, SP_TOKEN_INI, SNUFFLEUPAGUS_G(config).config_unserialize}, + {parse_enable, SP_TOKEN_AUTO_COOKIE_SECURE, &(SPCFG(auto_cookie_secure).enable)}, + {parse_enable, SP_TOKEN_DISABLE_XXE, &(SPCFG(disable_xxe).enable)}, + {parse_eval_filter_conf, SP_TOKEN_EVAL_BLACKLIST, &(SPCFG(eval).blacklist)}, + {parse_eval_filter_conf, SP_TOKEN_EVAL_WHITELIST, &(SPCFG(eval).whitelist)}, + {parse_session, SP_TOKEN_SESSION_ENCRYPTION, &(SPCFG(session))}, + {parse_enable, SP_TOKEN_SLOPPY_COMPARISON, &(SPCFG(sloppy).enable)}, + {parse_wrapper_whitelist, SP_TOKEN_ALLOW_WRAPPERS, &(SPCFG(wrapper))}, + {parse_ini_protection, SP_TOKEN_INI_PROTECTION, &(SPCFG(ini))}, + {parse_ini_entry, SP_TOKEN_INI, NULL}, {NULL, NULL, NULL}}; return sp_process_rule(parsed_rule, sp_func); } diff --git a/src/sp_config.h b/src/sp_config.h index df36976..262050b 100644 --- a/src/sp_config.h +++ b/src/sp_config.h @@ -32,11 +32,6 @@ typedef struct { uint8_t mask; } sp_cidr; -typedef struct { - zend_string *encryption_key; - zend_string *cookies_env_var; -} sp_config_global; - typedef struct { bool enable; bool simulation; @@ -181,35 +176,6 @@ typedef struct { HashTable *entries; // ht of sp_ini_entry } sp_config_ini; -typedef struct { - sp_config_random *config_random; - sp_config_sloppy *config_sloppy; - sp_config_unserialize *config_unserialize; - sp_config_readonly_exec *config_readonly_exec; - sp_config_upload_validation *config_upload_validation; - sp_config_cookie *config_cookie; - sp_config_global *config_snuffleupagus; - sp_config_auto_cookie_secure *config_auto_cookie_secure; - sp_config_global_strict *config_global_strict; - sp_config_disable_xxe *config_disable_xxe; - sp_config_eval *config_eval; - sp_config_wrapper *config_wrapper; - sp_config_session *config_session; - sp_config_ini *config_ini; - bool hook_execute; - char log_media; - u_long max_execution_depth; - bool server_encode; - bool server_strip; - - HashTable *config_disabled_functions; - HashTable *config_disabled_functions_hooked; - HashTable *config_disabled_functions_ret; - HashTable *config_disabled_functions_ret_hooked; - sp_config_disabled_functions *config_disabled_functions_reg; - sp_config_disabled_functions *config_disabled_functions_reg_ret; -} sp_config; - #define SP_PARSE_FN_(fname, kwvar) int fname(char *token, sp_parsed_keyword *kwvar, void *retval) #define SP_PARSE_FN(fname) SP_PARSE_FN_(fname, parsed_rule) #define SP_PARSEKW_FN(fname) SP_PARSE_FN_(fname, kw) diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index bd8a9a1..f6af86b 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -49,12 +49,12 @@ SP_PARSE_FN(parse_session) { #endif if (cfg->encrypt) { - if (!SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var) { + if (!SPCFG(cookies_env_var)) { sp_log_err("config", "You're trying to use the session cookie encryption feature " "on line %zu without having set the `.cookie_env_var` option in " "`sp.global`: please set it first", parsed_rule->lineno); return SP_PARSER_ERROR; - } else if (!SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key) { + } else if (!SPCFG(encryption_key)) { sp_log_err("config", "You're trying to use the session cookie encryption feature " "on line %zu without having set the `.secret_key` option in " "`sp.global`: please set it first", parsed_rule->lineno); @@ -127,12 +127,12 @@ SP_PARSE_FN(parse_readonly_exec) { SP_PARSE_FN(parse_global) { sp_config_keyword config_keywords[] = { - {parse_str, SP_TOKEN_ENCRYPTION_KEY, &(SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)}, - {parse_str, SP_TOKEN_ENV_VAR, &(SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var)}, - {parse_log_media, SP_TOKEN_LOG_MEDIA, &(SNUFFLEUPAGUS_G(config).log_media)}, - {parse_ulong, SP_TOKEN_MAX_EXECUTION_DEPTH, &(SNUFFLEUPAGUS_G(config).max_execution_depth)}, - {parse_enable, SP_TOKEN_SERVER_ENCODE, &(SNUFFLEUPAGUS_G(config).server_encode)}, - {parse_enable, SP_TOKEN_SERVER_STRIP, &(SNUFFLEUPAGUS_G(config).server_strip)}, + {parse_str, SP_TOKEN_ENCRYPTION_KEY, &(SPCFG(encryption_key))}, + {parse_str, SP_TOKEN_ENV_VAR, &(SPCFG(cookies_env_var))}, + {parse_log_media, SP_TOKEN_LOG_MEDIA, &(SPCFG(log_media))}, + {parse_ulong, SP_TOKEN_MAX_EXECUTION_DEPTH, &(SPCFG(max_execution_depth))}, + {parse_enable, SP_TOKEN_SERVER_ENCODE, &(SPCFG(server_encode))}, + {parse_enable, SP_TOKEN_SERVER_STRIP, &(SPCFG(server_strip))}, {0, 0, 0}}; SP_PROCESS_CONFIG_KEYWORDS_ERR(); @@ -140,7 +140,7 @@ SP_PARSE_FN(parse_global) { } SP_PARSE_FN(parse_eval_filter_conf) { - sp_config_eval *cfg = SNUFFLEUPAGUS_G(config).config_eval; + sp_config_eval *cfg = &(SPCFG(eval)); sp_config_keyword config_keywords[] = { {parse_list, SP_TOKEN_LIST, retval}, @@ -186,11 +186,11 @@ SP_PARSE_FN(parse_cookie) { SP_PROCESS_CONFIG_KEYWORDS(goto err); if (cookie->encrypt) { - if (!SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var) { + if (!SPCFG(cookies_env_var)) { sp_log_err("config", "You're trying to use the cookie encryption feature on line %zu " "without having set the `." SP_TOKEN_ENV_VAR "` option in `sp.global`: please set it first", parsed_rule->lineno); goto err; - } else if (!SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key) { + } else if (!SPCFG(encryption_key)) { sp_log_err("config", "You're trying to use the cookie encryption feature " "on line %zu without having set the `." SP_TOKEN_ENCRYPTION_KEY "` option in " "`sp." SP_TOKEN_GLOBAL "`: please set it first", parsed_rule->lineno); @@ -220,7 +220,7 @@ SP_PARSE_FN(parse_cookie) { } } - SNUFFLEUPAGUS_G(config).config_cookie->cookies = sp_list_insert(SNUFFLEUPAGUS_G(config).config_cookie->cookies, cookie); + SPCFG(cookie).cookies = sp_list_insert(SPCFG(cookie).cookies, cookie); return SP_PARSER_STOP; @@ -316,7 +316,7 @@ SP_PARSE_FN(parse_disabled_functions) { goto out; } if (df->filename && (*ZSTR_VAL(df->filename) != '/') && - (0 != strncmp(ZSTR_VAL(df->filename), "phar://", strlen("phar://")))) { + (0 != strncmp(ZSTR_VAL(df->filename), ZEND_STRL("phar://")))) { sp_log_err("config", "Invalid configuration line: 'sp.disabled_functions': '.filename' must be an absolute path or a phar archive on line %zu", parsed_rule->lineno); goto out; } @@ -365,20 +365,20 @@ SP_PARSE_FN(parse_disabled_functions) { if (df->function && zend_string_equals_literal(df->function, "print")) { zend_string_release(df->function); - df->function = zend_string_init("echo", sizeof("echo") - 1, 1); + df->function = zend_string_init(ZEND_STRL("echo"), 1); } if (df->function && !df->functions_list) { if (df->ret || df->r_ret || df->ret_type) { - add_df_to_hashtable(SNUFFLEUPAGUS_G(config).config_disabled_functions_ret, df); + add_df_to_hashtable(SPCFG(disabled_functions_ret), df); } else { - add_df_to_hashtable(SNUFFLEUPAGUS_G(config).config_disabled_functions, df); + add_df_to_hashtable(SPCFG(disabled_functions), df); } } else { if (df->ret || df->r_ret || df->ret_type) { - SNUFFLEUPAGUS_G(config).config_disabled_functions_reg_ret->disabled_functions = sp_list_insert(SNUFFLEUPAGUS_G(config).config_disabled_functions_reg_ret->disabled_functions, df); + SPCFG(disabled_functions_reg_ret).disabled_functions = sp_list_insert(SPCFG(disabled_functions_reg_ret).disabled_functions, df); } else { - SNUFFLEUPAGUS_G(config).config_disabled_functions_reg->disabled_functions = sp_list_insert(SNUFFLEUPAGUS_G(config).config_disabled_functions_reg->disabled_functions, df); + SPCFG(disabled_functions_reg).disabled_functions = sp_list_insert(SPCFG(disabled_functions_reg).disabled_functions, df); } } return SP_PARSER_STOP; @@ -493,7 +493,7 @@ SP_PARSE_FN(parse_ini_entry) { } entry->access = ro - rw; - zend_hash_add_ptr(SNUFFLEUPAGUS_G(config).config_ini->entries, entry->key, entry); + zend_hash_add_ptr(SPCFG(ini).entries, entry->key, entry); return SP_PARSER_STOP; err: diff --git a/src/sp_cookie_encryption.c b/src/sp_cookie_encryption.c index 7bcedd2..b2cff66 100644 --- a/src/sp_cookie_encryption.c +++ b/src/sp_cookie_encryption.c @@ -1,7 +1,7 @@ #include "php_snuffleupagus.h" static inline const sp_cookie *sp_lookup_cookie_config(const zend_string *key) { - const sp_list_node *it = SNUFFLEUPAGUS_G(config).config_cookie->cookies; + const sp_list_node *it = SPCFG(cookie).cookies; while (it) { const sp_cookie *config = it->data; @@ -133,11 +133,11 @@ PHP_FUNCTION(sp_setcookie) { } /* If the request was issued over HTTPS, the cookie should be "secure" */ - if (SNUFFLEUPAGUS_G(config).config_auto_cookie_secure) { + if (SPCFG(auto_cookie_secure).enable) { const zval server_vars = PG(http_globals)[TRACK_VARS_SERVER]; if (Z_TYPE(server_vars) == IS_ARRAY) { const zval *is_https = - zend_hash_str_find(Z_ARRVAL(server_vars), "HTTPS", strlen("HTTPS")); + zend_hash_str_find(Z_ARRVAL(server_vars), ZEND_STRL("HTTPS")); if (NULL != is_https) { secure = 1; } diff --git a/src/sp_crypt.c b/src/sp_crypt.c index ff8f65e..c1d9403 100644 --- a/src/sp_crypt.c +++ b/src/sp_crypt.c @@ -3,13 +3,10 @@ void generate_key(unsigned char *key) { PHP_SHA256_CTX ctx; const char *user_agent = getenv("HTTP_USER_AGENT"); - const zend_string *env_var_zend = - SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var; - const zend_string *encryption_key_zend = - SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key; + const zend_string *env_var_zend = SPCFG(cookies_env_var); + const zend_string *encryption_key_zend = SPCFG(encryption_key); const char *env_var = (env_var_zend ? getenv(ZSTR_VAL(env_var_zend)) : NULL); - const char *encryption_key = - (encryption_key_zend ? ZSTR_VAL(encryption_key_zend) : NULL); + const char *encryption_key = (encryption_key_zend ? ZSTR_VAL(encryption_key_zend) : NULL); assert(32 == crypto_secretbox_KEYBYTES); // 32 is the size of a SHA256. assert(encryption_key); // Encryption key can't be NULL diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c index 6ff3915..4ef72bf 100644 --- a/src/sp_disabled_functions.c +++ b/src/sp_disabled_functions.c @@ -479,21 +479,13 @@ ZEND_FUNCTION(check_disabled_function) { zif_handler orig_handler; const char* current_function_name = get_active_function_name(TSRMLS_C); - should_disable_ht( - execute_data, current_function_name, NULL, NULL, - SNUFFLEUPAGUS_G(config).config_disabled_functions_reg->disabled_functions, - SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked); + should_disable_ht(execute_data, current_function_name, NULL, NULL, SPCFG(disabled_functions_reg).disabled_functions, SPCFG(disabled_functions_hooked)); orig_handler = zend_hash_str_find_ptr( - SNUFFLEUPAGUS_G(disabled_functions_hook), current_function_name, + SPG(disabled_functions_hook), current_function_name, strlen(current_function_name)); orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); - should_drop_on_ret_ht( - return_value, current_function_name, - SNUFFLEUPAGUS_G(config) - .config_disabled_functions_reg_ret->disabled_functions, - SNUFFLEUPAGUS_G(config).config_disabled_functions_ret_hooked, - execute_data); + should_drop_on_ret_ht(return_value, current_function_name, SPCFG(disabled_functions_reg_ret).disabled_functions, SPCFG(disabled_functions_ret_hooked), execute_data); } static int hook_functions_regexp(const sp_list_node* config) { @@ -547,10 +539,10 @@ ZEND_FUNCTION(eval_blacklist_callback) { } zend_string_release(tmp); - if (SNUFFLEUPAGUS_G(in_eval) > 0) { + if (SPG(in_eval) > 0) { // zend_string* filename = get_eval_filename(zend_get_executed_filename()); // const int line_number = zend_get_executed_lineno(TSRMLS_C); - const sp_config_eval* config_eval = SNUFFLEUPAGUS_G(config).config_eval; + const sp_config_eval* config_eval = &(SPCFG(eval)); if (config_eval->dump) { sp_log_request(config_eval->dump, config_eval->textual_representation); @@ -565,7 +557,7 @@ ZEND_FUNCTION(eval_blacklist_callback) { whitelisted: orig_handler = zend_hash_str_find_ptr( - SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook), current_function_name, + SPG(sp_eval_blacklist_functions_hook), current_function_name, strlen(current_function_name)); orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); } @@ -575,26 +567,19 @@ int hook_disabled_functions(void) { int ret = SUCCESS; - hook_functions(SNUFFLEUPAGUS_G(config).config_disabled_functions, - SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked); + hook_functions(SPCFG(disabled_functions), SPCFG(disabled_functions_hooked)); + hook_functions(SPCFG(disabled_functions_ret), SPCFG(disabled_functions_ret_hooked)); - hook_functions(SNUFFLEUPAGUS_G(config).config_disabled_functions_ret, - SNUFFLEUPAGUS_G(config).config_disabled_functions_ret_hooked); + ret |= hook_functions_regexp(SPCFG(disabled_functions_reg).disabled_functions); - ret |= hook_functions_regexp( - SNUFFLEUPAGUS_G(config) - .config_disabled_functions_reg->disabled_functions); + ret |= hook_functions_regexp(SPCFG(disabled_functions_reg_ret).disabled_functions); - ret |= hook_functions_regexp( - SNUFFLEUPAGUS_G(config) - .config_disabled_functions_reg_ret->disabled_functions); - - if (NULL != SNUFFLEUPAGUS_G(config).config_eval->blacklist) { - sp_list_node* it = SNUFFLEUPAGUS_G(config).config_eval->blacklist; + if (NULL != SPCFG(eval).blacklist) { + sp_list_node* it = SPCFG(eval).blacklist; while (it) { hook_function(ZSTR_VAL((zend_string*)it->data), - SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook), + SPG(sp_eval_blacklist_functions_hook), PHP_FN(eval_blacklist_callback)); it = it->next; } @@ -611,10 +596,7 @@ int hook_echo(const char* str, size_t str_length) { #endif zend_string* zs = zend_string_init(str, str_length, 0); - should_disable_ht( - EG(current_execute_data), "echo", zs, NULL, - SNUFFLEUPAGUS_G(config).config_disabled_functions_reg->disabled_functions, - SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked); + should_disable_ht(EG(current_execute_data), "echo", zs, NULL, SPCFG(disabled_functions_reg).disabled_functions, SPCFG(disabled_functions_hooked)); zend_string_release(zs); diff --git a/src/sp_execute.c b/src/sp_execute.c index 41257ad..ccb7508 100644 --- a/src/sp_execute.c +++ b/src/sp_execute.c @@ -8,8 +8,7 @@ static int (*orig_zend_stream_open)(const char *filename, // FIXME handle symlink ZEND_COLD static inline void terminate_if_writable(const char *filename) { - const sp_config_readonly_exec *config_ro_exec = - SNUFFLEUPAGUS_G(config).config_readonly_exec; + const sp_config_readonly_exec *config_ro_exec = &(SPCFG(readonly_exec)); if (0 == access(filename, W_OK)) { if (config_ro_exec->dump) { @@ -43,21 +42,18 @@ inline static void is_builtin_matching( return; } - should_disable_ht( - EG(current_execute_data), function_name, param_value, param_name, - SNUFFLEUPAGUS_G(config).config_disabled_functions_reg->disabled_functions, - ht); + should_disable_ht(EG(current_execute_data), function_name, param_value, param_name, SPCFG(disabled_functions_reg).disabled_functions, ht); } static void ZEND_HOT is_in_eval_and_whitelisted(const zend_execute_data *execute_data) { - const sp_config_eval *config_eval = SNUFFLEUPAGUS_G(config).config_eval; + const sp_config_eval *config_eval = &(SPCFG(eval)); - if (EXPECTED(0 == SNUFFLEUPAGUS_G(in_eval))) { + if (EXPECTED(0 == SPG(in_eval))) { return; } - if (EXPECTED(NULL == SNUFFLEUPAGUS_G(config).config_eval->whitelist)) { + if (EXPECTED(NULL == config_eval->whitelist)) { return; } @@ -113,50 +109,45 @@ zend_string *get_eval_filename(const char *const filename) { } static inline void sp_orig_execute(zend_execute_data *execute_data) { - SNUFFLEUPAGUS_G(execution_depth)++; - if (SNUFFLEUPAGUS_G(execution_depth) > SNUFFLEUPAGUS_G(config).max_execution_depth && SNUFFLEUPAGUS_G(config).max_execution_depth > 0) { + SPG(execution_depth)++; + if (SPCFG(max_execution_depth) > 0 && SPG(execution_depth) > SPCFG(max_execution_depth)) { sp_log_drop("execute", "Maximum recursion limit reached. Script terminated."); } orig_execute_ex(execute_data); - SNUFFLEUPAGUS_G(execution_depth)--; + SPG(execution_depth)--; } static void sp_execute_ex(zend_execute_data *execute_data) { is_in_eval_and_whitelisted(execute_data); - const HashTable *config_disabled_functions = - SNUFFLEUPAGUS_G(config).config_disabled_functions; + const HashTable *config_disabled_functions = SPCFG(disabled_functions); if (!execute_data) { return; // LCOV_EXCL_LINE } if (UNEXPECTED(EX(func)->op_array.type == ZEND_EVAL_CODE)) { - const sp_list_node *config = zend_hash_str_find_ptr( - config_disabled_functions, "eval", sizeof("eval") - 1); + const sp_list_node *config = zend_hash_str_find_ptr(config_disabled_functions, ZEND_STRL("eval")); zend_string *filename = get_eval_filename(zend_get_executed_filename()); - is_builtin_matching(filename, "eval", NULL, config, - config_disabled_functions); + is_builtin_matching(filename, "eval", NULL, config, config_disabled_functions); zend_string_release(filename); - SNUFFLEUPAGUS_G(in_eval)++; + SPG(in_eval)++; sp_orig_execute(execute_data); - SNUFFLEUPAGUS_G(in_eval)--; + SPG(in_eval)--; return; } if (NULL != EX(func)->op_array.filename) { - if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { + if (SPCFG(readonly_exec).enable) { terminate_if_writable(ZSTR_VAL(EX(func)->op_array.filename)); } } - if (SNUFFLEUPAGUS_G(config).hook_execute) { + if (SPG(hook_execute)) { char *function_name = get_complete_function_path(execute_data); zval ret_val; - const sp_list_node *config_disabled_functions_reg = - SNUFFLEUPAGUS_G(config) - .config_disabled_functions_reg->disabled_functions; + const sp_list_node *config_disabled_functions_reg = SPCFG(disabled_functions_reg).disabled_functions; if (!function_name) { sp_orig_execute(execute_data); @@ -195,11 +186,7 @@ static void sp_execute_ex(zend_execute_data *execute_data) { sp_orig_execute(execute_data); - should_drop_on_ret_ht( - EX(return_value), function_name, - SNUFFLEUPAGUS_G(config) - .config_disabled_functions_reg_ret->disabled_functions, - SNUFFLEUPAGUS_G(config).config_disabled_functions_ret, execute_data); + should_drop_on_ret_ht(EX(return_value), function_name, SPCFG(disabled_functions_reg_ret).disabled_functions, SPCFG(disabled_functions_ret), execute_data); efree(function_name); if (EX(return_value) == &ret_val) { @@ -231,41 +218,36 @@ static int sp_stream_open(const char *filename, zend_file_handle *handle) { } zend_string *zend_filename = zend_string_init(filename, strlen(filename), 0); - const HashTable *disabled_functions_hooked = - SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked; + const HashTable *disabled_functions_hooked = SPCFG(disabled_functions_hooked); switch (data->opline->opcode) { case ZEND_INCLUDE_OR_EVAL: - if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { + if (SPCFG(readonly_exec).enable) { terminate_if_writable(filename); } switch (data->opline->extended_value) { case ZEND_INCLUDE: is_builtin_matching( zend_filename, "include", "inclusion path", - zend_hash_str_find_ptr(disabled_functions_hooked, "include", - sizeof("include") - 1), + zend_hash_str_find_ptr(disabled_functions_hooked, ZEND_STRL("include")), disabled_functions_hooked); break; case ZEND_REQUIRE: is_builtin_matching( zend_filename, "require", "inclusion path", - zend_hash_str_find_ptr(disabled_functions_hooked, "require", - sizeof("require") - 1), + zend_hash_str_find_ptr(disabled_functions_hooked, ZEND_STRL("require")), disabled_functions_hooked); break; case ZEND_REQUIRE_ONCE: is_builtin_matching( zend_filename, "require_once", "inclusion path", - zend_hash_str_find_ptr(disabled_functions_hooked, "require_once", - sizeof("require_once") - 1), + zend_hash_str_find_ptr(disabled_functions_hooked, ZEND_STRL("require_once")), disabled_functions_hooked); break; case ZEND_INCLUDE_ONCE: is_builtin_matching( zend_filename, "include_once", "inclusion path", - zend_hash_str_find_ptr(disabled_functions_hooked, "include_once", - sizeof("include_once") - 1), + zend_hash_str_find_ptr(disabled_functions_hooked, ZEND_STRL("include_once")), disabled_functions_hooked); break; EMPTY_SWITCH_DEFAULT_CASE(); // LCOV_EXCL_LINE diff --git a/src/sp_harden_rand.c b/src/sp_harden_rand.c index 43c2a5b..3e9bcb3 100644 --- a/src/sp_harden_rand.c +++ b/src/sp_harden_rand.c @@ -54,8 +54,7 @@ PHP_FUNCTION(sp_rand) { /* call the original `rand` function, * since we might no be the only ones to hook it*/ - orig_handler = zend_hash_str_find_ptr( - SNUFFLEUPAGUS_G(sp_internal_functions_hook), "rand", sizeof("rand") - 1); + orig_handler = zend_hash_str_find_ptr(SPG(sp_internal_functions_hook), ZEND_STRL("rand")); orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); random_int_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU); @@ -67,8 +66,7 @@ PHP_FUNCTION(sp_mt_rand) { /* call the original `mt_rand` function, * since we might no be the only ones to hook it*/ orig_handler = - zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), - "mt_rand", sizeof("mt_rand") - 1); + zend_hash_str_find_ptr(SPG(sp_internal_functions_hook), ZEND_STRL("mt_rand")); orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); random_int_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU); diff --git a/src/sp_ifilter.c b/src/sp_ifilter.c index a475c1e..8099882 100644 --- a/src/sp_ifilter.c +++ b/src/sp_ifilter.c @@ -77,12 +77,12 @@ static void sp_register_server_variables(zval *track_vars_array) { svars = Z_ARRVAL_P(track_vars_array); - if (SNUFFLEUPAGUS_G(config).server_encode) { + if (SPCFG(server_encode)) { sp_server_encode(svars, ZEND_STRL("REQUEST_URI")); sp_server_encode(svars, ZEND_STRL("QUERY_STRING")); } - if (SNUFFLEUPAGUS_G(config).server_strip) { + if (SPCFG(server_strip)) { sp_server_strip(svars, ZEND_STRL("PHP_SELF")); sp_server_strip(svars, ZEND_STRL("HTTP_HOST")); sp_server_strip(svars, ZEND_STRL("HTTP_USER_AGENT")); diff --git a/src/sp_ini.c b/src/sp_ini.c index 5777ca3..2238e3a 100644 --- a/src/sp_ini.c +++ b/src/sp_ini.c @@ -17,7 +17,7 @@ static bool /* success */ sp_ini_check(zend_string *varname, zend_string *new_va return false; } - sp_config_ini *cfg = SNUFFLEUPAGUS_G(config).config_ini; + sp_config_ini *cfg = &(SPCFG(ini)); sp_ini_entry *entry = zend_hash_find_ptr(cfg->entries, varname); if (sp_entry_p) { *sp_entry_p = entry; @@ -92,7 +92,7 @@ static PHP_INI_MH(sp_ini_onmodify) { } void sp_hook_ini() { - sp_config_ini *cfg = SNUFFLEUPAGUS_G(config).config_ini; + sp_config_ini *cfg = &(SPCFG(ini)); sp_ini_entry *sp_entry; zend_ini_entry *ini_entry; ZEND_HASH_FOREACH_PTR(cfg->entries, sp_entry) @@ -129,7 +129,7 @@ void sp_hook_ini() { void sp_unhook_ini() { sp_ini_entry *sp_entry; zend_ini_entry *ini_entry; - ZEND_HASH_FOREACH_PTR(SNUFFLEUPAGUS_G(config).config_ini->entries, sp_entry) + ZEND_HASH_FOREACH_PTR(SPCFG(ini).entries, sp_entry) if (!sp_entry->orig_onmodify) { // not hooked or no original onmodify continue; diff --git a/src/sp_session.c b/src/sp_session.c index 64233d1..b54849e 100644 --- a/src/sp_session.c +++ b/src/sp_session.c @@ -25,7 +25,7 @@ static int (*previous_sessionRINIT)(INIT_FUNC_ARGS) = NULL; static ZEND_INI_MH((*old_OnUpdateSaveHandler)) = NULL; static void check_sid_length(zend_string *sid) { - const sp_config_session *cfg = SNUFFLEUPAGUS_G(config).config_session; + const sp_config_session *cfg = &(SPCFG(session)); if (sid) { if (cfg->sid_min_length && ZSTR_LEN(sid) < cfg->sid_min_length) { @@ -38,7 +38,7 @@ static void check_sid_length(zend_string *sid) { } static int sp_hook_s_read(PS_READ_ARGS) { - const sp_config_session *cfg = SNUFFLEUPAGUS_G(config).config_session; + const sp_config_session *cfg = &(SPCFG(session)); check_sid_length(key); int r = old_s_read(mod_data, key, val, maxlifetime); @@ -65,7 +65,7 @@ static int sp_hook_s_read(PS_READ_ARGS) { } static int sp_hook_s_write(PS_WRITE_ARGS) { - const sp_config_session *cfg = SNUFFLEUPAGUS_G(config).config_session; + const sp_config_session *cfg = &(SPCFG(session)); check_sid_length(key); if (ZSTR_LEN(val) > 0 && cfg->encrypt) { diff --git a/src/sp_sloppy.c b/src/sp_sloppy.c index ff2d644..8afddc9 100644 --- a/src/sp_sloppy.c +++ b/src/sp_sloppy.c @@ -69,7 +69,7 @@ static void array_handler(INTERNAL_FUNCTION_PARAMETERS, const char* name, ZVAL_STRING(&func_name, name); - handler = zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), + handler = zend_hash_str_find_ptr(SPG(sp_internal_functions_hook), name, size); zend_internal_function* func = zend_hash_str_find_ptr(CG(function_table), name, size); diff --git a/src/sp_unserialize.c b/src/sp_unserialize.c index 82b2cef..1c9f731 100644 --- a/src/sp_unserialize.c +++ b/src/sp_unserialize.c @@ -4,10 +4,10 @@ PHP_FUNCTION(sp_serialize) { zif_handler orig_handler; /* Call the original `serialize` function. */ - orig_handler = - zend_hash_str_find_ptr(SNUFFLEUPAGUS_G(sp_internal_functions_hook), - "serialize", sizeof("serialize") - 1); - orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); + orig_handler = zend_hash_str_find_ptr(SPG(sp_internal_functions_hook), ZEND_STRL("serialize")); + if (orig_handler) { + orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); + } /* Compute the HMAC of the textual representation of the serialized data*/ zval func_name; @@ -19,7 +19,7 @@ PHP_FUNCTION(sp_serialize) { params[1] = *return_value; ZVAL_STRING( ¶ms[2], - ZSTR_VAL(SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)); + ZSTR_VAL(SPCFG(encryption_key))); call_user_function(CG(function_table), NULL, &func_name, &hmac, 3, params); size_t len = Z_STRLEN_P(return_value) + Z_STRLEN(hmac); @@ -46,8 +46,7 @@ PHP_FUNCTION(sp_unserialize) { size_t buf_len = 0; zval *opts = NULL; - const sp_config_unserialize *config_unserialize = - SNUFFLEUPAGUS_G(config).config_unserialize; + const sp_config_unserialize *config_unserialize = &(SPCFG(unserialize)); if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|a", &buf, &buf_len, &opts) == FAILURE) { @@ -71,7 +70,7 @@ PHP_FUNCTION(sp_unserialize) { ZVAL_STRING(¶ms[1], serialized_str); ZVAL_STRING( ¶ms[2], - ZSTR_VAL(SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)); + ZSTR_VAL(SPCFG(encryption_key))); call_user_function(CG(function_table), NULL, &func_name, &expected_hmac, 3, params); @@ -81,9 +80,7 @@ PHP_FUNCTION(sp_unserialize) { } if (0 == status) { - if ((orig_handler = zend_hash_str_find_ptr( - SNUFFLEUPAGUS_G(sp_internal_functions_hook), "unserialize", - sizeof("unserialize") - 1))) { + if ((orig_handler = zend_hash_str_find_ptr(SPG(sp_internal_functions_hook), ZEND_STRL("unserialize")))) { orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); } } else { @@ -93,9 +90,7 @@ PHP_FUNCTION(sp_unserialize) { } if (true == config_unserialize->simulation) { sp_log_simulation("unserialize", "Invalid HMAC for %s", serialized_str); - if ((orig_handler = zend_hash_str_find_ptr( - SNUFFLEUPAGUS_G(sp_internal_functions_hook), "unserialize", - sizeof("unserialize") - 1))) { + if ((orig_handler = zend_hash_str_find_ptr(SPG(sp_internal_functions_hook), ZEND_STRL("unserialize")))) { orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); } } else { diff --git a/src/sp_upload_validation.c b/src/sp_upload_validation.c index 4d44011..bff7e43 100644 --- a/src/sp_upload_validation.c +++ b/src/sp_upload_validation.c @@ -32,8 +32,7 @@ int sp_rfc1867_callback(unsigned int event, void *event_data, void **extra) { if (event == MULTIPART_EVENT_END) { zend_string *file_key __attribute__((unused)) = NULL; - const sp_config_upload_validation *config_upload = - SNUFFLEUPAGUS_G(config).config_upload_validation; + const sp_config_upload_validation *config_upload = &(SPCFG(upload_validation)); zval *file; pid_t pid; @@ -44,12 +43,9 @@ int sp_rfc1867_callback(unsigned int event, void *event_data, void **extra) { ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL(PG(http_globals)[TRACK_VARS_FILES]), file_key, file) { // for each uploaded file - char *filename = Z_STRVAL_P( - zend_hash_str_find(Z_ARRVAL_P(file), "name", sizeof("name") - 1)); - char *tmp_name = Z_STRVAL_P(zend_hash_str_find( - Z_ARRVAL_P(file), "tmp_name", sizeof("tmp_name") - 1)); - size_t filesize = Z_LVAL_P( - zend_hash_str_find(Z_ARRVAL_P(file), "size", sizeof("size") - 1)); + char *filename = Z_STRVAL_P(zend_hash_str_find(Z_ARRVAL_P(file), ZEND_STRL("name"))); + char *tmp_name = Z_STRVAL_P(zend_hash_str_find(Z_ARRVAL_P(file), ZEND_STRL("tmp_name"))); + size_t filesize = Z_LVAL_P(zend_hash_str_find(Z_ARRVAL_P(file), ZEND_STRL("size"))); char *cmd[3] = {0}; char *env[5] = {0}; diff --git a/src/sp_utils.c b/src/sp_utils.c index de19321..ff85494 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c @@ -46,7 +46,7 @@ void sp_log_msgf(char const* restrict feature, int level, int type, break; } - switch (SNUFFLEUPAGUS_G(config).log_media) { + switch (SPCFG(log_media)) { case SP_SYSLOG: { const char* error_filename = zend_get_executed_filename(); int syslog_level = (level == E_ERROR) ? LOG_ERR : LOG_INFO; @@ -244,17 +244,17 @@ const zend_string* sp_zval_to_zend_string(const zval* zv) { return Z_STR_P(zv); } case IS_FALSE: - return zend_string_init("FALSE", sizeof("FALSE") - 1, 0); + return zend_string_init(ZEND_STRL("FALSE"), 0); case IS_TRUE: - return zend_string_init("TRUE", sizeof("TRUE") - 1, 0); + return zend_string_init(ZEND_STRL("TRUE"), 0); case IS_NULL: - return zend_string_init("NULL", sizeof("NULL") - 1, 0); + return zend_string_init(ZEND_STRL("NULL"), 0); case IS_OBJECT: - return zend_string_init("OBJECT", sizeof("OBJECT") - 1, 0); + return zend_string_init(ZEND_STRL("OBJECT"), 0); case IS_ARRAY: - return zend_string_init("ARRAY", sizeof("ARRAY") - 1, 0); + return zend_string_init(ZEND_STRL("ARRAY"), 0); case IS_RESOURCE: - return zend_string_init("RESOURCE", sizeof("RESOURCE") - 1, 0); + return zend_string_init(ZEND_STRL("RESOURCE"), 0); default: // LCOV_EXCL_LINE return zend_string_init("", 0, 0); // LCOV_EXCL_LINE } @@ -432,7 +432,7 @@ bool hook_function(const char* original_name, HashTable* hook_table, if (NULL == mb_name) { return FAILURE; } - memcpy(mb_name, "mb_", sizeof("mb_") - 1); + memcpy(mb_name, ZEND_STRL("mb_")); memcpy(mb_name + 3, VAR_AND_LEN(original_name)); _hook_function(mb_name, hook_table, new_function); efree(mb_name); @@ -471,7 +471,7 @@ void unhook_functions(HashTable *ht) { } bool check_is_in_eval_whitelist(const zend_string* const function_name) { - const sp_list_node* it = SNUFFLEUPAGUS_G(config).config_eval->whitelist; + const sp_list_node* it = SPCFG(eval).whitelist; if (!it) { return false; } diff --git a/src/sp_utils.h b/src/sp_utils.h index ef626a3..27c8bfa 100644 --- a/src/sp_utils.h +++ b/src/sp_utils.h @@ -23,10 +23,10 @@ #define SHA256_SIZE 32 #define HOOK_FUNCTION(original_name, hook_table, new_function) \ - hook_function(original_name, SNUFFLEUPAGUS_G(hook_table), new_function) + hook_function(original_name, SPG(hook_table), new_function) #define HOOK_FUNCTION_BY_REGEXP(regexp, hook_table, new_function) \ - hook_regexp(regexp, SNUFFLEUPAGUS_G(hook_table), new_function) + hook_regexp(regexp, SPG(hook_table), new_function) #define SP_TYPE_LOG (0) #define SP_TYPE_DROP (1) diff --git a/src/sp_wrapper.c b/src/sp_wrapper.c index 7610114..1538e33 100644 --- a/src/sp_wrapper.c +++ b/src/sp_wrapper.c @@ -1,7 +1,7 @@ #include "php_snuffleupagus.h" static bool wrapper_is_whitelisted(const zend_string *const zs) { - const sp_list_node *list = SNUFFLEUPAGUS_G(config).config_wrapper->whitelist; + const sp_list_node *list = SPCFG(wrapper).whitelist; if (!zs) { return false; // LCOV_EXCL_LINE @@ -38,8 +38,7 @@ void sp_disable_wrapper() { zend_hash_destroy(orig_complete); pefree(orig_complete, 1); - SNUFFLEUPAGUS_G(config).config_wrapper->num_wrapper = - zend_hash_num_elements(orig); + SPCFG(wrapper).num_wrapper = zend_hash_num_elements(orig); } PHP_FUNCTION(sp_stream_wrapper_register) { @@ -53,9 +52,7 @@ PHP_FUNCTION(sp_stream_wrapper_register) { // LCOV_EXCL_BR_END if (wrapper_is_whitelisted(protocol_name)) { - orig_handler = zend_hash_str_find_ptr( - SNUFFLEUPAGUS_G(sp_internal_functions_hook), "stream_wrapper_register", - sizeof("stream_wrapper_register") - 1); + orig_handler = zend_hash_str_find_ptr(SPG(sp_internal_functions_hook), ZEND_STRL("stream_wrapper_register")); orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); } } -- cgit v1.3 From 713cb08b58d4e5dd5e7e80b1f82e27cbe52d4381 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Thu, 11 Nov 2021 13:15:52 +0100 Subject: inverted logic. set xxe_protection.enable() instead of disable_xxe.disable() --- config/default.rules | 2 +- config/default_php8.rules | 2 +- config/suhosin.rules | 2 +- doc/source/config.rst | 7 ++++--- src/php_snuffleupagus.h | 2 +- src/snuffleupagus.c | 2 +- src/sp_config.c | 2 +- src/sp_config.h | 4 ++-- src/tests/xxe/config/disable_xxe.ini | 2 +- src/tests/xxe/config/disable_xxe_disable.ini | 2 +- src/tests/xxe/disable_xxe_dom_disabled.phpt | 4 ++-- src/tests/xxe/disable_xxe_simplexml.phpt | 3 ++- src/tests/xxe/disable_xxe_simplexml_oop.phpt | 3 ++- src/tests/xxe/disable_xxe_xml_parse.phpt | 5 ++++- 14 files changed, 24 insertions(+), 18 deletions(-) (limited to 'src/php_snuffleupagus.h') diff --git a/config/default.rules b/config/default.rules index b964073..2de703b 100644 --- a/config/default.rules +++ b/config/default.rules @@ -7,7 +7,7 @@ sp.harden_random.enable(); # Disabled XXE -sp.disable_xxe.enable(); +sp.xxe_protection.enable(); # Global configuration variables # sp.global.secret_key("YOU _DO_ NEED TO CHANGE THIS WITH SOME RANDOM CHARACTERS."); diff --git a/config/default_php8.rules b/config/default_php8.rules index de2da5c..1d16191 100644 --- a/config/default_php8.rules +++ b/config/default_php8.rules @@ -8,7 +8,7 @@ sp.harden_random.enable(); # Disabled XXE -sp.disable_xxe.enable(); +sp.xxe_protection.enable(); # Global configuration variables # sp.global.secret_key("YOU _DO_ NEED TO CHANGE THIS WITH SOME RANDOM CHARACTERS."); diff --git a/config/suhosin.rules b/config/suhosin.rules index 4beb4c8..0bdc453 100644 --- a/config/suhosin.rules +++ b/config/suhosin.rules @@ -276,6 +276,6 @@ sp.harden_random.enable(); sp.auto_cookie_secure.enable(); #sp.cookie.name("cookie1").samesite("lax"); #sp.cookie.name("cookie2").samesite("strict");; -sp.disable_xxe.enable(); +sp.xxe_protection.enable(); #sp.sloppy_comparison.enable(); diff --git a/doc/source/config.rst b/doc/source/config.rst index 10b0afd..63ddf7b 100644 --- a/doc/source/config.rst +++ b/doc/source/config.rst @@ -293,14 +293,15 @@ It can either be ``enabled`` or ``disabled`` and can be used in ``simulation`` m sp.upload_validation.script("/var/www/is_valid_php.py").enable(); -disable_xxe +xxe_protection ^^^^^^^^^^^ -:ref:`disable_xxe `, enabled by default, will prevent XXE attacks by disabling the loading of external entities (``libxml_disable_entity_loader``) in the XML parser. +:ref:`xxe_protection `, disabled by default, will prevent XXE attacks by disabling the loading of external entities (``libxml_disable_entity_loader``) in the XML parser. :: - sp.disable_xxe.enable(); + sp.xxe_protection.enable(); + sp.xxe_protection.disable(); Whitelist of stream-wrappers diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index 308031b..03c9bb6 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -116,7 +116,7 @@ sp_config_upload_validation config_upload_validation; sp_config_cookie config_cookie; sp_config_auto_cookie_secure config_auto_cookie_secure; sp_config_global_strict config_global_strict; -sp_config_disable_xxe config_disable_xxe; +sp_config_xxe_protection config_xxe_protection; sp_config_eval config_eval; sp_config_wrapper config_wrapper; sp_config_session config_session; diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 6fd6f25..c96a911 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -314,7 +314,7 @@ static PHP_INI_MH(OnUpdateConfiguration) { hook_upload(); } - if (SPCFG(disable_xxe).enable == 0) { + if (SPCFG(xxe_protection).enable) { hook_libxml_disable_entity_loader(); } diff --git a/src/sp_config.c b/src/sp_config.c index ec6c5a8..bc9aa0d 100644 --- a/src/sp_config.c +++ b/src/sp_config.c @@ -17,7 +17,7 @@ static zend_result sp_process_config_root(sp_parsed_keyword *parsed_rule) { {parse_cookie, SP_TOKEN_COOKIE_ENCRYPTION, NULL}, {parse_global, SP_TOKEN_GLOBAL, NULL}, {parse_enable, SP_TOKEN_AUTO_COOKIE_SECURE, &(SPCFG(auto_cookie_secure).enable)}, - {parse_enable, SP_TOKEN_DISABLE_XXE, &(SPCFG(disable_xxe).enable)}, + {parse_enable, SP_TOKEN_XXE_PROTECTION, &(SPCFG(xxe_protection).enable)}, {parse_eval_filter_conf, SP_TOKEN_EVAL_BLACKLIST, &(SPCFG(eval).blacklist)}, {parse_eval_filter_conf, SP_TOKEN_EVAL_WHITELIST, &(SPCFG(eval).whitelist)}, {parse_session, SP_TOKEN_SESSION_ENCRYPTION, &(SPCFG(session))}, diff --git a/src/sp_config.h b/src/sp_config.h index 262050b..a557105 100644 --- a/src/sp_config.h +++ b/src/sp_config.h @@ -57,7 +57,7 @@ typedef struct { typedef struct { bool enable; -} sp_config_disable_xxe; +} sp_config_xxe_protection; typedef struct { enum samesite_type { strict = 1, lax = 2 } samesite; @@ -202,7 +202,7 @@ typedef struct { #define SP_TOKEN_READONLY_EXEC "readonly_exec" #define SP_TOKEN_UNSERIALIZE_HMAC "unserialize_hmac" #define SP_TOKEN_UPLOAD_VALIDATION "upload_validation" -#define SP_TOKEN_DISABLE_XXE "disable_xxe" +#define SP_TOKEN_XXE_PROTECTION "xxe_protection" #define SP_TOKEN_EVAL_BLACKLIST "eval_blacklist" #define SP_TOKEN_EVAL_WHITELIST "eval_whitelist" #define SP_TOKEN_SLOPPY_COMPARISON "sloppy_comparison" diff --git a/src/tests/xxe/config/disable_xxe.ini b/src/tests/xxe/config/disable_xxe.ini index bc9d1f2..a50a3b9 100644 --- a/src/tests/xxe/config/disable_xxe.ini +++ b/src/tests/xxe/config/disable_xxe.ini @@ -1 +1 @@ -sp.disable_xxe.enable(); +sp.xxe_protection.enable(); diff --git a/src/tests/xxe/config/disable_xxe_disable.ini b/src/tests/xxe/config/disable_xxe_disable.ini index bb1e432..eaf5755 100644 --- a/src/tests/xxe/config/disable_xxe_disable.ini +++ b/src/tests/xxe/config/disable_xxe_disable.ini @@ -1 +1 @@ -sp.disable_xxe.disable(); +sp.xxe_protection.disable(); diff --git a/src/tests/xxe/disable_xxe_dom_disabled.phpt b/src/tests/xxe/disable_xxe_dom_disabled.phpt index a49e094..107171c 100644 --- a/src/tests/xxe/disable_xxe_dom_disabled.phpt +++ b/src/tests/xxe/disable_xxe_dom_disabled.phpt @@ -1,10 +1,10 @@ --TEST-- -Disable XXE +Disable XXE (feature enabled) --SKIPIF-- = 80000) print "skip"; ?> --INI-- -sp.configuration_file={PWD}/config/disable_xxe_disable.ini +sp.configuration_file={PWD}/config/disable_xxe.ini --EXTENSIONS-- dom --FILE-- diff --git a/src/tests/xxe/disable_xxe_simplexml.phpt b/src/tests/xxe/disable_xxe_simplexml.phpt index 1d3ef4c..9560156 100644 --- a/src/tests/xxe/disable_xxe_simplexml.phpt +++ b/src/tests/xxe/disable_xxe_simplexml.phpt @@ -2,8 +2,9 @@ Disable XXE --SKIPIF-- += 80000) print "skip"; ?> --INI-- -sp.configuration_file={PWD}/config/disable_xxe.ini +sp.configuration_file={PWD}/config/disable_xxe_disable.ini --EXTENSIONS-- simplexml --XFAIL-- diff --git a/src/tests/xxe/disable_xxe_simplexml_oop.phpt b/src/tests/xxe/disable_xxe_simplexml_oop.phpt index e101337..1b2c4ca 100644 --- a/src/tests/xxe/disable_xxe_simplexml_oop.phpt +++ b/src/tests/xxe/disable_xxe_simplexml_oop.phpt @@ -2,8 +2,9 @@ Disable XXE --SKIPIF-- += 80000) print "skip"; ?> --INI-- -sp.configuration_file={PWD}/config/disable_xxe.ini +sp.configuration_file={PWD}/config/disable_xxe_disable.ini --EXTENSIONS-- simplexml --XFAIL-- diff --git a/src/tests/xxe/disable_xxe_xml_parse.phpt b/src/tests/xxe/disable_xxe_xml_parse.phpt index 6b48bea..bc7e338 100644 --- a/src/tests/xxe/disable_xxe_xml_parse.phpt +++ b/src/tests/xxe/disable_xxe_xml_parse.phpt @@ -70,7 +70,8 @@ $parser = create_parser(); $doc = xml_parse($parser, $xml, true); xml_parser_free($parser); ---EXPECT-- +--EXPECTF-- +Warning: [snuffleupagus][0.0.0.0][xxe][log] A call to libxml_disable_entity_loader was tried and nopped in %a.php on line 41 string(4) "TEST" array(0) { @@ -81,6 +82,8 @@ array(0) { } string(7) "TESTING" string(4) "TEST" + +Warning: [snuffleupagus][0.0.0.0][xxe][log] A call to libxml_disable_entity_loader was tried and nopped in %a.php on line 46 string(4) "TEST" array(0) { -- cgit v1.3 From 0462573a7678468b19bc4865c75f7b82dbedbe03 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Fri, 19 Nov 2021 16:47:08 +0100 Subject: added old php version check --- src/php_snuffleupagus.h | 1 + src/snuffleupagus.c | 13 +++++++++++++ src/sp_config.h | 1 + src/sp_config_keywords.c | 3 ++- .../config/broken_conf_enable_disable2.ini | 1 + .../broken_conf_enable_disable2.phpt | 5 ----- 6 files changed, 18 insertions(+), 6 deletions(-) (limited to 'src/php_snuffleupagus.h') diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index 03c9bb6..8fcbd58 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -127,6 +127,7 @@ bool config_server_encode; bool config_server_strip; zend_string *config_encryption_key; zend_string *config_cookies_env_var; +bool config_show_old_php_warning; HashTable *config_disabled_functions; HashTable *config_disabled_functions_hooked; diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index c96a911..e3ecd72 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -276,6 +276,9 @@ static PHP_INI_MH(OnUpdateConfiguration) { return FAILURE; } + // set some defaults + SPCFG(show_old_php_warning) = true; + char *str = new_value->val; while (1) { @@ -365,6 +368,16 @@ static PHP_INI_MH(OnUpdateConfiguration) { (SPCFG(disabled_functions) && zend_hash_num_elements(SPCFG(disabled_functions))) || (SPCFG(disabled_functions) && zend_hash_num_elements(SPCFG(disabled_functions_ret))); + if (SPCFG(show_old_php_warning)) { + time_t ts = time(NULL); + sp_log_debug("foo"); + if (PHP_VERSION_ID < 70300 || + PHP_VERSION_ID < 70400 && ts >= (time_t)1638745200L || + PHP_VERSION_ID < 80000 && ts >= (time_t)1669590000L || + PHP_VERSION_ID < 80100 && ts >= (time_t)1700953200L) { + sp_log_warn("End-of-Life Check", "Your PHP version '" PHP_VERSION "' is not officially mainained anymore. Please upgrade as soon as possible."); + } + } return SUCCESS; } diff --git a/src/sp_config.h b/src/sp_config.h index a557105..1a891c1 100644 --- a/src/sp_config.h +++ b/src/sp_config.h @@ -262,6 +262,7 @@ typedef struct { #define SP_TOKEN_SERVER_STRIP "server_strip" #define SP_TOKEN_SID_MIN_LENGTH "sid_min_length" #define SP_TOKEN_SID_MAX_LENGTH "sid_max_length" +#define SP_TOKEN_SHOW_OLD_PHP_WARNING "show_old_php_warning" // upload_validator #define SP_TOKEN_UPLOAD_SCRIPT "script" diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index cf44ed9..cbe4966 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -1,7 +1,7 @@ #include "php_snuffleupagus.h" #define SP_SET_ENABLE_DISABLE(enable, disable, varname) \ - if (((varname) || enable) && disable) { \ + if (enable && disable) { \ sp_log_err("config", "A rule can't be enabled and disabled on line %zu", parsed_rule->lineno); \ return SP_PARSER_ERROR; \ } \ @@ -133,6 +133,7 @@ SP_PARSE_FN(parse_global) { {parse_ulong, SP_TOKEN_MAX_EXECUTION_DEPTH, &(SPCFG(max_execution_depth))}, {parse_enable, SP_TOKEN_SERVER_ENCODE, &(SPCFG(server_encode))}, {parse_enable, SP_TOKEN_SERVER_STRIP, &(SPCFG(server_strip))}, + {parse_enable, SP_TOKEN_SHOW_OLD_PHP_WARNING, &(SPCFG(show_old_php_warning))}, {0, 0, 0}}; SP_PROCESS_CONFIG_KEYWORDS_ERR(); diff --git a/src/tests/broken_configuration/config/broken_conf_enable_disable2.ini b/src/tests/broken_configuration/config/broken_conf_enable_disable2.ini index 39d97cc..7ed0c16 100644 --- a/src/tests/broken_configuration/config/broken_conf_enable_disable2.ini +++ b/src/tests/broken_configuration/config/broken_conf_enable_disable2.ini @@ -1,2 +1,3 @@ sp.global_strict.enable(); sp.global_strict.disable(); +;; this is actually not recognised as broken, as there is no internal third state for 'unset' diff --git a/src/tests/broken_configuration_php8/broken_conf_enable_disable2.phpt b/src/tests/broken_configuration_php8/broken_conf_enable_disable2.phpt index efe5538..2446663 100644 --- a/src/tests/broken_configuration_php8/broken_conf_enable_disable2.phpt +++ b/src/tests/broken_configuration_php8/broken_conf_enable_disable2.phpt @@ -7,8 +7,3 @@ Global strict mode sp.configuration_file={PWD}/../broken_configuration/config/broken_conf_enable_disable2.ini --FILE-- --EXPECTF-- - -Fatal error: [snuffleupagus][0.0.0.0][config][log] A rule can't be enabled and disabled on line 2 in Unknown on line 0 - -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 -Could not startup. -- cgit v1.3