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/sp_config_keywords.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/sp_config_keywords.c') diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index a13aed2..abb3110 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -1,7 +1,5 @@ #include "php_snuffleupagus.h" -ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) - static int parse_enable(char *line, bool *restrict retval, bool *restrict simulation) { bool enable = false, disable = false; -- cgit v1.3 From d8bf25aa20e93d366133b4550ac8304d06186ad3 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Mon, 15 Jun 2020 11:33:48 +0200 Subject: stricter config checks --- src/sp_config_keywords.c | 64 +++++++++++++++--------------------------------- 1 file changed, 20 insertions(+), 44 deletions(-) (limited to 'src/sp_config_keywords.c') diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index abb3110..5f6cc7b 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -356,65 +356,41 @@ int parse_disabled_functions(char *line) { "Invalid configuration line: 'sp.disabled_functions%s': " \ "'.%s' and '.%s' are mutually exclusive on line %zu", \ line, STR1, STR2, sp_line_no); \ - return 1; \ + return -1; \ } - MUTUALLY_EXCLUSIVE(df->value, df->r_value, "value", "regexp"); - MUTUALLY_EXCLUSIVE(df->r_function, df->function, "r_function", "function"); - MUTUALLY_EXCLUSIVE(df->filename, df->r_filename, "r_filename", "filename"); - MUTUALLY_EXCLUSIVE(df->ret, df->r_ret, "r_ret", "ret"); - MUTUALLY_EXCLUSIVE(df->key, df->r_key, "r_key", "key"); + MUTUALLY_EXCLUSIVE(df->value, df->r_value, "value", "value_r"); + MUTUALLY_EXCLUSIVE(df->r_function, df->function, "function", "function_r"); + 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(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"); + MUTUALLY_EXCLUSIVE((df->r_ret || df->ret || df->ret_type), (var), "ret", "var"); + MUTUALLY_EXCLUSIVE((df->r_ret || df->ret || df->ret_type), (df->value || df->r_value), "ret", "value"); + #undef MUTUALLY_EXCLUSIVE - if (1 < - ((df->r_param ? 1 : 0) + (param ? 1 : 0) + ((-1 != df->pos) ? 1 : 0))) { - sp_log_err( - "config", - "Invalid configuration line: 'sp.disabled_functions%s':" - "'.r_param', '.param' and '.pos' are mutually exclusive on line %zu", - line, sp_line_no); - return -1; - } else if ((df->r_key || df->key) && (df->r_value || df->value)) { - sp_log_err("config", - "Invalid configuration line: 'sp.disabled_functions%s':" - "`key` and `value` are mutually exclusive on line %zu", - line, sp_line_no); - return -1; - } else if ((df->r_ret || df->ret || df->ret_type) && (df->r_param || param)) { - sp_log_err("config", - "Invalid configuration line: 'sp.disabled_functions%s':" - "`ret` and `param` are mutually exclusive on line %zu", - line, sp_line_no); - return -1; - } else if ((df->r_ret || df->ret || df->ret_type) && (var)) { - sp_log_err("config", - "Invalid configuration line: 'sp.disabled_functions%s':" - "`ret` and `var` are mutually exclusive on line %zu", - line, sp_line_no); - return -1; - } else if ((df->r_ret || df->ret || df->ret_type) && - (df->value || df->r_value)) { - sp_log_err("config", - "Invalid configuration line: 'sp.disabled_functions%s':" - "`ret` and `value` are mutually exclusive on line %zu", - line, sp_line_no); - return -1; - } else if (!(df->r_function || df->function)) { + 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); return -1; - } else if (df->filename && (*ZSTR_VAL(df->filename) != '/') && - (0 != - strncmp(ZSTR_VAL(df->filename), "phar://", strlen("phar://")))) { + } + 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); return -1; - } else if (!(allow ^ drop)) { + } + 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", -- cgit v1.3 From d4993c7deaefadbc5675f39404a46e64006174b9 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Tue, 3 Aug 2021 15:32:28 +0200 Subject: fixed mem leak in parse_disabled_functions --- src/sp_config_keywords.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'src/sp_config_keywords.c') diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index 64b5715..8080eec 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -366,7 +366,7 @@ int parse_disabled_functions(char *line) { ret = parse_keywords(sp_config_funcs_disabled_functions, line); if (0 != ret) { - return ret; + goto out; } #define MUTUALLY_EXCLUSIVE(X, Y, STR1, STR2) \ @@ -375,7 +375,7 @@ int parse_disabled_functions(char *line) { "Invalid configuration line: 'sp.disabled_functions%s': " \ "'.%s' and '.%s' are mutually exclusive on line %zu", \ line, STR1, STR2, sp_line_no); \ - return -1; \ + ret = -1; goto out; \ } MUTUALLY_EXCLUSIVE(df->value, df->r_value, "value", "value_r"); @@ -398,7 +398,7 @@ int parse_disabled_functions(char *line) { "Invalid configuration line: 'sp.disabled_functions%s':" " must take a function name on line %zu", line, sp_line_no); - return -1; + ret = -1; goto out; } if (df->filename && (*ZSTR_VAL(df->filename) != '/') && (0 != strncmp(ZSTR_VAL(df->filename), "phar://", strlen("phar://")))) { @@ -407,14 +407,14 @@ int parse_disabled_functions(char *line) { "Invalid configuration line: 'sp.disabled_functions%s':" "'.filename' must be an absolute path or a phar archive on line %zu", line, sp_line_no); - return -1; + ret = -1; 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); - return -1; + ret = -1; goto out; } if (pos) { @@ -424,7 +424,7 @@ int parse_disabled_functions(char *line) { 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); - return -1; + ret = -1; goto out; } } @@ -435,7 +435,7 @@ int parse_disabled_functions(char *line) { 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); - return -1; + ret = -1; goto out; } } df->allow = allow; @@ -454,14 +454,14 @@ int parse_disabled_functions(char *line) { new[0] = '$'; memcpy(new + 1, ZSTR_VAL(param), ZSTR_LEN(param)); df->param = sp_parse_var(new); - free(new); + pefree(new, 1); } else { 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); - return -1; + ret = -1; goto out; } } @@ -471,15 +471,18 @@ int parse_disabled_functions(char *line) { if (!df->var) { sp_log_err("config", "Invalid value '%s' for `var` on line %zu", ZSTR_VAL(var), sp_line_no); - return -1; + ret = -1; goto out; } } else { sp_log_err("config", "Empty value in `var` on line %zu", sp_line_no); - return -1; + ret = -1; goto out; } } - if (true == disable) { + if (true == disable || 0 != ret) { + out: + sp_free_disabled_function(df); + pefree(df, 1); return ret; } -- 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/sp_config_keywords.c') 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 bd8b5bb241ca359b65c1a3717c9905d034b9703b Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Sat, 7 Aug 2021 15:56:57 +0200 Subject: more ini protection features --- config/ini_protection.php8.rules | 20 +++++++++++++++- src/sp_config.h | 8 +++++-- src/sp_config_keywords.c | 21 ++++++++++++---- src/sp_ini.c | 52 +++++++++++++++++++++++++++------------- 4 files changed, 76 insertions(+), 25 deletions(-) (limited to 'src/sp_config_keywords.c') diff --git a/config/ini_protection.php8.rules b/config/ini_protection.php8.rules index 081048f..b4ddb30 100644 --- a/config/ini_protection.php8.rules +++ b/config/ini_protection.php8.rules @@ -1,6 +1,20 @@ ## INI protection - prevent unwanted runtime ini changes made by ini_set() or other functions or by .htaccess sp.ini_protection.enable(); +## simulation mode: only log violations +#sp.ini_protection.simulation(); + +## drop policy: drop request on rule violation +#sp.ini_protection.policy_drop(); + +## do not log violations. +## this setting has no effect in simulation or drop mode +#sp.ini_protection.policy_silent_fail(); + +## do not log read-only violations +## this setting has no effect in simulation or drop mode +sp.ini_protection.policy_silent_ro(); + ## access policy can be one of ## .policy_readonly(): All entries are read-only by default. ## Individual entries can be set read-write using .readwrite() or .rw() @@ -10,13 +24,17 @@ sp.ini_protection.enable(); ## sp.ini entries can have the following attributes ## .key("..."): mandatory ini name. -## .set("..."): set the value. This overrides php.ini. +## .set("..."): set the initial value. This overrides php.ini. +## checks are not performed for this initial value. ## .min("...") / .max("..."): value must be an integer between .min and .max. ## shorthand notation (e.g. 1k = 1024) is allowed ## .regexp("..."): value must match the regular expression +## .allow_null(): allow setting a NULL-value ## .msg("..."): message is shown in logs on rule violation instead of default message ## .readonly() / .ro() / .readwrite() / .rw(): set entry to read-only or read-write respectively ## If no access keyword is provided, the entry inherits the default policy set by sp.ini_protection.policy_*-rules. +## .drop(): drop request on rule violation for this entry +## .simulation(): only log rule violation for this entry ## FOR PRODUCTION SYSTEMS: disable error messages and version numbers sp.ini.key("display_errors").set("0").ro(); diff --git a/src/sp_config.h b/src/sp_config.h index bd2530a..0ba2e7f 100644 --- a/src/sp_config.h +++ b/src/sp_config.h @@ -170,17 +170,21 @@ typedef struct { zend_string *min; zend_string *max; sp_pcre *regexp; - bool simulation; zend_string *msg; zend_string *set; + bool allow_null; + bool simulation; + bool drop; PHP_INI_MH((*orig_onmodify)); } sp_ini_entry; typedef struct { bool enable; bool simulation; - // sp_ini_permission access_policy; bool policy_readonly; + bool policy_silent_ro; + bool policy_silent_fail; + bool policy_drop; HashTable *entries; // ht of sp_ini_entry } sp_config_ini; diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index e6eb05e..c547f10 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -566,14 +566,19 @@ int parse_upload_validation(char *line) { 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_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, &(SNUFFLEUPAGUS_G(config).config_ini->simulation)}, + {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}, {0, 0, 0}}; int ret = parse_keywords(sp_config_ini_protection, line); @@ -585,15 +590,19 @@ int parse_ini_protection(char *line) { return -1; } if (enable || disable) { - SNUFFLEUPAGUS_G(config).config_ini->enable = (enable || !disable); + cfg->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; + 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; + } return ret; } @@ -611,8 +620,10 @@ int parse_ini_entry(char *line) { {parse_regexp, ".regexp(", &entry->regexp}, {parse_empty, ".readonly(", &ro}, {parse_empty, ".ro(", &ro}, - {parse_empty, ".readwrite()", &rw}, - {parse_empty, ".rw()", &rw}, + {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); diff --git a/src/sp_ini.c b/src/sp_ini.c index 05d7d99..5777ca3 100644 --- a/src/sp_ini.c +++ b/src/sp_ini.c @@ -3,6 +3,15 @@ #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)) +#define sp_log_auto2(feature, is_simulation, drop, ...) \ + sp_log_msgf(feature, ((is_simulation || !drop) ? SP_LOG_WARN : SP_LOG_ERROR), \ + (is_simulation ? SP_TYPE_SIMULATION : (drop ? SP_TYPE_DROP : SP_TYPE_LOG)), \ + __VA_ARGS__) +#define sp_log_ini_check_violation(...) if (simulation || cfg->policy_drop || (entry && entry->drop) || !cfg->policy_silent_fail) { \ + sp_log_auto2("ini_protection", simulation, (cfg->policy_drop || (entry && entry->drop)), __VA_ARGS__); \ + } + + 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; @@ -17,40 +26,49 @@ static bool /* success */ sp_ini_check(zend_string *varname, zend_string *new_va if (!entry) { if (cfg->policy_readonly) { - sp_log_auto("ini_protection", simulation, "INI setting is read-only"); - if (simulation) { return true; } - return false; + if (!cfg->policy_silent_ro) { + sp_log_ini_check_violation("INI setting is read-only"); + } + return simulation; } return true; } + // we have an entry. + 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 (!cfg->policy_silent_ro) { + sp_log_ini_check_violation("%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI setting is read-only")); + } + return simulation; } - 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 (!new_value || ZSTR_LEN(new_value) == 0) { + if (entry->allow_null) { + return true; // allow NULL value and skip other tests + } + if (SP_INI_HAS_CHECKS_COND(entry)) { + sp_log_ini_check_violation("new INI value must not be NULL or empty"); + return simulation; + } + return true; // no new_value, but no checks to perform } + // we have a new_value. + 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; + sp_log_ini_check_violation("%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI value out of range")); + return simulation; } } 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; + sp_log_ini_check_violation("%s", (entry->msg ? ZSTR_VAL(entry->msg) : "INI value does not match regex")); + return simulation; } } @@ -83,7 +101,7 @@ void sp_hook_ini() { 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)) { + if (SP_INI_ACCESS_READONLY_COND(sp_entry, cfg) && (cfg->policy_silent_ro || cfg->policy_silent_fail) && !sp_entry->drop && !(sp_entry->simulation || cfg->simulation)) { ini_entry->modifiable = ini_entry->orig_modifiable = 0; } PHP_INI_MH((*orig_onmodify)) = ini_entry->on_modify; -- cgit v1.3 From dce966ffec7dfdae2b701d581d71df6a5a542db9 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Sun, 8 Aug 2021 15:55:06 +0200 Subject: fixed enable/disable logic --- src/sp_config_keywords.c | 49 +++++++--------------- src/tests/upload_validation/upload_validation.phpt | 2 +- 2 files changed, 15 insertions(+), 36 deletions(-) (limited to 'src/sp_config_keywords.c') diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index c547f10..b627122 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -1,5 +1,14 @@ #include "php_snuffleupagus.h" +#define SP_SET_ENABLE_DISABLE(enable, disable, varname) \ + 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) { \ + (varname) = (enable || !disable); \ + } + static int parse_enable(char *line, bool *restrict retval, bool *restrict simulation) { bool enable = false, disable = false; @@ -15,13 +24,7 @@ static int parse_enable(char *line, bool *restrict retval, 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; - } - - *retval = enable; + SP_SET_ENABLE_DISABLE(enable, disable, *retval); return ret; } @@ -141,13 +144,7 @@ int parse_unserialize(char *line) { 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; - } - - SNUFFLEUPAGUS_G(config).config_unserialize->enable = enable; + SP_SET_ENABLE_DISABLE(enable, disable, SNUFFLEUPAGUS_G(config).config_unserialize->enable); return ret; } @@ -172,13 +169,7 @@ int parse_readonly_exec(char *line) { 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; - } - - SNUFFLEUPAGUS_G(config).config_readonly_exec->enable = enable; + SP_SET_ENABLE_DISABLE(enable, disable, SNUFFLEUPAGUS_G(config).config_readonly_exec->enable); return ret; } @@ -535,12 +526,7 @@ int parse_upload_validation(char *line) { 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; - } - SNUFFLEUPAGUS_G(config).config_upload_validation->enable = 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; @@ -584,14 +570,7 @@ int parse_ini_protection(char *line) { 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) { - cfg->enable = (enable || !disable); - } + 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); diff --git a/src/tests/upload_validation/upload_validation.phpt b/src/tests/upload_validation/upload_validation.phpt index 965d3aa..810c23d 100644 --- a/src/tests/upload_validation/upload_validation.phpt +++ b/src/tests/upload_validation/upload_validation.phpt @@ -15,4 +15,4 @@ echo 1; --EXPECTF-- Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 -Fatal error: [snuffleupagus][0.0.0.0][config][log] A rule can't be enabled and disabled on line 1 in Unknown on line 0 +Fatal error: [snuffleupagus][0.0.0.0][config][log] The `script` (tests/upload_ko.sh) doesn't exist on line 1 in Unknown on line 0 -- cgit v1.3 From f3d5d251875ee7f854a3df38709eedef4c6d1a31 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Tue, 10 Aug 2021 16:45:40 +0200 Subject: prevent option to be enabled and then disabled --- src/sp_config_keywords.c | 2 +- .../broken_configuration/broken_conf_enable_disable2.phpt | 15 +++++++++++++++ .../config/broken_conf_enable_disable2.ini | 2 ++ .../broken_conf_enable_disable2.phpt | 14 ++++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/tests/broken_configuration/broken_conf_enable_disable2.phpt create mode 100644 src/tests/broken_configuration/config/broken_conf_enable_disable2.ini create mode 100644 src/tests/broken_configuration_php8/broken_conf_enable_disable2.phpt (limited to 'src/sp_config_keywords.c') diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index b627122..a177a5e 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 (enable && disable) { \ + if (((varname) || enable) && disable) { \ sp_log_err("config", "A rule can't be enabled and disabled on line %zu", sp_line_no); \ return -1; \ } \ diff --git a/src/tests/broken_configuration/broken_conf_enable_disable2.phpt b/src/tests/broken_configuration/broken_conf_enable_disable2.phpt new file mode 100644 index 0000000..0d6fb8c --- /dev/null +++ b/src/tests/broken_configuration/broken_conf_enable_disable2.phpt @@ -0,0 +1,15 @@ +--TEST-- +Global strict mode +--SKIPIF-- + += 80000) print "skip"; ?> +--INI-- +sp.configuration_file={PWD}/../broken_configuration/config/broken_conf_enable_disable2.ini +--FILE-- +--EXPECTF-- +PHP 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] 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. diff --git a/src/tests/broken_configuration/config/broken_conf_enable_disable2.ini b/src/tests/broken_configuration/config/broken_conf_enable_disable2.ini new file mode 100644 index 0000000..39d97cc --- /dev/null +++ b/src/tests/broken_configuration/config/broken_conf_enable_disable2.ini @@ -0,0 +1,2 @@ +sp.global_strict.enable(); +sp.global_strict.disable(); diff --git a/src/tests/broken_configuration_php8/broken_conf_enable_disable2.phpt b/src/tests/broken_configuration_php8/broken_conf_enable_disable2.phpt new file mode 100644 index 0000000..efe5538 --- /dev/null +++ b/src/tests/broken_configuration_php8/broken_conf_enable_disable2.phpt @@ -0,0 +1,14 @@ +--TEST-- +Global strict mode +--SKIPIF-- + + +--INI-- +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 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/sp_config_keywords.c') 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 a67fd0af43e0cc786069bba4539e28eccdcb12b0 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Tue, 17 Aug 2021 13:47:14 +0200 Subject: removed unused variables --- src/sp_config_keywords.c | 1 - src/sp_utils.c | 3 --- 2 files changed, 4 deletions(-) (limited to 'src/sp_config_keywords.c') diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index 8084698..fd90453 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -166,7 +166,6 @@ SP_PARSE_FN(parse_wrapper_whitelist) { } SP_PARSE_FN(parse_cookie) { - int ret = 0; zend_string *samesite = NULL; sp_cookie *cookie = pecalloc(sizeof(sp_cookie), 1, 1); diff --git a/src/sp_utils.c b/src/sp_utils.c index c4209de..de19321 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c @@ -415,9 +415,6 @@ bool /* success */ _hook_function(const char* original_name, HashTable* hook_tab bool hook_function(const char* original_name, HashTable* hook_table, zif_handler new_function) { - zend_function* func; - - bool ret = _hook_function(original_name, hook_table, new_function); #if PHP_VERSION_ID < 80000 -- cgit v1.3 From b4dcbe2dd11efda09adc934fa2563eafc12e9b55 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Thu, 2 Sep 2021 13:58:01 +0200 Subject: fixed compiler warnings + test cases --- src/sp_config_keywords.c | 2 +- src/sp_config_scanner.cached.c | 14 +++++++------- src/sp_config_scanner.re | 14 +++++++------- .../broken_conf_cookie_encryption_without_env_var.phpt | 2 +- .../cookies_encryption_warning/encrypt_cookies_no_env.phpt | 2 +- .../encrypt_regexp_cookies_no_env.phpt | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) (limited to 'src/sp_config_keywords.c') diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index fd90453..3b6bc0b 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -183,7 +183,7 @@ SP_PARSE_FN(parse_cookie) { if (cookie->encrypt) { 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); + "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 " diff --git a/src/sp_config_scanner.cached.c b/src/sp_config_scanner.cached.c index 26a6652..868d271 100644 --- a/src/sp_config_scanner.cached.c +++ b/src/sp_config_scanner.cached.c @@ -154,7 +154,7 @@ const char *yyt4; zend_hash_str_add_ptr(&vars, ZEND_STRL("PHP_VERSION_ID"), zend_string_init(ZEND_STRL(ZEND_TOSTR(PHP_VERSION_ID)), 1)); - int cond_res[100] = {0}; + int cond_res[100] = {1}; int cond_res_i = 0; char cond_op[100] = {0}; int cond_op_i = 0; @@ -883,7 +883,7 @@ yy111: if (cond_op_i == 0 || sy_op_peek() != '(') { cs_error_log("unbalanced parathesis on line %d", lineno); goto out; } - sy_op_pop(); + cond_op_i--; goto yyc_cond_op; } yy113: @@ -910,12 +910,12 @@ yy116: case '>': op1 = 'G'; break; // >= } } - while (cond_op_i && sy_op_peek() != '(' && ((sy_op_precedence(sy_op_peek()) > sy_op_precedence(*t1)) || (sy_op_precedence(sy_op_peek()) == sy_op_precedence(*t1)) && sy_op_is_left_assoc(*t1))) { - SY_APPLY_OP_FROM_STACK(); - } - sy_op_push(*t1); - goto yyc_cond; + while (cond_op_i && sy_op_peek() != '(' && ((sy_op_precedence(sy_op_peek()) > sy_op_precedence(*t1)) || (sy_op_precedence(sy_op_peek()) == sy_op_precedence(*t1) && sy_op_is_left_assoc(*t1)))) { + SY_APPLY_OP_FROM_STACK(); } + sy_op_push(*t1); + goto yyc_cond; + } yy117: yych = *++YYCURSOR; if (yych == '=') goto yy119; diff --git a/src/sp_config_scanner.re b/src/sp_config_scanner.re index f911df3..5fd1928 100644 --- a/src/sp_config_scanner.re +++ b/src/sp_config_scanner.re @@ -143,7 +143,7 @@ zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_key zend_hash_str_add_ptr(&vars, ZEND_STRL("PHP_VERSION_ID"), zend_string_init(ZEND_STRL(ZEND_TOSTR(PHP_VERSION_ID)), 1)); - int cond_res[100] = {0}; + int cond_res[100] = {1}; int cond_res_i = 0; char cond_op[100] = {0}; int cond_op_i = 0; @@ -220,12 +220,12 @@ zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_key case '>': op1 = 'G'; break; // >= } } - while (cond_op_i && sy_op_peek() != '(' && ((sy_op_precedence(sy_op_peek()) > sy_op_precedence(*t1)) || (sy_op_precedence(sy_op_peek()) == sy_op_precedence(*t1)) && sy_op_is_left_assoc(*t1))) { - SY_APPLY_OP_FROM_STACK(); - } - sy_op_push(*t1); - goto yyc_cond; + while (cond_op_i && sy_op_peek() != '(' && ((sy_op_precedence(sy_op_peek()) > sy_op_precedence(*t1)) || (sy_op_precedence(sy_op_peek()) == sy_op_precedence(*t1) && sy_op_is_left_assoc(*t1)))) { + SY_APPLY_OP_FROM_STACK(); } + sy_op_push(*t1); + goto yyc_cond; + } ")" { while (cond_op_i && sy_op_peek() != '(') { SY_APPLY_OP_FROM_STACK(); @@ -233,7 +233,7 @@ zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_key if (cond_op_i == 0 || sy_op_peek() != '(') { cs_error_log("unbalanced parathesis on line %d", lineno); goto out; } - sy_op_pop(); + cond_op_i--; goto yyc_cond_op; } ";" { 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 25371dd..99e391e 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,7 +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 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] 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/cookies_encryption_warning/encrypt_cookies_no_env.phpt b/src/tests/cookies_encryption_warning/encrypt_cookies_no_env.phpt index a01c352..b31bf78 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 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][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_env.phpt b/src/tests/cookies_encryption_warning/encrypt_regexp_cookies_no_env.phpt index 1fe4074..d4b7e6a 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 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][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 -- 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/sp_config_keywords.c') 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/sp_config_keywords.c') 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-- +encrypt) { + if (SNUFFLEUPAGUS_G(config).config_session->encrypt || SNUFFLEUPAGUS_G(config).config_session->sid_min_length || SNUFFLEUPAGUS_G(config).config_session->sid_max_length) { hook_session(); } diff --git a/src/sp_config.h b/src/sp_config.h index af9b905..df36976 100644 --- a/src/sp_config.h +++ b/src/sp_config.h @@ -81,6 +81,8 @@ typedef struct { typedef struct { bool encrypt; bool simulation; + u_long sid_min_length; + u_long sid_max_length; } sp_config_session; typedef struct { @@ -292,6 +294,8 @@ typedef struct { #define SP_TOKEN_MAX_EXECUTION_DEPTH "max_execution_depth" #define SP_TOKEN_SERVER_ENCODE "server_encode" #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" // upload_validator #define SP_TOKEN_UPLOAD_SCRIPT "script" diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index 38b8526..bd8a9a1 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -33,6 +33,8 @@ SP_PARSE_FN(parse_session) { {parse_empty, SP_TOKEN_ENCRYPT, &(cfg->encrypt)}, {parse_empty, SP_TOKEN_SIMULATION, &(cfg->simulation)}, {parse_empty, SP_TOKEN_SIM, &(cfg->simulation)}, + {parse_ulong, SP_TOKEN_SID_MIN_LENGTH, &(cfg->sid_min_length)}, + {parse_ulong, SP_TOKEN_SID_MAX_LENGTH, &(cfg->sid_max_length)}, {0, 0, 0}}; SP_PROCESS_CONFIG_KEYWORDS_ERR(); diff --git a/src/sp_session.c b/src/sp_session.c index 7fa4937..64233d1 100644 --- a/src/sp_session.c +++ b/src/sp_session.c @@ -24,21 +24,35 @@ static int (*old_s_write)(PS_WRITE_ARGS); 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; + + if (sid) { + if (cfg->sid_min_length && ZSTR_LEN(sid) < cfg->sid_min_length) { + sp_log_auto("session", cfg->simulation, "Session ID is too short"); + } + if (cfg->sid_max_length && ZSTR_LEN(sid) > cfg->sid_max_length) { + sp_log_auto("session", cfg->simulation, "Session ID is too long"); + } + } +} + static int sp_hook_s_read(PS_READ_ARGS) { + const sp_config_session *cfg = SNUFFLEUPAGUS_G(config).config_session; + check_sid_length(key); + int r = old_s_read(mod_data, key, val, maxlifetime); - const sp_config_session *config_session = - SNUFFLEUPAGUS_G(config).config_session; if ((NULL == val) || (NULL == *val) || (0 == ZSTR_LEN(*val))) { return r; } - if (r == SUCCESS && config_session->encrypt) { + if (r == SUCCESS && cfg->encrypt) { zend_string *orig_val = *val; zval val_zval; ZVAL_PSTRINGL(&val_zval, ZSTR_VAL(*val), ZSTR_LEN(*val)); - int ret = decrypt_zval(&val_zval, config_session->simulation, NULL); + int ret = decrypt_zval(&val_zval, cfg->simulation, NULL); if (ZEND_HASH_APPLY_KEEP != ret) { zend_bailout(); } @@ -51,7 +65,10 @@ static int sp_hook_s_read(PS_READ_ARGS) { } static int sp_hook_s_write(PS_WRITE_ARGS) { - if (ZSTR_LEN(val) > 0 && SNUFFLEUPAGUS_G(config).config_session->encrypt) { + const sp_config_session *cfg = SNUFFLEUPAGUS_G(config).config_session; + check_sid_length(key); + + if (ZSTR_LEN(val) > 0 && cfg->encrypt) { zend_string *new_val = encrypt_zval(val); return old_s_write(mod_data, key, new_val, maxlifetime); } diff --git a/src/tests/sid_too_long.phpt b/src/tests/sid_too_long.phpt new file mode 100644 index 0000000..235b166 --- /dev/null +++ b/src/tests/sid_too_long.phpt @@ -0,0 +1,16 @@ +--TEST-- +SESSION ID too long +--SKIPIF-- + +--INI-- +sp.configuration_file={PWD}/config/sid_length_limit.ini +--FILE-- + +--EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][session][drop] Session ID is too long in %a.php on line %d + +Fatal error: [snuffleupagus][0.0.0.0][session][drop] Session ID is too long in Unknown on line 0 \ No newline at end of file diff --git a/src/tests/sid_too_short.phpt b/src/tests/sid_too_short.phpt new file mode 100644 index 0000000..0d9d514 --- /dev/null +++ b/src/tests/sid_too_short.phpt @@ -0,0 +1,16 @@ +--TEST-- +SESSION ID too short +--SKIPIF-- + +--INI-- +sp.configuration_file={PWD}/config/sid_length_limit.ini +--FILE-- + +--EXPECTF-- +Fatal error: [snuffleupagus][0.0.0.0][session][drop] Session ID is too short in %a.php on line %d + +Fatal error: [snuffleupagus][0.0.0.0][session][drop] Session ID is too short in Unknown on line 0 \ No newline at end of file -- cgit v1.3 From 54c352c1b5aa08b187dd1e52e544709cad2b0fee Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Thu, 23 Sep 2021 12:23:40 +0200 Subject: config is stack allocated now + some code improvements (see details) * for easier memory manegement, the entire sp_config struct was merged into snuffleupagus_globals and allocated on stack where possible * SNUFFLEUPAGUS_G() can be written as SPG(), which is faster to type and easier to read * execution_depth is re-initialized to 0 for each request * function calls with inline string and length parameters consistently use ZEND_STRL instead of sizeof()-1 * execution is actually hooked if recursion protection is enabled * some line breaks were removed to make the code more readable --- src/php_snuffleupagus.h | 41 ++++++++- src/snuffleupagus.c | 201 +++++++++++++++++--------------------------- src/sp_config.c | 30 +++---- src/sp_config.h | 34 -------- src/sp_config_keywords.c | 38 ++++----- src/sp_cookie_encryption.c | 6 +- src/sp_crypt.c | 9 +- src/sp_disabled_functions.c | 46 +++------- src/sp_execute.c | 64 +++++--------- src/sp_harden_rand.c | 6 +- src/sp_ifilter.c | 4 +- src/sp_ini.c | 6 +- src/sp_session.c | 6 +- src/sp_sloppy.c | 2 +- src/sp_unserialize.c | 23 ++--- src/sp_upload_validation.c | 12 +-- src/sp_utils.c | 18 ++-- src/sp_utils.h | 4 +- src/sp_wrapper.c | 9 +- 19 files changed, 228 insertions(+), 331 deletions(-) (limited to 'src/sp_config_keywords.c') diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index bcb613c..308031b 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -106,11 +106,44 @@ extern zend_module_entry snuffleupagus_module_entry; #endif ZEND_BEGIN_MODULE_GLOBALS(snuffleupagus) -size_t in_eval; -sp_config config; +// sp_config config; +// --- snuffleupagus config +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_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; +char config_log_media; +u_long config_max_execution_depth; +bool config_server_encode; +bool config_server_strip; +zend_string *config_encryption_key; +zend_string *config_cookies_env_var; + +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; + +bool hook_execute; + +// --- ini options +bool allow_broken_configuration; + +// --- runtime/state variables int is_config_valid; // 1 = valid, 0 = invalid, -1 = none +size_t in_eval; u_long execution_depth; -bool allow_broken_configuration; HashTable *disabled_functions_hook; HashTable *sp_internal_functions_hook; HashTable *sp_eval_blacklist_functions_hook; @@ -118,6 +151,8 @@ ZEND_END_MODULE_GLOBALS(snuffleupagus) ZEND_EXTERN_MODULE_GLOBALS(snuffleupagus) #define SNUFFLEUPAGUS_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(snuffleupagus, v) +#define SPG(v) SNUFFLEUPAGUS_G(v) +#define SPCFG(v) SPG(config_##v) #if defined(ZTS) && defined(COMPILE_DL_SNUFFLEUPAGUS) ZEND_TSRMLS_CACHE_EXTERN() diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 84ab171..6fd6f25 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -30,7 +30,7 @@ static inline void sp_op_array_handler(zend_op_array *const op) { if (NULL == op->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 9111fdf5e6332923a5faf9f8a7e6b428eb91795a Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Thu, 11 Nov 2021 12:02:07 +0100 Subject: detect dummy or short encryption key --- src/sp_config_keywords.c | 13 ++++++++++++ .../config/broken_conf_cookie_name_and_regexp.ini | 2 +- .../config/config_encrypted_cookies_noname.ini | 2 +- .../config_encrypted_regexp_cookies_bad_regexp.ini | 2 +- .../config/config_encryption_key_short.ini | 1 + .../encrypt_key_too_short.phpt | 23 ++++++++++++++++++++++ .../encrypt_regexp_cookies_bad_regexp.phpt | 3 ++- .../broken_conf_cookie_name_and_regexp.phpt | 2 +- .../config/broken_conf_cookie_name_and_regexp.ini | 2 +- .../config/config_encrypted_cookies_noname.ini | 2 +- .../config_encrypted_regexp_cookies_bad_regexp.ini | 2 +- .../encrypt_key_too_short.phpt | 22 +++++++++++++++++++++ .../encrypt_regexp_cookies_bad_regexp.phpt | 2 +- src/tests/config/config_samesite_cookies.ini | 2 +- src/tests/config/phplog.ini | 2 +- src/tests/config/sid_length_limit.ini | 1 + src/tests/config/syslog.ini | 2 +- src/tests/config/syslog_simulation.ini | 2 +- .../config/config_encrypted_cookies.ini | 2 +- .../config/config_encrypted_cookies_empty_env.ini | 2 +- .../config/config_encrypted_cookies_simulation.ini | 2 +- .../config/config_encrypted_regexp_cookies.ini | 2 +- .../config_encrypted_regexp_cookies_empty_env.ini | 2 +- .../config/encryption_key_only.ini | 2 +- src/tests/cookies_encryption/encrypt_cookies.phpt | 2 +- src/tests/cookies_encryption/encrypt_cookies3.phpt | 2 +- .../cookies_encryption/encrypt_regexp_cookies.phpt | 2 +- .../encrypt_regexp_cookies3.phpt | 2 +- .../config/encrypt_cookies_no_env.ini | 2 +- .../config/encrypt_regexp_cookies_no_env.ini | 2 +- .../config/config_encrypted_cookies.ini | 2 +- .../config/config_crypt_session.ini | 2 +- .../config/config_crypt_session_simul.ini | 2 +- src/tests/unserialize/config/config_serialize.ini | 2 +- .../unserialize/config/config_serialize_sim.ini | 2 +- src/tests/unserialize/config/dump_unserialize.ini | 2 +- src/tests/unserialize/serialize.phpt | 2 +- src/tests/unserialize/unserialize_sim.phpt | 5 +++-- .../unserialize_php8/config/config_serialize.ini | 2 +- 39 files changed, 97 insertions(+), 35 deletions(-) create mode 100644 src/tests/broken_configuration/config/config_encryption_key_short.ini create mode 100644 src/tests/broken_configuration/encrypt_key_too_short.phpt create mode 100644 src/tests/broken_configuration_php8/encrypt_key_too_short.phpt create mode 100644 src/tests/config/sid_length_limit.ini (limited to 'src/sp_config_keywords.c') diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index f6af86b..cf44ed9 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -136,6 +136,19 @@ SP_PARSE_FN(parse_global) { {0, 0, 0}}; SP_PROCESS_CONFIG_KEYWORDS_ERR(); + + if (SPCFG(encryption_key)) { + if (ZSTR_LEN(SPCFG(encryption_key)) < 10) { + sp_log_err("config", "The encryption key set on line %zu is too short. please use at least 10 bytes", parsed_rule->lineno); + return SP_PARSER_ERROR; + } + if (zend_string_equals_literal(SPCFG(encryption_key), "YOU _DO_ NEED TO CHANGE THIS WITH SOME RANDOM CHARACTERS.") || + zend_string_equals_literal(SPCFG(encryption_key), "c6a0e02b3b818f7559d5f85303d8fe44")) { + sp_log_err("config", "The encryption key set on line %zu is an unchanged dummy value. please use a unique secret.", parsed_rule->lineno); + return SP_PARSER_ERROR; + } + } + return SP_PARSER_STOP; } diff --git a/src/tests/broken_configuration/config/broken_conf_cookie_name_and_regexp.ini b/src/tests/broken_configuration/config/broken_conf_cookie_name_and_regexp.ini index 503889b..6b43b71 100644 --- a/src/tests/broken_configuration/config/broken_conf_cookie_name_and_regexp.ini +++ b/src/tests/broken_configuration/config/broken_conf_cookie_name_and_regexp.ini @@ -1,2 +1,2 @@ -sp.global.secret_key("abcdef").cookie_env_var("REMOTE_ADDR"); +sp.global.secret_key("abcdefGHIJ").cookie_env_var("REMOTE_ADDR"); sp.cookie.name("my_cookie_name").name_r("my_cookie_regexp").encrypt(); diff --git a/src/tests/broken_configuration/config/config_encrypted_cookies_noname.ini b/src/tests/broken_configuration/config/config_encrypted_cookies_noname.ini index 048e404..43a4284 100644 --- a/src/tests/broken_configuration/config/config_encrypted_cookies_noname.ini +++ b/src/tests/broken_configuration/config/config_encrypted_cookies_noname.ini @@ -1,3 +1,3 @@ -sp.global.secret_key("abcdef").cookie_env_var("REMOTE_ADDR"); +sp.global.secret_key("abcdefGHIJ").cookie_env_var("REMOTE_ADDR"); sp.cookie.name("").encrypt(); sp.auto_cookie_secure.enable(); diff --git a/src/tests/broken_configuration/config/config_encrypted_regexp_cookies_bad_regexp.ini b/src/tests/broken_configuration/config/config_encrypted_regexp_cookies_bad_regexp.ini index 4fe92fd..817de14 100644 --- a/src/tests/broken_configuration/config/config_encrypted_regexp_cookies_bad_regexp.ini +++ b/src/tests/broken_configuration/config/config_encrypted_regexp_cookies_bad_regexp.ini @@ -1,3 +1,3 @@ -sp.global.secret_key("abcdef").cookie_env_var("REMOTE_ADDR"); +sp.global.secret_key("abcdefGHIJ").cookie_env_var("REMOTE_ADDR"); sp.cookie.name_r("^super_co[a-z+$").encrypt(); sp.auto_cookie_secure.enable(); diff --git a/src/tests/broken_configuration/config/config_encryption_key_short.ini b/src/tests/broken_configuration/config/config_encryption_key_short.ini new file mode 100644 index 0000000..7de4438 --- /dev/null +++ b/src/tests/broken_configuration/config/config_encryption_key_short.ini @@ -0,0 +1 @@ +sp.global.secret_key("abcdef"); diff --git a/src/tests/broken_configuration/encrypt_key_too_short.phpt b/src/tests/broken_configuration/encrypt_key_too_short.phpt new file mode 100644 index 0000000..fe80be1 --- /dev/null +++ b/src/tests/broken_configuration/encrypt_key_too_short.phpt @@ -0,0 +1,23 @@ +--TEST-- +Cookie encryption key too short +--SKIPIF-- + +--INI-- +sp.configuration_file={PWD}/config/config_encryption_key_short.ini +--COOKIE-- +--ENV-- +return << +--EXPECT-- +PHP Fatal error: [snuffleupagus][2001:0db8:0000:0000:0000:fe00:0042:8329][config][log] The encryption key set on line 1 is too short. please use at least 10 bytes in Unknown on line 0 + +Fatal error: [snuffleupagus][2001:0db8:0000:0000:0000:fe00:0042:8329][config][log] The encryption key set on line 1 is too short. please use at least 10 bytes in Unknown on line 0 + +Fatal error: [snuffleupagus][2001:0db8:0000:0000:0000:fe00:0042:8329][config][log] Invalid configuration file in Unknown on line 0 +Could not startup. \ No newline at end of file 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 5383df6..ef83154 100644 --- a/src/tests/broken_configuration/encrypt_regexp_cookies_bad_regexp.phpt +++ b/src/tests/broken_configuration/encrypt_regexp_cookies_bad_regexp.phpt @@ -2,11 +2,12 @@ Cookie decryption in ipv4 --SKIPIF-- += 80000) print "skip"; ?> --INI-- sp.configuration_file={PWD}/config/config_encrypted_regexp_cookies_bad_regexp.ini error_reporting=1 --COOKIE-- -super_cookie=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP3gV9YJZL/pUeNAjCKFW0U2ywmf1CwHzwd2pWM=;awful_cookie=awful_cookie_value; +super_cookie=IpRZV4rivSjANrEOSxINd%2FdFe17giJgaAAAAAAAAAAAAAAAAAAAAALnmBVs%2BTILKxauHeGcUyJpR%2BX2UiZ6OamUTaWc=;awful_cookie=awful_cookie_value; --ENV-- return << --INI-- -sp.configuration_file={PWD}/config/broken_conf_cookie_name_and_regexp.ini +sp.configuration_file={PWD}/../broken_configuration/config/broken_conf_cookie_name_and_regexp.ini --FILE-- --EXPECT-- diff --git a/src/tests/broken_configuration_php8/config/broken_conf_cookie_name_and_regexp.ini b/src/tests/broken_configuration_php8/config/broken_conf_cookie_name_and_regexp.ini index 503889b..6b43b71 100644 --- a/src/tests/broken_configuration_php8/config/broken_conf_cookie_name_and_regexp.ini +++ b/src/tests/broken_configuration_php8/config/broken_conf_cookie_name_and_regexp.ini @@ -1,2 +1,2 @@ -sp.global.secret_key("abcdef").cookie_env_var("REMOTE_ADDR"); +sp.global.secret_key("abcdefGHIJ").cookie_env_var("REMOTE_ADDR"); sp.cookie.name("my_cookie_name").name_r("my_cookie_regexp").encrypt(); diff --git a/src/tests/broken_configuration_php8/config/config_encrypted_cookies_noname.ini b/src/tests/broken_configuration_php8/config/config_encrypted_cookies_noname.ini index 048e404..43a4284 100644 --- a/src/tests/broken_configuration_php8/config/config_encrypted_cookies_noname.ini +++ b/src/tests/broken_configuration_php8/config/config_encrypted_cookies_noname.ini @@ -1,3 +1,3 @@ -sp.global.secret_key("abcdef").cookie_env_var("REMOTE_ADDR"); +sp.global.secret_key("abcdefGHIJ").cookie_env_var("REMOTE_ADDR"); sp.cookie.name("").encrypt(); sp.auto_cookie_secure.enable(); diff --git a/src/tests/broken_configuration_php8/config/config_encrypted_regexp_cookies_bad_regexp.ini b/src/tests/broken_configuration_php8/config/config_encrypted_regexp_cookies_bad_regexp.ini index 4fe92fd..817de14 100644 --- a/src/tests/broken_configuration_php8/config/config_encrypted_regexp_cookies_bad_regexp.ini +++ b/src/tests/broken_configuration_php8/config/config_encrypted_regexp_cookies_bad_regexp.ini @@ -1,3 +1,3 @@ -sp.global.secret_key("abcdef").cookie_env_var("REMOTE_ADDR"); +sp.global.secret_key("abcdefGHIJ").cookie_env_var("REMOTE_ADDR"); sp.cookie.name_r("^super_co[a-z+$").encrypt(); sp.auto_cookie_secure.enable(); diff --git a/src/tests/broken_configuration_php8/encrypt_key_too_short.phpt b/src/tests/broken_configuration_php8/encrypt_key_too_short.phpt new file mode 100644 index 0000000..c14785e --- /dev/null +++ b/src/tests/broken_configuration_php8/encrypt_key_too_short.phpt @@ -0,0 +1,22 @@ +--TEST-- +Cookie encryption key too short +--SKIPIF-- + + +--INI-- +sp.configuration_file={PWD}/../broken_configuration/config/config_encryption_key_short.ini +--COOKIE-- +--ENV-- +return << +--EXPECT-- +Fatal error: [snuffleupagus][2001:0db8:0000:0000:0000:fe00:0042:8329][config][log] The encryption key set on line 1 is too short. please use at least 10 bytes in Unknown on line 0 + +Fatal error: [snuffleupagus][2001:0db8:0000:0000:0000:fe00:0042:8329][config][log] Invalid configuration file in Unknown on line 0 +Could not startup. \ No newline at end of file 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 5383df6..6796c5b 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 @@ -6,7 +6,7 @@ Cookie decryption in ipv4 sp.configuration_file={PWD}/config/config_encrypted_regexp_cookies_bad_regexp.ini error_reporting=1 --COOKIE-- -super_cookie=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP3gV9YJZL/pUeNAjCKFW0U2ywmf1CwHzwd2pWM=;awful_cookie=awful_cookie_value; +super_cookie=IpRZV4rivSjANrEOSxINd%2FdFe17giJgaAAAAAAAAAAAAAAAAAAAAALnmBVs%2BTILKxauHeGcUyJpR%2BX2UiZ6OamUTaWc=;awful_cookie=awful_cookie_value; --ENV-- return << --EXPECT-- -s:1:"a";650609b417904d0d9bbf1fc44a975d13ecdf6b02b715c1a06271fb3b673f25b1 +s:1:"a";cdbc93e593656164d448db33e4668a3f30fa794d6658016365f7eb453d48b022 diff --git a/src/tests/unserialize/unserialize_sim.phpt b/src/tests/unserialize/unserialize_sim.phpt index 9bff2c1..1256c23 100644 --- a/src/tests/unserialize/unserialize_sim.phpt +++ b/src/tests/unserialize/unserialize_sim.phpt @@ -7,12 +7,13 @@ sp.configuration_file={PWD}/config/config_serialize_sim.ini --FILE-- --EXPECTF-- -s:1:"a";650609b417904d0d9bbf1fc44a975d13ecdf6b02b715c1a06271fb3b673f25b1string(1) "a" +s:1:"a";cdbc93e593656164d448db33e4668a3f30fa794d6658016365f7eb453d48b022 +string(1) "a" Warning: [snuffleupagus][0.0.0.0][unserialize][simulation] Invalid HMAC for s:1:"a";alyualskdufyhalkdjsfh in %a/unserialize_sim.php on line 5 string(1) "a" diff --git a/src/tests/unserialize_php8/config/config_serialize.ini b/src/tests/unserialize_php8/config/config_serialize.ini index 7de4438..e107f15 100644 --- a/src/tests/unserialize_php8/config/config_serialize.ini +++ b/src/tests/unserialize_php8/config/config_serialize.ini @@ -1 +1 @@ -sp.global.secret_key("abcdef"); +sp.global.secret_key("abcdefGHIJ"); -- 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/sp_config_keywords.c') 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 From 2863344b21977bb5b1df276b2f17e2ac9572e42a Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Mon, 20 Dec 2021 18:00:34 +0100 Subject: removed upload script x-bit check at load time, thus allowing root-user to execute test cases --- src/sp_config_keywords.c | 3 --- src/tests/upload_validation/upload_validation_no_exec.phpt | 7 ++++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'src/sp_config_keywords.c') diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index cbe4966..138da75 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -429,9 +429,6 @@ SP_PARSE_FN(parse_upload_validation) { } 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 SP_PARSER_STOP; diff --git a/src/tests/upload_validation/upload_validation_no_exec.phpt b/src/tests/upload_validation/upload_validation_no_exec.phpt index b198bda..ff3dc14 100644 --- a/src/tests/upload_validation/upload_validation_no_exec.phpt +++ b/src/tests/upload_validation/upload_validation_no_exec.phpt @@ -4,6 +4,7 @@ Upload a file, validation script not executable file_uploads=1 sp.configuration_file={PWD}/config/upload_validation_non_exec.ini output_buffering=off +expose_php=0 --POST_RAW-- Content-Type: multipart/form-data; boundary=blabla --blabla @@ -14,6 +15,6 @@ Content-Disposition: form-data; name="test"; filename="test.php" var_dump($_FILES); ?> --EXPECTF-- -Fatal error: [snuffleupagus][0.0.0.0][config][log] Invalid configuration file in Unknown on line 0 - -Fatal error: [snuffleupagus][0.0.0.0][config][log] The `script` (tests/data/upload_no_exec.sh) isn't executable on line 1 in Unknown on line 0 +Warning: [snuffleupagus][0.0.0.0][upload_validation][log] Could not call '%s' : Permission denied %s +%a +Fatal error: [snuffleupagus][0.0.0.0][upload_validation][drop] The upload %s was rejected. in Unknown on line 0 -- cgit v1.3 From 02fa1c084405fc96ba83a06cd83047ecd8eb22cb Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Wed, 12 Jan 2022 19:08:28 +0100 Subject: make session support a runtime check instead of compile time --- src/sp_config_keywords.c | 9 --------- src/sp_session.c | 11 ++--------- 2 files changed, 2 insertions(+), 18 deletions(-) (limited to 'src/sp_config_keywords.c') diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index 138da75..3e2b156 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c @@ -39,15 +39,6 @@ SP_PARSE_FN(parse_session) { SP_PROCESS_CONFIG_KEYWORDS_ERR(); -#if (!HAVE_PHP_SESSION || defined(COMPILE_DL_SESSION)) - 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.", parsed_rule->lineno); - return SP_PARSER_ERROR; -#endif - if (cfg->encrypt) { if (!SPCFG(cookies_env_var)) { sp_log_err("config", "You're trying to use the session cookie encryption feature " diff --git a/src/sp_session.c b/src/sp_session.c index 214aa85..6335838 100644 --- a/src/sp_session.c +++ b/src/sp_session.c @@ -1,7 +1,5 @@ #include "php_snuffleupagus.h" -#if (HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)) - #ifdef ZTS static ts_rsrc_id session_globals_id = 0; #define SESSION_G(v) ZEND_TSRMG(session_globals_id, php_ps_globals *, v) @@ -10,7 +8,7 @@ ZEND_TSRMLS_CACHE_EXTERN(); #endif #else static php_ps_globals *session_globals = NULL; -#define SESSION_G(v) (ps_globals.v) +#define SESSION_G(v) (session_globals->v) #endif static ps_module *s_module; @@ -138,6 +136,7 @@ void hook_session() { zend_module_entry *module; if ((module = zend_hash_str_find_ptr(&module_registry, ZEND_STRL("session"))) == NULL) { + sp_log_err("session", "You are trying to use session encryption or session ID restrictions, but your PHP installation has no session support. Please install the PHP session module or recompile PHP with session support."); return; // LCOV_EXCL_LINE } @@ -166,9 +165,3 @@ void hook_session() { sp_hook_session_module(); } - -#else - -void hook_session() {} - -#endif // HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION) -- cgit v1.3