From 8776410692bf336a104fa19442f0fb761ecf0b5d Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Mon, 15 Jun 2020 11:27:30 +0200 Subject: clobal config.h + better debug log --- src/snuffleupagus.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/snuffleupagus.c') diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index ff2d2b6..d62069c 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -4,10 +4,6 @@ #include #endif -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include "php_snuffleupagus.h" #ifndef ZEND_EXT_API -- cgit v1.3 From ae4ac9f69de3120004557824e0d766fe8140b27d Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Mon, 2 Aug 2021 19:19:23 +0200 Subject: properly free memory on shutdown --- src/snuffleupagus.c | 77 ++++++++++++++++++++++++++++------------------------- src/sp_config.c | 74 ++++++++++++++++++++++++++++++-------------------- src/sp_config.h | 10 ++++--- src/sp_list.c | 16 ++++++++++- src/sp_list.h | 3 ++- src/sp_var_parser.c | 2 +- 6 files changed, 110 insertions(+), 72 deletions(-) (limited to 'src/snuffleupagus.c') diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 7bf3649..d8a86b5 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -69,7 +69,7 @@ ZEND_DLEXPORT zend_extension zend_extension_entry = { NULL, /* op_array_dtor_func_t */ STANDARD_ZEND_EXTENSION_PROPERTIES}; -PHP_GINIT_FUNCTION(snuffleupagus) { +static PHP_GINIT_FUNCTION(snuffleupagus) { snuffleupagus_globals->is_config_valid = SP_CONFIG_NONE; snuffleupagus_globals->in_eval = 0; @@ -88,21 +88,21 @@ PHP_GINIT_FUNCTION(snuffleupagus) { #define SP_INIT(F) \ snuffleupagus_globals->config.F = \ pecalloc(sizeof(*(snuffleupagus_globals->config.F)), 1, 1); - SP_INIT(config_unserialize); SP_INIT(config_random); SP_INIT(config_sloppy); + SP_INIT(config_unserialize); SP_INIT(config_readonly_exec); - SP_INIT(config_global_strict); - SP_INIT(config_auto_cookie_secure); - SP_INIT(config_snuffleupagus); - SP_INIT(config_disable_xxe); SP_INIT(config_upload_validation); - SP_INIT(config_disabled_functions_reg); - SP_INIT(config_disabled_functions_reg_ret); SP_INIT(config_cookie); - SP_INIT(config_session); + 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_disabled_functions_reg); + SP_INIT(config_disabled_functions_reg_ret); #undef SP_INIT #define SP_INIT_NULL(F) snuffleupagus_globals->config.F = NULL; @@ -121,21 +121,27 @@ PHP_MINIT_FUNCTION(snuffleupagus) { return SUCCESS; } -static void free_disabled_functions_hashtable(HashTable *const ht) { +PHP_MSHUTDOWN_FUNCTION(snuffleupagus) { + UNREGISTER_INI_ENTRIES(); + + return SUCCESS; +} + +static inline void free_disabled_functions_hashtable(HashTable *const ht) { void *ptr = NULL; - ZEND_HASH_FOREACH_PTR(ht, ptr) { sp_list_free(ptr); } + ZEND_HASH_FOREACH_PTR(ht, ptr) { sp_list_free(ptr, sp_free_disabled_function); } ZEND_HASH_FOREACH_END(); } -PHP_MSHUTDOWN_FUNCTION(snuffleupagus) { +static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) { #define FREE_HT(F) \ - zend_hash_destroy(SNUFFLEUPAGUS_G(F)); \ - pefree(SNUFFLEUPAGUS_G(F), 1); + zend_hash_destroy(snuffleupagus_globals->F); \ + pefree(snuffleupagus_globals->F, 1); FREE_HT(disabled_functions_hook); FREE_HT(sp_eval_blacklist_functions_hook); #define FREE_HT_LIST(F) \ - free_disabled_functions_hashtable(SNUFFLEUPAGUS_G(config).F); \ + free_disabled_functions_hashtable(snuffleupagus_globals->config.F); \ FREE_HT(config.F); FREE_HT_LIST(config_disabled_functions); FREE_HT_LIST(config_disabled_functions_hooked); @@ -145,44 +151,43 @@ PHP_MSHUTDOWN_FUNCTION(snuffleupagus) { #undef FREE_HT #define FREE_LST_DISABLE(L) \ - do { \ - sp_list_node *_n = SNUFFLEUPAGUS_G(config).L; \ - sp_disabled_function_list_free(_n); \ - sp_list_free(_n); \ - } while (0) + 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_node *_n = SNUFFLEUPAGUS_G(config).config_cookie->cookies; - sp_cookie_list_free(_n); - sp_list_free(_n); + sp_list_free(snuffleupagus_globals->config.config_cookie->cookies, sp_free_cookie); -#define FREE_LST(L) sp_list_free(SNUFFLEUPAGUS_G(config).L); +#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); #undef FREE_LST -#define FREE_CFG(C) pefree(SNUFFLEUPAGUS_G(config).C, 1); - FREE_CFG(config_unserialize); +#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(config_global_strict); - FREE_CFG(config_auto_cookie_secure); + 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(config_upload_validation); + 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_disabled_functions_reg); FREE_CFG(config_disabled_functions_reg_ret); - FREE_CFG(config_cookie); - FREE_CFG(config_wrapper); #undef FREE_CFG - - UNREGISTER_INI_ENTRIES(); - - return SUCCESS; +#undef FREE_CFG_ZSTR } PHP_RINIT_FUNCTION(snuffleupagus) { @@ -358,7 +363,7 @@ zend_module_entry snuffleupagus_module_entry = { PHP_SNUFFLEUPAGUS_VERSION, PHP_MODULE_GLOBALS(snuffleupagus), PHP_GINIT(snuffleupagus), - NULL, + PHP_GSHUTDOWN(snuffleupagus), NULL, STANDARD_MODULE_PROPERTIES_EX}; diff --git a/src/sp_config.c b/src/sp_config.c index c12b435..72781c6 100644 --- a/src/sp_config.c +++ b/src/sp_config.c @@ -216,36 +216,52 @@ int sp_parse_config(const char *conf_file) { return SUCCESS; } -void sp_disabled_function_list_free(sp_list_node *list) { - sp_list_node *cursor = list; - while (cursor) { - sp_disabled_function *df = cursor->data; - if (df) { - sp_list_free(df->functions_list); - sp_list_free(df->param_array_keys); - sp_list_free(df->var_array_keys); - - sp_pcre_free(df->r_filename); - sp_pcre_free(df->r_function); - sp_pcre_free(df->r_param); - sp_pcre_free(df->r_ret); - sp_pcre_free(df->r_value); - sp_pcre_free(df->r_key); - - sp_tree_free(df->param); - sp_tree_free(df->var); - } - cursor = cursor->next; - } +void sp_free_disabled_function(void *data) { + sp_disabled_function *df = data; + + sp_free_zstr(df->textual_representation); + + sp_free_zstr(df->filename); + sp_pcre_free(df->r_filename); + + sp_free_zstr(df->function); + sp_pcre_free(df->r_function); + sp_list_free(df->functions_list, free); + + sp_free_zstr(df->hash); + + sp_tree_free(df->param); + sp_pcre_free(df->r_param); + + sp_pcre_free(df->r_ret); + sp_free_zstr(df->ret); + + sp_pcre_free(df->r_value); + sp_free_zstr(df->value); + + sp_pcre_free(df->r_key); + sp_free_zstr(df->key); + + sp_free_zstr(df->dump); + sp_free_zstr(df->alias); + + // sp_list_free(df->param_array_keys); + // sp_list_free(df->var_array_keys); + + sp_tree_free(df->var); + + pefree(df->cidr, 1); } -void sp_cookie_list_free(sp_list_node *list) { - sp_list_node *cursor = list; - while (cursor) { - sp_cookie *c = cursor->data; - if (c) { - sp_pcre_free(c->name_r); - } - cursor = cursor->next; +void sp_free_cookie(void *data) { + sp_cookie *c = data; + if (c->name) + zend_string_release_ex(c->name, 1); + sp_pcre_free(c->name_r); +} + +void sp_free_zstr(void *data) { + if (data) { + zend_string_release_ex((zend_string*)data, 1); } } diff --git a/src/sp_config.h b/src/sp_config.h index e7b1473..f3b64a6 100644 --- a/src/sp_config.h +++ b/src/sp_config.h @@ -130,8 +130,8 @@ typedef struct { zend_string *alias; bool param_is_array; bool var_is_array; - sp_list_node *param_array_keys; - sp_list_node *var_array_keys; + // sp_list_node *param_array_keys; + // sp_list_node *var_array_keys; bool allow; @@ -281,7 +281,9 @@ int parse_php_type(char *restrict, char *restrict, void *); int parse_list(char *restrict, char *restrict, void *); // cleanup -void sp_disabled_function_list_free(sp_list_node *); -void sp_cookie_list_free(sp_list_node *); +void sp_free_disabled_function(void *data); +void sp_free_cookie(void *data); +void sp_free_zstr(void *data); + #endif /* SP_CONFIG_H */ diff --git a/src/sp_list.c b/src/sp_list.c index 0f00371..92e628d 100644 --- a/src/sp_list.c +++ b/src/sp_list.c @@ -1,8 +1,22 @@ #include "php_snuffleupagus.h" -void sp_list_free(sp_list_node *node) { +void sp_list_free(sp_list_node *node, void (*free_data_func)(void *data)) { while (node) { sp_list_node *tmp = node->next; + if (free_data_func && node->data) { + free_data_func(node->data); + } + pefree(node, 1); + node = tmp; + } +} + +void sp_list_free2(sp_list_node *node) { + while (node) { + sp_list_node *tmp = node->next; + if (node->data) { + pefree(node->data, 1); + } pefree(node, 1); node = tmp; } diff --git a/src/sp_list.h b/src/sp_list.h index 2c91995..7ceee50 100644 --- a/src/sp_list.h +++ b/src/sp_list.h @@ -11,6 +11,7 @@ sp_list_node *sp_list_sort(sp_list_node *, int (*)(sp_list_node const *const, sp_list_node const *const)); sp_list_node *sp_list_insert(sp_list_node *, void *); sp_list_node *sp_list_prepend(sp_list_node *, void *); -void sp_list_free(sp_list_node *); +void sp_list_free(sp_list_node *, void (*free_data_func)(void *data)); +void sp_list_free2(sp_list_node *node); #endif diff --git a/src/sp_var_parser.c b/src/sp_var_parser.c index bb5a5c0..eb57f70 100644 --- a/src/sp_var_parser.c +++ b/src/sp_var_parser.c @@ -249,7 +249,7 @@ sp_tree *sp_parse_var(const char *line) { } tokens_list = sp_list_sort(tokens_list, cmp_tokens); tree = parse_tokens(line, tokens_list); - sp_list_free(tokens_list); + sp_list_free2(tokens_list); // Check if tree is empty. if (tree && tree->next == NULL && tree->type == UNDEFINED) { tree->type = CONSTANT; -- cgit v1.3 From baecad40b5b8a977ce2a42f9ad1e31820254ae6e Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Fri, 6 Aug 2021 16:39:03 +0200 Subject: debug log to dup'd stderr / php is closing stderr during shutdown --- src/snuffleupagus.c | 17 +++++++++++++++++ src/sp_utils.h | 9 +++++++++ 2 files changed, 26 insertions(+) (limited to 'src/snuffleupagus.c') diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index d8a86b5..8c7ecbf 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -13,6 +13,10 @@ static PHP_INI_MH(OnUpdateConfiguration); static inline void sp_op_array_handler(zend_op_array *op); +#ifdef SP_DEBUG_STDERR +int sp_debug_stderr = STDERR_FILENO; +#endif + ZEND_EXTENSION(); // LCOV_EXCL_START @@ -70,6 +74,10 @@ ZEND_DLEXPORT zend_extension zend_extension_entry = { STANDARD_ZEND_EXTENSION_PROPERTIES}; static PHP_GINIT_FUNCTION(snuffleupagus) { +#ifdef SP_DEBUG_STDERR + sp_debug_stderr = dup(STDERR_FILENO); +#endif + sp_log_debug("(GINIT)"); snuffleupagus_globals->is_config_valid = SP_CONFIG_NONE; snuffleupagus_globals->in_eval = 0; @@ -116,6 +124,7 @@ static PHP_GINIT_FUNCTION(snuffleupagus) { } PHP_MINIT_FUNCTION(snuffleupagus) { + sp_log_debug("(MINIT)"); REGISTER_INI_ENTRIES(); return SUCCESS; @@ -134,6 +143,7 @@ static inline void free_disabled_functions_hashtable(HashTable *const ht) { } static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) { + sp_log_debug("(GSHUTDOWN)"); #define FREE_HT(F) \ zend_hash_destroy(snuffleupagus_globals->F); \ pefree(snuffleupagus_globals->F, 1); @@ -188,6 +198,11 @@ static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) { FREE_CFG(config_disabled_functions_reg_ret); #undef FREE_CFG #undef FREE_CFG_ZSTR + +#ifdef SP_DEBUG_STDERR + close(sp_debug_stderr); + sp_debug_stderr = STDERR_FILENO; +#endif } PHP_RINIT_FUNCTION(snuffleupagus) { @@ -249,6 +264,8 @@ PHP_MINFO_FUNCTION(snuffleupagus) { } static PHP_INI_MH(OnUpdateConfiguration) { + sp_log_debug("(OnUpdateConfiguration)"); + TSRMLS_FETCH(); if (!new_value || !new_value->len) { diff --git a/src/sp_utils.h b/src/sp_utils.h index 7c287da..5537a34 100644 --- a/src/sp_utils.h +++ b/src/sp_utils.h @@ -51,9 +51,18 @@ sp_log_msgf(feature, SP_LOG_ERROR, SP_TYPE_LOG, __VA_ARGS__) #define sp_log_warn(feature, ...) \ sp_log_msgf(feature, SP_LOG_WARN, SP_TYPE_LOG, __VA_ARGS__) + #ifdef SP_DEBUG + +#ifdef SP_DEBUG_STDERR +extern int sp_debug_stderr; +#define sp_log_debug(fmt, ...) \ + dprintf(sp_debug_stderr, "[snuffleupagus][DEBUG] %s(): " fmt "\n", __FUNCTION__, ##__VA_ARGS__); +#else #define sp_log_debug(fmt, ...) \ sp_log_msgf("DEBUG", SP_LOG_DEBUG, SP_TYPE_LOG, "%s(): " fmt, __FUNCTION__, ##__VA_ARGS__) +#endif + #else #define sp_log_debug(...) #endif -- cgit v1.3 From 2392c46836ceea520fa2a45369c8d638aadb943c Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Fri, 6 Aug 2021 20:23:52 +0200 Subject: implemented ini settings protection --- src/config.m4 | 1 + src/php_snuffleupagus.h | 1 + src/snuffleupagus.c | 46 ++++++++++++----- src/sp_config.c | 13 +++++ src/sp_config.h | 26 +++++++++- src/sp_config_keywords.c | 77 +++++++++++++++++++++++++++++ src/sp_config_keywords.h | 2 + src/sp_ini.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++ src/sp_ini.h | 2 + 9 files changed, 281 insertions(+), 13 deletions(-) create mode 100644 src/sp_ini.c create mode 100644 src/sp_ini.h (limited to 'src/snuffleupagus.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 e8bb162220ac17cb9b8cc229666356e88f081887 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Sat, 7 Aug 2021 15:55:48 +0200 Subject: prevent STDERR debug output based on SP_NODEBUG environment variable --- src/snuffleupagus.c | 12 +++++++++--- src/sp_utils.h | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src/snuffleupagus.c') diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 2ee94a1..3ad47d5 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -75,7 +75,11 @@ ZEND_DLEXPORT zend_extension zend_extension_entry = { static PHP_GINIT_FUNCTION(snuffleupagus) { #ifdef SP_DEBUG_STDERR - sp_debug_stderr = dup(STDERR_FILENO); + if (getenv("SP_NODEBUG")) { + sp_debug_stderr = -1; + } else { + sp_debug_stderr = dup(STDERR_FILENO); + } #endif sp_log_debug("(GINIT)"); snuffleupagus_globals->is_config_valid = SP_CONFIG_NONE; @@ -218,8 +222,10 @@ static PHP_GSHUTDOWN_FUNCTION(snuffleupagus) { #undef FREE_CFG_ZSTR #ifdef SP_DEBUG_STDERR - close(sp_debug_stderr); - sp_debug_stderr = STDERR_FILENO; + if (sp_debug_stderr >= 0) { + close(sp_debug_stderr); + sp_debug_stderr = STDERR_FILENO; + } #endif } diff --git a/src/sp_utils.h b/src/sp_utils.h index ec79e8b..c0ddbe4 100644 --- a/src/sp_utils.h +++ b/src/sp_utils.h @@ -57,7 +57,7 @@ #ifdef SP_DEBUG_STDERR extern int sp_debug_stderr; #define sp_log_debug(fmt, ...) \ - dprintf(sp_debug_stderr, "[snuffleupagus][DEBUG] %s(): " fmt "\n", __FUNCTION__, ##__VA_ARGS__); + if (sp_debug_stderr > 0) dprintf(sp_debug_stderr, "[snuffleupagus][DEBUG] %s(): " fmt "\n", __FUNCTION__, ##__VA_ARGS__); #else #define sp_log_debug(fmt, ...) \ sp_log_msgf("DEBUG", SP_LOG_DEBUG, SP_TYPE_LOG, "%s(): " fmt, __FUNCTION__, ##__VA_ARGS__) -- cgit v1.3 From 627932d1eb9cfa88c72df66e51f520e987d7655e Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Wed, 18 Aug 2021 10:54:58 +0200 Subject: start SP as late as possible. this allows us to hook functions of extensions supposed to be loaded later --- src/snuffleupagus.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'src/snuffleupagus.c') diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 3ad47d5..650e5e4 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -73,6 +73,26 @@ ZEND_DLEXPORT zend_extension zend_extension_entry = { NULL, /* op_array_dtor_func_t */ STANDARD_ZEND_EXTENSION_PROPERTIES}; +static void sp_load_other_modules() { + // try to load other modules before initializing Snuffleupagus + zend_module_entry *module; + bool should_start = false; + ZEND_HASH_FOREACH_PTR(&module_registry, module) { + if (should_start) { + sp_log_debug("attempting to start module '%s' early", module->name); + if (zend_startup_module_ex(module) != SUCCESS) { + // startup failed. let's try again later. + module->module_started = 0; + } + } + if (strcmp(module->name, PHP_SNUFFLEUPAGUS_EXTNAME) == 0) { + should_start = true; + } + } ZEND_HASH_FOREACH_END(); + + +} + static PHP_GINIT_FUNCTION(snuffleupagus) { #ifdef SP_DEBUG_STDERR if (getenv("SP_NODEBUG")) { @@ -82,6 +102,7 @@ static PHP_GINIT_FUNCTION(snuffleupagus) { } #endif sp_log_debug("(GINIT)"); + sp_load_other_modules(); snuffleupagus_globals->is_config_valid = SP_CONFIG_NONE; snuffleupagus_globals->in_eval = 0; -- cgit v1.3 From 8e42064026906f0f25caca237e4624b5b3c5087e Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Wed, 15 Sep 2021 20:25:33 +0200 Subject: changed version and version output in phpinfo --- src/php_snuffleupagus.h | 6 +++--- src/snuffleupagus.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/snuffleupagus.c') diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index 91ee8a6..e11f976 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -1,10 +1,10 @@ #ifndef PHP_SNUFFLEUPAGUS_H #define PHP_SNUFFLEUPAGUS_H -#define PHP_SNUFFLEUPAGUS_VERSION "0.7.0" +#define PHP_SNUFFLEUPAGUS_VERSION "0.8.0" #define PHP_SNUFFLEUPAGUS_EXTNAME "snuffleupagus" -#define PHP_SNUFFLEUPAGUS_AUTHOR "NBS System & Julien (jvoisin) Voisin" -#define PHP_SNUFFLEUPAGUS_URL "https://github.com/jvoisin/snuffleupagus" +#define PHP_SNUFFLEUPAGUS_AUTHOR "NBS System & Julien (jvoisin) Voisin | Suhosin-NG patches by SektionEins GmbH" +#define PHP_SNUFFLEUPAGUS_URL "https://github.com/sektioneins/snuffleupagus" #define PHP_SNUFFLEUPAGUS_COPYRIGHT "LGPLv2" #ifdef HAVE_CONFIG_H diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 650e5e4..dab5dca 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -302,7 +302,7 @@ PHP_MINFO_FUNCTION(snuffleupagus) { php_info_print_table_row( 2, "snuffleupagus support", SNUFFLEUPAGUS_G(is_config_valid) ? "enabled" : "disabled"); - php_info_print_table_row(2, "Version", PHP_SNUFFLEUPAGUS_VERSION); + php_info_print_table_row(2, "Version", PHP_SNUFFLEUPAGUS_VERSION "-sng (with Suhosin-NG patches)"); php_info_print_table_row(2, "Valid config", valid_config); php_info_print_table_end(); DISPLAY_INI_ENTRIES(); -- cgit v1.3 From 31d6a3cddd18cef447698ba2beaa7b5d9ab9dd94 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Wed, 15 Sep 2021 20:26:02 +0200 Subject: implemented execution depth limit --- src/php_snuffleupagus.h | 1 + src/snuffleupagus.c | 2 ++ src/sp_config.h | 2 ++ src/sp_config_keywords.c | 1 + src/sp_execute.c | 17 +++++++++++++---- 5 files changed, 19 insertions(+), 4 deletions(-) (limited to 'src/snuffleupagus.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/snuffleupagus.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/snuffleupagus.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 713cb08b58d4e5dd5e7e80b1f82e27cbe52d4381 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Thu, 11 Nov 2021 13:15:52 +0100 Subject: inverted logic. set xxe_protection.enable() instead of disable_xxe.disable() --- config/default.rules | 2 +- config/default_php8.rules | 2 +- config/suhosin.rules | 2 +- doc/source/config.rst | 7 ++++--- src/php_snuffleupagus.h | 2 +- src/snuffleupagus.c | 2 +- src/sp_config.c | 2 +- src/sp_config.h | 4 ++-- src/tests/xxe/config/disable_xxe.ini | 2 +- src/tests/xxe/config/disable_xxe_disable.ini | 2 +- src/tests/xxe/disable_xxe_dom_disabled.phpt | 4 ++-- src/tests/xxe/disable_xxe_simplexml.phpt | 3 ++- src/tests/xxe/disable_xxe_simplexml_oop.phpt | 3 ++- src/tests/xxe/disable_xxe_xml_parse.phpt | 5 ++++- 14 files changed, 24 insertions(+), 18 deletions(-) (limited to 'src/snuffleupagus.c') diff --git a/config/default.rules b/config/default.rules index b964073..2de703b 100644 --- a/config/default.rules +++ b/config/default.rules @@ -7,7 +7,7 @@ sp.harden_random.enable(); # Disabled XXE -sp.disable_xxe.enable(); +sp.xxe_protection.enable(); # Global configuration variables # sp.global.secret_key("YOU _DO_ NEED TO CHANGE THIS WITH SOME RANDOM CHARACTERS."); diff --git a/config/default_php8.rules b/config/default_php8.rules index de2da5c..1d16191 100644 --- a/config/default_php8.rules +++ b/config/default_php8.rules @@ -8,7 +8,7 @@ sp.harden_random.enable(); # Disabled XXE -sp.disable_xxe.enable(); +sp.xxe_protection.enable(); # Global configuration variables # sp.global.secret_key("YOU _DO_ NEED TO CHANGE THIS WITH SOME RANDOM CHARACTERS."); diff --git a/config/suhosin.rules b/config/suhosin.rules index 4beb4c8..0bdc453 100644 --- a/config/suhosin.rules +++ b/config/suhosin.rules @@ -276,6 +276,6 @@ sp.harden_random.enable(); sp.auto_cookie_secure.enable(); #sp.cookie.name("cookie1").samesite("lax"); #sp.cookie.name("cookie2").samesite("strict");; -sp.disable_xxe.enable(); +sp.xxe_protection.enable(); #sp.sloppy_comparison.enable(); diff --git a/doc/source/config.rst b/doc/source/config.rst index 10b0afd..63ddf7b 100644 --- a/doc/source/config.rst +++ b/doc/source/config.rst @@ -293,14 +293,15 @@ It can either be ``enabled`` or ``disabled`` and can be used in ``simulation`` m sp.upload_validation.script("/var/www/is_valid_php.py").enable(); -disable_xxe +xxe_protection ^^^^^^^^^^^ -:ref:`disable_xxe `, enabled by default, will prevent XXE attacks by disabling the loading of external entities (``libxml_disable_entity_loader``) in the XML parser. +:ref:`xxe_protection `, disabled by default, will prevent XXE attacks by disabling the loading of external entities (``libxml_disable_entity_loader``) in the XML parser. :: - sp.disable_xxe.enable(); + sp.xxe_protection.enable(); + sp.xxe_protection.disable(); Whitelist of stream-wrappers diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index 308031b..03c9bb6 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -116,7 +116,7 @@ sp_config_upload_validation config_upload_validation; sp_config_cookie config_cookie; sp_config_auto_cookie_secure config_auto_cookie_secure; sp_config_global_strict config_global_strict; -sp_config_disable_xxe config_disable_xxe; +sp_config_xxe_protection config_xxe_protection; sp_config_eval config_eval; sp_config_wrapper config_wrapper; sp_config_session config_session; diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 6fd6f25..c96a911 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -314,7 +314,7 @@ static PHP_INI_MH(OnUpdateConfiguration) { hook_upload(); } - if (SPCFG(disable_xxe).enable == 0) { + if (SPCFG(xxe_protection).enable) { hook_libxml_disable_entity_loader(); } diff --git a/src/sp_config.c b/src/sp_config.c index ec6c5a8..bc9aa0d 100644 --- a/src/sp_config.c +++ b/src/sp_config.c @@ -17,7 +17,7 @@ static zend_result sp_process_config_root(sp_parsed_keyword *parsed_rule) { {parse_cookie, SP_TOKEN_COOKIE_ENCRYPTION, NULL}, {parse_global, SP_TOKEN_GLOBAL, NULL}, {parse_enable, SP_TOKEN_AUTO_COOKIE_SECURE, &(SPCFG(auto_cookie_secure).enable)}, - {parse_enable, SP_TOKEN_DISABLE_XXE, &(SPCFG(disable_xxe).enable)}, + {parse_enable, SP_TOKEN_XXE_PROTECTION, &(SPCFG(xxe_protection).enable)}, {parse_eval_filter_conf, SP_TOKEN_EVAL_BLACKLIST, &(SPCFG(eval).blacklist)}, {parse_eval_filter_conf, SP_TOKEN_EVAL_WHITELIST, &(SPCFG(eval).whitelist)}, {parse_session, SP_TOKEN_SESSION_ENCRYPTION, &(SPCFG(session))}, diff --git a/src/sp_config.h b/src/sp_config.h index 262050b..a557105 100644 --- a/src/sp_config.h +++ b/src/sp_config.h @@ -57,7 +57,7 @@ typedef struct { typedef struct { bool enable; -} sp_config_disable_xxe; +} sp_config_xxe_protection; typedef struct { enum samesite_type { strict = 1, lax = 2 } samesite; @@ -202,7 +202,7 @@ typedef struct { #define SP_TOKEN_READONLY_EXEC "readonly_exec" #define SP_TOKEN_UNSERIALIZE_HMAC "unserialize_hmac" #define SP_TOKEN_UPLOAD_VALIDATION "upload_validation" -#define SP_TOKEN_DISABLE_XXE "disable_xxe" +#define SP_TOKEN_XXE_PROTECTION "xxe_protection" #define SP_TOKEN_EVAL_BLACKLIST "eval_blacklist" #define SP_TOKEN_EVAL_WHITELIST "eval_whitelist" #define SP_TOKEN_SLOPPY_COMPARISON "sloppy_comparison" diff --git a/src/tests/xxe/config/disable_xxe.ini b/src/tests/xxe/config/disable_xxe.ini index bc9d1f2..a50a3b9 100644 --- a/src/tests/xxe/config/disable_xxe.ini +++ b/src/tests/xxe/config/disable_xxe.ini @@ -1 +1 @@ -sp.disable_xxe.enable(); +sp.xxe_protection.enable(); diff --git a/src/tests/xxe/config/disable_xxe_disable.ini b/src/tests/xxe/config/disable_xxe_disable.ini index bb1e432..eaf5755 100644 --- a/src/tests/xxe/config/disable_xxe_disable.ini +++ b/src/tests/xxe/config/disable_xxe_disable.ini @@ -1 +1 @@ -sp.disable_xxe.disable(); +sp.xxe_protection.disable(); diff --git a/src/tests/xxe/disable_xxe_dom_disabled.phpt b/src/tests/xxe/disable_xxe_dom_disabled.phpt index a49e094..107171c 100644 --- a/src/tests/xxe/disable_xxe_dom_disabled.phpt +++ b/src/tests/xxe/disable_xxe_dom_disabled.phpt @@ -1,10 +1,10 @@ --TEST-- -Disable XXE +Disable XXE (feature enabled) --SKIPIF-- = 80000) print "skip"; ?> --INI-- -sp.configuration_file={PWD}/config/disable_xxe_disable.ini +sp.configuration_file={PWD}/config/disable_xxe.ini --EXTENSIONS-- dom --FILE-- diff --git a/src/tests/xxe/disable_xxe_simplexml.phpt b/src/tests/xxe/disable_xxe_simplexml.phpt index 1d3ef4c..9560156 100644 --- a/src/tests/xxe/disable_xxe_simplexml.phpt +++ b/src/tests/xxe/disable_xxe_simplexml.phpt @@ -2,8 +2,9 @@ Disable XXE --SKIPIF-- += 80000) print "skip"; ?> --INI-- -sp.configuration_file={PWD}/config/disable_xxe.ini +sp.configuration_file={PWD}/config/disable_xxe_disable.ini --EXTENSIONS-- simplexml --XFAIL-- diff --git a/src/tests/xxe/disable_xxe_simplexml_oop.phpt b/src/tests/xxe/disable_xxe_simplexml_oop.phpt index e101337..1b2c4ca 100644 --- a/src/tests/xxe/disable_xxe_simplexml_oop.phpt +++ b/src/tests/xxe/disable_xxe_simplexml_oop.phpt @@ -2,8 +2,9 @@ Disable XXE --SKIPIF-- += 80000) print "skip"; ?> --INI-- -sp.configuration_file={PWD}/config/disable_xxe.ini +sp.configuration_file={PWD}/config/disable_xxe_disable.ini --EXTENSIONS-- simplexml --XFAIL-- diff --git a/src/tests/xxe/disable_xxe_xml_parse.phpt b/src/tests/xxe/disable_xxe_xml_parse.phpt index 6b48bea..bc7e338 100644 --- a/src/tests/xxe/disable_xxe_xml_parse.phpt +++ b/src/tests/xxe/disable_xxe_xml_parse.phpt @@ -70,7 +70,8 @@ $parser = create_parser(); $doc = xml_parse($parser, $xml, true); xml_parser_free($parser); ---EXPECT-- +--EXPECTF-- +Warning: [snuffleupagus][0.0.0.0][xxe][log] A call to libxml_disable_entity_loader was tried and nopped in %a.php on line 41 string(4) "TEST" array(0) { @@ -81,6 +82,8 @@ array(0) { } string(7) "TESTING" string(4) "TEST" + +Warning: [snuffleupagus][0.0.0.0][xxe][log] A call to libxml_disable_entity_loader was tried and nopped in %a.php on line 46 string(4) "TEST" array(0) { -- cgit v1.3 From 0462573a7678468b19bc4865c75f7b82dbedbe03 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Fri, 19 Nov 2021 16:47:08 +0100 Subject: added old php version check --- src/php_snuffleupagus.h | 1 + src/snuffleupagus.c | 13 +++++++++++++ src/sp_config.h | 1 + src/sp_config_keywords.c | 3 ++- .../config/broken_conf_enable_disable2.ini | 1 + .../broken_conf_enable_disable2.phpt | 5 ----- 6 files changed, 18 insertions(+), 6 deletions(-) (limited to 'src/snuffleupagus.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 6095651e2caa729ff56ae5a53c908b09e5f7dc29 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Tue, 30 Nov 2021 19:38:34 +0100 Subject: PHP 8.1 compatibility with streams/includes + fix for ticks --- src/snuffleupagus.c | 1 - src/sp_disabled_functions.c | 12 +++----- src/sp_execute.c | 40 ++++++++++++++++++++------ src/tests/ini/config/sp-policy-drop.ini | 2 +- src/tests/ini/config/sp-policy-silent-fail.ini | 2 +- src/tests/ini/config/sp.ini | 3 +- src/tests/ini/ini_min_policy_drop.phpt | 4 +-- src/tests/ini/ini_min_policy_silent_fail.phpt | 4 +-- src/tests/ini/ini_minmax.phpt | 24 ++++++++-------- 9 files changed, 55 insertions(+), 37 deletions(-) (limited to 'src/snuffleupagus.c') diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index e3ecd72..01a0b01 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -370,7 +370,6 @@ static PHP_INI_MH(OnUpdateConfiguration) { 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 || diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c index 4ef72bf..a3b3e99 100644 --- a/src/sp_disabled_functions.c +++ b/src/sp_disabled_functions.c @@ -498,11 +498,9 @@ static int hook_functions_regexp(const sp_list_node* config) { assert(function_name || function_name_regexp); if (function_name) { - HOOK_FUNCTION(ZSTR_VAL(function_name), disabled_functions_hook, - PHP_FN(check_disabled_function)); + HOOK_FUNCTION(ZSTR_VAL(function_name), disabled_functions_hook, PHP_FN(check_disabled_function)); } else { - HOOK_FUNCTION_BY_REGEXP(function_name_regexp, disabled_functions_hook, - PHP_FN(check_disabled_function)); + HOOK_FUNCTION_BY_REGEXP(function_name_regexp, disabled_functions_hook, PHP_FN(check_disabled_function)); } config = config->next; @@ -515,10 +513,8 @@ static void hook_functions(HashTable* to_hook_ht, HashTable* hooked_ht) { zval* value; ZEND_HASH_FOREACH_STR_KEY_VAL(to_hook_ht, key, value) { - bool hooked = HOOK_FUNCTION(ZSTR_VAL(key), disabled_functions_hook, - PHP_FN(check_disabled_function)); - bool is_builtin = - check_is_builtin_name(((sp_list_node*)Z_PTR_P(value))->data); + bool hooked = HOOK_FUNCTION(ZSTR_VAL(key), disabled_functions_hook, PHP_FN(check_disabled_function)); + bool is_builtin = check_is_builtin_name(((sp_list_node*)Z_PTR_P(value))->data); if (hooked || is_builtin) { zend_symtable_add_new(hooked_ht, key, value); zend_hash_del(to_hook_ht, key); diff --git a/src/sp_execute.c b/src/sp_execute.c index ccb7508..f540119 100644 --- a/src/sp_execute.c +++ b/src/sp_execute.c @@ -3,8 +3,11 @@ static void (*orig_execute_ex)(zend_execute_data *execute_data) = NULL; static void (*orig_zend_execute_internal)(zend_execute_data *execute_data, zval *return_value) = NULL; -static int (*orig_zend_stream_open)(const char *filename, - zend_file_handle *handle) = NULL; +#if PHP_VERSION_ID < 80100 +static int (*orig_zend_stream_open)(const char *filename, zend_file_handle *handle) = NULL; +#else +static zend_result (*orig_zend_stream_open)(zend_file_handle *handle) = NULL; +#endif // FIXME handle symlink ZEND_COLD static inline void terminate_if_writable(const char *filename) { @@ -168,6 +171,7 @@ static void sp_execute_ex(zend_execute_data *execute_data) { case ZEND_DO_FCALL_BY_NAME: case ZEND_DO_ICALL: case ZEND_DO_UCALL: + case ZEND_TICKS: should_disable_ht(execute_data, function_name, NULL, NULL, config_disabled_functions_reg, config_disabled_functions); @@ -209,21 +213,21 @@ static void sp_zend_execute_internal(INTERNAL_FUNCTION_PARAMETERS) { } } -static int sp_stream_open(const char *filename, zend_file_handle *handle) { +static inline void sp_stream_open_checks(zend_string *zend_filename, zend_file_handle *handle) { zend_execute_data const *const data = EG(current_execute_data); if ((NULL == data) || (NULL == data->opline) || (data->func->type != ZEND_USER_FUNCTION)) { - goto end; + return; } - zend_string *zend_filename = zend_string_init(filename, strlen(filename), 0); + // zend_string *zend_filename = zend_string_init(filename, strlen(filename), 0); const HashTable *disabled_functions_hooked = SPCFG(disabled_functions_hooked); switch (data->opline->opcode) { case ZEND_INCLUDE_OR_EVAL: if (SPCFG(readonly_exec).enable) { - terminate_if_writable(filename); + terminate_if_writable(ZSTR_VAL(zend_filename)); } switch (data->opline->extended_value) { case ZEND_INCLUDE: @@ -253,12 +257,32 @@ static int sp_stream_open(const char *filename, zend_file_handle *handle) { EMPTY_SWITCH_DEFAULT_CASE(); // LCOV_EXCL_LINE } } - efree(zend_filename); + // efree(zend_filename); + +// end: + // return orig_zend_stream_open(filename, handle); +} + +#if PHP_VERSION_ID < 80100 + +static int sp_stream_open(const char *filename, zend_file_handle *handle) { + zend_string *zend_filename = zend_string_init(filename, strlen(filename), 0); -end: + sp_stream_open_checks(zend_filename, handle); + + zend_string_release_ex(zend_filename, 0); return orig_zend_stream_open(filename, handle); } +#else // PHP >= 8.1 + +static zend_result sp_stream_open(zend_file_handle *handle) { + sp_stream_open_checks(handle->filename, handle); + return orig_zend_stream_open(handle); +} + +#endif + int hook_execute(void) { TSRMLS_FETCH(); diff --git a/src/tests/ini/config/sp-policy-drop.ini b/src/tests/ini/config/sp-policy-drop.ini index 1c28030..4b1e374 100644 --- a/src/tests/ini/config/sp-policy-drop.ini +++ b/src/tests/ini/config/sp-policy-drop.ini @@ -1,3 +1,3 @@ sp.ini_protection.enable(); sp.ini_protection.policy_drop(); -sp.ini.key("log_errors_max_len").min("200").max("2000"); +sp.ini.key("max_execution_time").min("30").max("300"); diff --git a/src/tests/ini/config/sp-policy-silent-fail.ini b/src/tests/ini/config/sp-policy-silent-fail.ini index 8236077..2123837 100644 --- a/src/tests/ini/config/sp-policy-silent-fail.ini +++ b/src/tests/ini/config/sp-policy-silent-fail.ini @@ -1,3 +1,3 @@ sp.ini_protection.enable(); sp.ini_protection.policy_silent_fail(); -sp.ini.key("log_errors_max_len").min("200").max("2000"); +sp.ini.key("max_execution_time").min("30").max("300"); diff --git a/src/tests/ini/config/sp.ini b/src/tests/ini/config/sp.ini index 3022e37..86a63a7 100644 --- a/src/tests/ini/config/sp.ini +++ b/src/tests/ini/config/sp.ini @@ -1,7 +1,6 @@ sp.ini_protection.enable(); -sp.ini.key("log_errors_max_len").min("200").max("2000"); -sp.ini.key("max_execution_time").min("30").max("600"); +sp.ini.key("max_execution_time").min("30").max("300"); sp.ini.key("highlight.comment").regexp("^#[0-9a-fA-F]{6}$"); sp.ini.key("default_mimetype").set("text/plain").ro(); diff --git a/src/tests/ini/ini_min_policy_drop.phpt b/src/tests/ini/ini_min_policy_drop.phpt index 9dddcc4..ef40ebc 100644 --- a/src/tests/ini/ini_min_policy_drop.phpt +++ b/src/tests/ini/ini_min_policy_drop.phpt @@ -6,8 +6,8 @@ INI protection .min() + .policy_drop() sp.configuration_file={PWD}/config/sp-policy-drop.ini --FILE-- --EXPECTF-- Fatal error: [snuffleupagus][0.0.0.0][ini_protection][drop] INI value out of range in %a/ini_min_policy_drop.php on line 2 diff --git a/src/tests/ini/ini_min_policy_silent_fail.phpt b/src/tests/ini/ini_min_policy_silent_fail.phpt index 8ef780d..d0117a7 100644 --- a/src/tests/ini/ini_min_policy_silent_fail.phpt +++ b/src/tests/ini/ini_min_policy_silent_fail.phpt @@ -6,8 +6,8 @@ INI protection .min() + .policy_silent_fail() sp.configuration_file={PWD}/config/sp-policy-silent-fail.ini --FILE-- --EXPECTF-- bool(true) diff --git a/src/tests/ini/ini_minmax.phpt b/src/tests/ini/ini_minmax.phpt index fc93075..4cd6bc4 100644 --- a/src/tests/ini/ini_minmax.phpt +++ b/src/tests/ini/ini_minmax.phpt @@ -6,29 +6,29 @@ INI protection .min()/.max() sp.configuration_file={PWD}/config/sp.ini --FILE-- --EXPECTF-- bool(false) -string(3) "200" +string(2) "30" bool(false) -string(4) "2000" +string(3) "300" Warning: [snuffleupagus][0.0.0.0][ini_protection][log] INI value out of range in %a/ini_minmax.php on line 8 bool(true) -string(4) "2000" +string(3) "300" Warning: [snuffleupagus][0.0.0.0][ini_protection][log] INI value out of range in %a/ini_minmax.php on line 11 bool(true) -string(4) "2000" \ No newline at end of file +string(3) "300" \ No newline at end of file -- cgit v1.3 From c160736a503c853366c0cfb72e7a1a316cb5eef2 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Tue, 14 Dec 2021 14:17:32 +0100 Subject: fixed typo where execution hook may not have been active --- src/snuffleupagus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/snuffleupagus.c') diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 01a0b01..de68130 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -366,7 +366,7 @@ static PHP_INI_MH(OnUpdateConfiguration) { 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))); + (SPCFG(disabled_functions_ret) && zend_hash_num_elements(SPCFG(disabled_functions_ret))); if (SPCFG(show_old_php_warning)) { time_t ts = time(NULL); -- cgit v1.3 From d3d9b594fe904e6d101522617fdcf18dc5518b16 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Mon, 20 Dec 2021 16:26:12 +0100 Subject: added @warn/@err to config syntax --- src/snuffleupagus.c | 3 +- src/sp_config_scanner.cached.c | 937 +++++++++++++++++++++++++---------------- src/sp_config_scanner.re | 26 +- 3 files changed, 593 insertions(+), 373 deletions(-) (limited to 'src/snuffleupagus.c') diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index de68130..3baad1b 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -223,8 +223,7 @@ PHP_RINIT_FUNCTION(snuffleupagus) { if (SPG(is_config_valid) == SP_CONFIG_INVALID) { sp_log_err("config", "Invalid configuration file"); } else if (SPG(is_config_valid) == SP_CONFIG_NONE) { - sp_log_warn("config", - "No configuration specificed via sp.configuration_file"); + sp_log_warn("config", "No configuration specificed via sp.configuration_file"); } } diff --git a/src/sp_config_scanner.cached.c b/src/sp_config_scanner.cached.c index 91144c7..bd2fa3c 100644 --- a/src/sp_config_scanner.cached.c +++ b/src/sp_config_scanner.cached.c @@ -11,6 +11,8 @@ enum YYCONDTYPE { #define cs_log_error(fmt, ...) sp_log_err("config", fmt, ##__VA_ARGS__) #define cs_log_info(fmt, ...) sp_log_msg("config", SP_LOG_INFO, fmt, ##__VA_ARGS__) +#define cs_log_warning(fmt, ...) sp_log_warn("config", fmt, ##__VA_ARGS__) + zend_string *sp_get_arg_string(sp_parsed_keyword *kw) { if (!kw || !kw->arg) { @@ -133,6 +135,12 @@ static int sy_apply_op(char op, int a, int b) { int res = sy_apply_op(op, a, b); \ sy_res_push(res); +#define TMPSTR(tmpstr, t2, t1) \ + char tmpstr[1024]; \ + size_t tmplen = MIN(t2-t1-2, 1023); \ + strncpy(tmpstr, t1+1, tmplen); \ + tmpstr[tmplen] = 0; + zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_keyword*)) { @@ -270,23 +278,23 @@ yy12: yy15: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych <= 'd') { - if (yych == 'c') goto yy17; - goto yy5; - } else { - if (yych <= 'e') goto yy19; - if (yych == 'l') goto yy20; - goto yy5; + switch (yych) { + case 'c': goto yy17; + case 'e': goto yy19; + case 'i': goto yy20; + case 'l': goto yy21; + case 'w': goto yy22; + default: goto yy5; } yy16: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == 'e') goto yy21; - if (yych == 'p') goto yy22; + if (yych == 'e') goto yy23; + if (yych == 'p') goto yy24; goto yy5; yy17: yych = *++YYCURSOR; - if (yych == 'o') goto yy24; + if (yych == 'o') goto yy26; yy18: YYCURSOR = YYMARKER; if (yyaccept <= 2) { @@ -294,225 +302,406 @@ yy18: if (yyaccept == 0) { goto yy5; } else { - yyt1 = YYCURSOR; - goto yy37; + goto yy66; } } else { - goto yy37; + goto yy70; } } else { - if (yyaccept == 3) { - yyt4 = YYCURSOR; - goto yy57; + if (yyaccept <= 4) { + if (yyaccept == 3) { + goto yy83; + } else { + yyt4 = YYCURSOR; + goto yy88; + } } else { - goto yy57; + goto yy88; } } yy19: yych = *++YYCURSOR; - if (yych == 'n') goto yy25; + if (yych == 'n') goto yy27; + if (yych == 'r') goto yy28; goto yy18; yy20: yych = *++YYCURSOR; - if (yych == 'o') goto yy26; + if (yych == 'n') goto yy29; goto yy18; yy21: yych = *++YYCURSOR; - if (yych == 't') goto yy27; + if (yych == 'o') goto yy30; goto yy18; yy22: - ++YYCURSOR; - { kw_i = 0; goto yyc_rule; } -yy24: yych = *++YYCURSOR; - if (yych == 'n') goto yy28; + if (yych == 'a') goto yy31; goto yy18; -yy25: +yy23: yych = *++YYCURSOR; - if (yych == 'd') goto yy29; + if (yych == 't') goto yy32; goto yy18; +yy24: + ++YYCURSOR; + { kw_i = 0; goto yyc_rule; } yy26: yych = *++YYCURSOR; - if (yych == 'g') goto yy30; + if (yych == 'n') goto yy33; goto yy18; yy27: yych = *++YYCURSOR; - if (yych == '\t') goto yy31; - if (yych == ' ') goto yy31; + if (yych == 'd') goto yy34; goto yy18; yy28: yych = *++YYCURSOR; - if (yych == 'd') goto yy33; + if (yych == 'r') goto yy35; goto yy18; yy29: yych = *++YYCURSOR; - if (yych == '_') goto yy34; + if (yych == 'f') goto yy36; goto yy18; yy30: yych = *++YYCURSOR; - if (yych == '\t') goto yy35; - if (yych == ' ') goto yy35; + if (yych == 'g') goto yy37; goto yy18; yy31: + yych = *++YYCURSOR; + if (yych == 'r') goto yy38; + goto yy18; +yy32: + yych = *++YYCURSOR; + if (yych == '\t') goto yy39; + if (yych == ' ') goto yy39; + goto yy18; +yy33: + yych = *++YYCURSOR; + if (yych == 'd') goto yy41; + goto yy18; +yy34: + yych = *++YYCURSOR; + if (yych == '_') goto yy42; + goto yy18; +yy35: + yych = *++YYCURSOR; + if (yych == '"') goto yy18; + if (yych == 'o') goto yy45; + goto yy44; +yy36: + yych = *++YYCURSOR; + if (yych != 'o') goto yy18; +yy37: + yych = *++YYCURSOR; + if (yych == '"') goto yy18; + goto yy47; +yy38: + yych = *++YYCURSOR; + if (yych == 'n') goto yy48; + goto yy18; +yy39: yych = *++YYCURSOR; if (yych <= '@') { if (yych <= '\t') { if (yych <= 0x08) goto yy18; - goto yy31; + goto yy39; } else { - if (yych == ' ') goto yy31; + if (yych == ' ') goto yy39; goto yy18; } } else { if (yych <= '_') { if (yych <= 'Z') { yyt1 = YYCURSOR; - goto yy38; + goto yy49; } if (yych <= '^') goto yy18; yyt1 = YYCURSOR; - goto yy38; + goto yy49; } else { if (yych <= '`') goto yy18; if (yych <= 'z') { yyt1 = YYCURSOR; - goto yy38; + goto yy49; } goto yy18; } } -yy33: +yy41: yych = *++YYCURSOR; - if (yych == 'i') goto yy40; + if (yych == 'i') goto yy51; goto yy18; -yy34: +yy42: yych = *++YYCURSOR; - if (yych == 'c') goto yy41; + if (yych == 'c') goto yy52; goto yy18; -yy35: - yyaccept = 1; - yych = *(YYMARKER = ++YYCURSOR); +yy43: + yych = *++YYCURSOR; +yy44: if (yych <= 0x1F) { - if (yych == '\t') goto yy35; - yyt1 = YYCURSOR; + if (yych == '\t') goto yy43; + goto yy18; } else { - if (yych <= ' ') goto yy35; + if (yych <= ' ') goto yy43; if (yych == '"') { yyt1 = YYCURSOR; - goto yy42; + goto yy53; } - yyt1 = YYCURSOR; + goto yy18; } -yy37: - t1 = yyt1; - t2 = YYCURSOR; - { - char tmpstr[1024]; - size_t tmplen = MIN(t2-t1-2, 1023); - strncpy(tmpstr, t1+1, tmplen); - tmpstr[tmplen] = 0; - cs_log_info("[line %d]: %s", lineno, tmpstr); - goto yyc_init; - } -yy38: +yy45: + yych = *++YYCURSOR; + if (yych == 'r') goto yy55; + goto yy18; +yy46: + yych = *++YYCURSOR; +yy47: + if (yych <= 0x1F) { + if (yych == '\t') goto yy46; + goto yy18; + } else { + if (yych <= ' ') goto yy46; + if (yych == '"') { + yyt1 = YYCURSOR; + goto yy56; + } + goto yy18; + } +yy48: + yych = *++YYCURSOR; + if (yych == '"') goto yy18; + if (yych == 'i') goto yy60; + goto yy59; +yy49: yych = *++YYCURSOR; if (yybm[0+yych] & 32) { - goto yy38; + goto yy49; } if (yych == '\t') { yyt2 = YYCURSOR; - goto yy44; + goto yy61; } if (yych == ' ') { yyt2 = YYCURSOR; - goto yy44; + goto yy61; } goto yy18; -yy40: +yy51: yych = *++YYCURSOR; - if (yych == 't') goto yy46; + if (yych == 't') goto yy63; goto yy18; -yy41: +yy52: yych = *++YYCURSOR; - if (yych == 'o') goto yy47; + if (yych == 'o') goto yy64; goto yy18; -yy42: +yy53: yych = *++YYCURSOR; if (yybm[0+yych] & 64) { - goto yy42; + goto yy53; } if (yych <= '\r') goto yy18; - if (yych <= '"') goto yy48; - goto yy49; -yy44: + if (yych <= '"') goto yy65; + goto yy67; +yy55: yych = *++YYCURSOR; + if (yych == '"') goto yy18; + goto yy44; +yy56: + yych = *++YYCURSOR; + if (yych <= '\r') { + if (yych == '\n') goto yy18; + if (yych <= '\f') goto yy56; + goto yy18; + } else { + if (yych <= '"') { + if (yych <= '!') goto yy56; + goto yy69; + } else { + if (yych == '\\') goto yy71; + goto yy56; + } + } +yy58: + yych = *++YYCURSOR; +yy59: if (yych <= 0x1F) { - if (yych == '\t') goto yy44; + if (yych == '\t') goto yy58; goto yy18; } else { - if (yych <= ' ') goto yy44; + if (yych <= ' ') goto yy58; + if (yych == '"') { + yyt1 = YYCURSOR; + goto yy73; + } + goto yy18; + } +yy60: + yych = *++YYCURSOR; + if (yych == 'n') goto yy75; + goto yy18; +yy61: + yych = *++YYCURSOR; + if (yych <= 0x1F) { + if (yych == '\t') goto yy61; + goto yy18; + } else { + if (yych <= ' ') goto yy61; if (yych == '"') { yyt3 = YYCURSOR; - goto yy51; + goto yy76; } goto yy18; } -yy46: +yy63: yych = *++YYCURSOR; - if (yych == 'i') goto yy53; + if (yych == 'i') goto yy78; goto yy18; -yy47: +yy64: yych = *++YYCURSOR; - if (yych == 'n') goto yy54; + if (yych == 'n') goto yy79; goto yy18; -yy48: +yy65: ++YYCURSOR; - goto yy37; -yy49: +yy66: + t1 = yyt1; + t2 = YYCURSOR; + { + TMPSTR(tmpstr, t2, t1); + cs_log_error("[line %d]: %s", lineno, tmpstr); + goto out; + } +yy67: yych = *++YYCURSOR; if (yybm[0+yych] & 64) { - goto yy42; + goto yy53; } if (yych <= '\r') goto yy18; - if (yych <= '"') goto yy55; - goto yy49; -yy51: + if (yych <= '"') goto yy80; + goto yy67; +yy69: + ++YYCURSOR; +yy70: + t1 = yyt1; + t2 = YYCURSOR; + { + TMPSTR(tmpstr, t2, t1); + sp_log_debug("tmplen: %d", tmplen); + cs_log_info("[line %d]: %s", lineno, tmpstr); + goto yyc_init; + } +yy71: yych = *++YYCURSOR; if (yych <= '\r') { if (yych == '\n') goto yy18; - if (yych <= '\f') goto yy51; + if (yych <= '\f') goto yy56; goto yy18; } else { if (yych <= '"') { - if (yych <= '!') goto yy51; + if (yych <= '!') goto yy56; + goto yy81; + } else { + if (yych == '\\') goto yy71; goto yy56; + } + } +yy73: + yych = *++YYCURSOR; + if (yych <= '\r') { + if (yych == '\n') goto yy18; + if (yych <= '\f') goto yy73; + goto yy18; + } else { + if (yych <= '"') { + if (yych <= '!') goto yy73; + goto yy82; } else { - if (yych == '\\') goto yy58; - goto yy51; + if (yych == '\\') goto yy84; + goto yy73; } } -yy53: +yy75: yych = *++YYCURSOR; - if (yych == 'o') goto yy60; + if (yych == 'g') goto yy86; goto yy18; -yy54: +yy76: yych = *++YYCURSOR; - if (yych == 'd') goto yy61; + if (yych <= '\r') { + if (yych == '\n') goto yy18; + if (yych <= '\f') goto yy76; + goto yy18; + } else { + if (yych <= '"') { + if (yych <= '!') goto yy76; + goto yy87; + } else { + if (yych == '\\') goto yy89; + goto yy76; + } + } +yy78: + yych = *++YYCURSOR; + if (yych == 'o') goto yy91; goto yy18; -yy55: - yyaccept = 2; +yy79: + yych = *++YYCURSOR; + if (yych == 'd') goto yy92; + goto yy18; +yy80: + yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); if (yybm[0+yych] & 64) { - goto yy42; + goto yy53; } - if (yych <= '\r') goto yy37; - if (yych <= '"') goto yy48; - goto yy49; -yy56: + if (yych <= '\r') goto yy66; + if (yych <= '"') goto yy65; + goto yy67; +yy81: + yyaccept = 2; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '\r') { + if (yych == '\n') goto yy70; + if (yych <= '\f') goto yy56; + goto yy70; + } else { + if (yych <= '"') { + if (yych <= '!') goto yy56; + goto yy69; + } else { + if (yych == '\\') goto yy71; + goto yy56; + } + } +yy82: + ++YYCURSOR; +yy83: + t1 = yyt1; + t2 = YYCURSOR; + { + TMPSTR(tmpstr, t2, t1); + cs_log_warning("[line %d]: %s", lineno, tmpstr); + goto yyc_init; + } +yy84: + yych = *++YYCURSOR; + if (yych <= '\r') { + if (yych == '\n') goto yy18; + if (yych <= '\f') goto yy73; + goto yy18; + } else { + if (yych <= '"') { + if (yych <= '!') goto yy73; + goto yy93; + } else { + if (yych == '\\') goto yy84; + goto yy73; + } + } +yy86: + yych = *++YYCURSOR; + if (yych == '"') goto yy18; + goto yy59; +yy87: yych = *++YYCURSOR; yyt4 = YYCURSOR; - goto yy63; -yy57: + goto yy95; +yy88: t1 = yyt1; t2 = yyt2; t3 = yyt3; @@ -528,142 +717,158 @@ yy57: zend_hash_str_add_ptr(&vars, key, keylen, tmp); goto yyc_init; } -yy58: +yy89: yych = *++YYCURSOR; if (yych <= '\r') { if (yych == '\n') goto yy18; - if (yych <= '\f') goto yy51; + if (yych <= '\f') goto yy76; goto yy18; } else { if (yych <= '"') { - if (yych <= '!') goto yy51; - goto yy65; + if (yych <= '!') goto yy76; + goto yy97; } else { - if (yych == '\\') goto yy58; - goto yy51; + if (yych == '\\') goto yy89; + goto yy76; } } -yy60: +yy91: yych = *++YYCURSOR; - if (yych == 'n') goto yy66; + if (yych == 'n') goto yy98; goto yy18; -yy61: +yy92: yych = *++YYCURSOR; - if (yych == 'i') goto yy67; + if (yych == 'i') goto yy99; goto yy18; -yy62: +yy93: + yyaccept = 3; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= '\r') { + if (yych == '\n') goto yy83; + if (yych <= '\f') goto yy73; + goto yy83; + } else { + if (yych <= '"') { + if (yych <= '!') goto yy73; + goto yy82; + } else { + if (yych == '\\') goto yy84; + goto yy73; + } + } +yy94: yych = *++YYCURSOR; -yy63: +yy95: if (yych <= 0x1F) { - if (yych == '\t') goto yy62; - goto yy57; + if (yych == '\t') goto yy94; + goto yy88; } else { - if (yych <= ' ') goto yy62; - if (yych != ';') goto yy57; + if (yych <= ' ') goto yy94; + if (yych != ';') goto yy88; } ++YYCURSOR; - goto yy57; -yy65: - yyaccept = 3; + goto yy88; +yy97: + yyaccept = 4; yych = *(YYMARKER = ++YYCURSOR); if (yych <= ' ') { if (yych <= '\n') { - if (yych <= 0x08) goto yy51; + if (yych <= 0x08) goto yy76; if (yych <= '\t') { yyt4 = YYCURSOR; - goto yy68; + goto yy100; } yyt4 = YYCURSOR; - goto yy57; + goto yy88; } else { if (yych == '\r') { yyt4 = YYCURSOR; - goto yy57; + goto yy88; } - if (yych <= 0x1F) goto yy51; + if (yych <= 0x1F) goto yy76; yyt4 = YYCURSOR; - goto yy68; + goto yy100; } } else { if (yych <= ':') { - if (yych == '"') goto yy56; - goto yy51; + if (yych == '"') goto yy87; + goto yy76; } else { if (yych <= ';') { yyt4 = YYCURSOR; - goto yy70; + goto yy102; } - if (yych == '\\') goto yy58; - goto yy51; + if (yych == '\\') goto yy89; + goto yy76; } } -yy66: +yy98: yych = *++YYCURSOR; - if (yych == '\t') goto yy71; - if (yych == ' ') goto yy71; + if (yych == '\t') goto yy103; + if (yych == ' ') goto yy103; goto yy18; -yy67: +yy99: yych = *++YYCURSOR; - if (yych == 't') goto yy74; + if (yych == 't') goto yy106; goto yy18; -yy68: - yyaccept = 4; +yy100: + yyaccept = 5; yych = *(YYMARKER = ++YYCURSOR); if (yych <= ' ') { if (yych <= '\n') { - if (yych <= 0x08) goto yy51; - if (yych <= '\t') goto yy68; - goto yy57; + if (yych <= 0x08) goto yy76; + if (yych <= '\t') goto yy100; + goto yy88; } else { - if (yych == '\r') goto yy57; - if (yych <= 0x1F) goto yy51; - goto yy68; + if (yych == '\r') goto yy88; + if (yych <= 0x1F) goto yy76; + goto yy100; } } else { if (yych <= ':') { - if (yych == '"') goto yy56; - goto yy51; + if (yych == '"') goto yy87; + goto yy76; } else { - if (yych <= ';') goto yy70; - if (yych == '\\') goto yy58; - goto yy51; + if (yych <= ';') goto yy102; + if (yych == '\\') goto yy89; + goto yy76; } } -yy70: - yyaccept = 4; +yy102: + yyaccept = 5; yych = *(YYMARKER = ++YYCURSOR); if (yych <= '\r') { - if (yych == '\n') goto yy57; - if (yych <= '\f') goto yy51; - goto yy57; + if (yych == '\n') goto yy88; + if (yych <= '\f') goto yy76; + goto yy88; } else { if (yych <= '"') { - if (yych <= '!') goto yy51; - goto yy56; + if (yych <= '!') goto yy76; + goto yy87; } else { - if (yych == '\\') goto yy58; - goto yy51; + if (yych == '\\') goto yy89; + goto yy76; } } -yy71: +yy103: yych = *++YYCURSOR; - if (yych == '\t') goto yy71; - if (yych == ' ') goto yy71; + if (yych == '\t') goto yy103; + if (yych == ' ') goto yy103; { goto yyc_cond; } -yy74: +yy106: yych = *++YYCURSOR; if (yych != 'i') goto yy18; yych = *++YYCURSOR; if (yych != 'o') goto yy18; yych = *++YYCURSOR; if (yych != 'n') goto yy18; -yy77: +yy109: yych = *++YYCURSOR; if (yych <= 0x1F) { - if (yych == '\t') goto yy77; + if (yych == '\t') goto yy109; goto yy18; } else { - if (yych <= ' ') goto yy77; + if (yych <= ' ') goto yy109; if (yych != ';') goto yy18; } ++YYCURSOR; @@ -708,85 +913,85 @@ yyc_cond: }; yych = *YYCURSOR; if (yybm[0+yych] & 8) { - goto yy85; + goto yy117; } if (yych <= '(') { if (yych <= '\r') { - if (yych <= 0x08) goto yy83; - if (yych <= '\n') goto yy88; - if (yych >= '\r') goto yy90; + if (yych <= 0x08) goto yy115; + if (yych <= '\n') goto yy120; + if (yych >= '\r') goto yy122; } else { - if (yych <= 0x1F) goto yy83; - if (yych <= '!') goto yy91; - if (yych >= '(') goto yy93; + if (yych <= 0x1F) goto yy115; + if (yych <= '!') goto yy123; + if (yych >= '(') goto yy125; } } else { if (yych <= 'Z') { - if (yych <= '/') goto yy83; + if (yych <= '/') goto yy115; if (yych <= '9') { yyt1 = YYCURSOR; - goto yy95; + goto yy127; } if (yych >= 'A') { yyt1 = YYCURSOR; - goto yy98; + goto yy130; } } else { if (yych <= '_') { if (yych >= '_') { yyt1 = YYCURSOR; - goto yy98; + goto yy130; } } else { - if (yych <= '`') goto yy83; + if (yych <= '`') goto yy115; if (yych <= 'z') { yyt1 = YYCURSOR; - goto yy98; + goto yy130; } } } } -yy83: +yy115: ++YYCURSOR; -yy84: +yy116: { cs_log_error("Syntax error in condition on line %d", lineno); goto out; } -yy85: +yy117: yych = *++YYCURSOR; if (yybm[0+yych] & 8) { - goto yy85; + goto yy117; } { goto yyc_cond; } -yy88: +yy120: ++YYCURSOR; { lineno++; goto yyc_cond; } -yy90: +yy122: yych = *++YYCURSOR; - if (yych == '\n') goto yy88; - goto yy84; -yy91: + if (yych == '\n') goto yy120; + goto yy116; +yy123: ++YYCURSOR; t1 = YYCURSOR - 1; { sy_op_push(*t1); goto yyc_cond; } -yy93: +yy125: ++YYCURSOR; t1 = YYCURSOR - 1; { sy_op_push(*t1); goto yyc_cond; } -yy95: +yy127: yych = *++YYCURSOR; if (yybm[0+yych] & 16) { - goto yy95; + goto yy127; } t1 = yyt1; t2 = YYCURSOR; { sy_res_push(atoi(t1)); goto yyc_cond_op; } -yy98: +yy130: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); if (yybm[0+yych] & 32) { - goto yy98; + goto yy130; } - if (yych == '(') goto yy101; -yy100: + if (yych == '(') goto yy133; +yy132: t1 = yyt1; t2 = YYCURSOR; { @@ -798,34 +1003,34 @@ yy100: sy_res_push(atoi(ZSTR_VAL(tmp))); goto yyc_cond_op; } -yy101: +yy133: yych = *++YYCURSOR; if (yych == '"') { yyt2 = YYCURSOR; - goto yy103; + goto yy135; } if (yych == ')') { yyt2 = YYCURSOR; - goto yy105; + goto yy137; } -yy102: +yy134: YYCURSOR = YYMARKER; if (yyaccept == 0) { - goto yy100; + goto yy132; } else { - goto yy106; + goto yy138; } -yy103: +yy135: yych = *++YYCURSOR; if (yybm[0+yych] & 64) { - goto yy103; + goto yy135; } - if (yych <= '\r') goto yy102; - if (yych <= '"') goto yy107; - goto yy108; -yy105: + if (yych <= '\r') goto yy134; + if (yych <= '"') goto yy139; + goto yy140; +yy137: ++YYCURSOR; -yy106: +yy138: t1 = yyt1; t3 = yyt2; t2 = yyt2 - 1; @@ -840,41 +1045,41 @@ yy106: } goto yyc_cond_op; } -yy107: +yy139: yych = *++YYCURSOR; - if (yych == ')') goto yy105; - goto yy102; -yy108: + if (yych == ')') goto yy137; + goto yy134; +yy140: yych = *++YYCURSOR; if (yybm[0+yych] & 64) { - goto yy103; + goto yy135; } - if (yych <= '\r') goto yy102; - if (yych >= '#') goto yy108; + if (yych <= '\r') goto yy134; + if (yych >= '#') goto yy140; yych = *++YYCURSOR; if (yybm[0+yych] & 128) { - goto yy108; + goto yy140; } if (yych <= '\r') { - if (yych == '\n') goto yy102; - if (yych <= '\f') goto yy103; - goto yy102; + if (yych == '\n') goto yy134; + if (yych <= '\f') goto yy135; + goto yy134; } else { if (yych <= '"') { - if (yych <= '!') goto yy103; - goto yy107; + if (yych <= '!') goto yy135; + goto yy139; } else { - if (yych != ')') goto yy103; + if (yych != ')') goto yy135; } } yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); if (yybm[0+yych] & 64) { - goto yy103; + goto yy135; } - if (yych <= '\r') goto yy106; - if (yych <= '"') goto yy107; - goto yy108; + if (yych <= '\r') goto yy138; + if (yych <= '"') goto yy139; + goto yy140; } /* *********************************** */ yyc_cond_op: @@ -915,63 +1120,63 @@ yyc_cond_op: }; yych = *YYCURSOR; if (yybm[0+yych] & 128) { - goto yy116; + goto yy148; } if (yych <= ')') { if (yych <= '\r') { - if (yych <= 0x08) goto yy114; - if (yych <= '\n') goto yy119; - if (yych >= '\r') goto yy121; + if (yych <= 0x08) goto yy146; + if (yych <= '\n') goto yy151; + if (yych >= '\r') goto yy153; } else { if (yych == '&') { yyt1 = YYCURSOR; - goto yy122; + goto yy154; } - if (yych >= ')') goto yy123; + if (yych >= ')') goto yy155; } } else { if (yych <= '=') { - if (yych <= ':') goto yy114; - if (yych <= ';') goto yy125; + if (yych <= ':') goto yy146; + if (yych <= ';') goto yy157; if (yych <= '<') { yyt1 = YYCURSOR; - goto yy127; + goto yy159; } yyt1 = YYCURSOR; - goto yy129; + goto yy161; } else { if (yych <= '>') { yyt1 = YYCURSOR; - goto yy127; + goto yy159; } if (yych == '|') { yyt1 = YYCURSOR; - goto yy130; + goto yy162; } } } -yy114: +yy146: ++YYCURSOR; -yy115: +yy147: { cs_log_error("Syntax error in condition on line %d", lineno); goto out; } -yy116: +yy148: yych = *++YYCURSOR; if (yybm[0+yych] & 128) { - goto yy116; + goto yy148; } { goto yyc_cond_op; } -yy119: +yy151: ++YYCURSOR; { lineno++; goto yyc_cond_op; } -yy121: +yy153: yych = *++YYCURSOR; - if (yych == '\n') goto yy119; - goto yy115; -yy122: + if (yych == '\n') goto yy151; + goto yy147; +yy154: yych = *++YYCURSOR; - if (yych == '&') goto yy131; - goto yy115; -yy123: + if (yych == '&') goto yy163; + goto yy147; +yy155: ++YYCURSOR; { while (cond_op_i && sy_op_peek() != '(') { @@ -983,7 +1188,7 @@ yy123: cond_op_i--; goto yyc_cond_op; } -yy125: +yy157: ++YYCURSOR; { while (cond_op_i) { @@ -993,10 +1198,10 @@ yy125: if (cond_res_i > 1) { cs_log_error("invalid condition on line %d", lineno); goto out; } goto yyc_init; } -yy127: +yy159: yych = *++YYCURSOR; - if (yych == '=') goto yy131; -yy128: + if (yych == '=') goto yy163; +yy160: t1 = yyt1; t2 = YYCURSOR; { @@ -1013,16 +1218,16 @@ yy128: sy_op_push(*t1); goto yyc_cond; } -yy129: +yy161: yych = *++YYCURSOR; - if (yych == '=') goto yy131; - goto yy115; -yy130: + if (yych == '=') goto yy163; + goto yy147; +yy162: yych = *++YYCURSOR; - if (yych != '|') goto yy115; -yy131: + if (yych != '|') goto yy147; +yy163: ++YYCURSOR; - goto yy128; + goto yy160; } /* *********************************** */ yyc_rule: @@ -1063,77 +1268,77 @@ yyc_rule: }; yych = *YYCURSOR; if (yybm[0+yych] & 8) { - goto yy136; + goto yy168; } if (yych <= '\r') { - if (yych <= 0x08) goto yy134; - if (yych <= '\n') goto yy139; - if (yych >= '\r') goto yy140; + if (yych <= 0x08) goto yy166; + if (yych <= '\n') goto yy171; + if (yych >= '\r') goto yy172; } else { if (yych <= '.') { - if (yych >= '.') goto yy141; + if (yych >= '.') goto yy173; } else { - if (yych == ';') goto yy142; + if (yych == ';') goto yy174; } } -yy134: +yy166: ++YYCURSOR; -yy135: +yy167: { goto end_of_rule; } -yy136: +yy168: yych = *++YYCURSOR; if (yybm[0+yych] & 8) { - goto yy136; + goto yy168; } { goto yyc_rule; } -yy139: +yy171: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); if (yych <= '\r') { - if (yych <= 0x08) goto yy135; + if (yych <= 0x08) goto yy167; if (yych <= '\n') { yyt1 = YYCURSOR; - goto yy144; + goto yy176; } - if (yych <= '\f') goto yy135; + if (yych <= '\f') goto yy167; yyt1 = YYCURSOR; - goto yy147; + goto yy179; } else { if (yych <= ' ') { - if (yych <= 0x1F) goto yy135; + if (yych <= 0x1F) goto yy167; yyt1 = YYCURSOR; - goto yy144; + goto yy176; } else { if (yych == '.') { yyt1 = YYCURSOR; - goto yy148; + goto yy180; } - goto yy135; + goto yy167; } } -yy140: +yy172: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if (yych == '\n') goto yy150; - goto yy135; -yy141: + if (yych == '\n') goto yy182; + goto yy167; +yy173: yych = *++YYCURSOR; if (yych <= '^') { - if (yych <= '@') goto yy135; + if (yych <= '@') goto yy167; if (yych <= 'Z') { yyt1 = YYCURSOR; - goto yy151; + goto yy183; } - goto yy135; + goto yy167; } else { - if (yych == '`') goto yy135; + if (yych == '`') goto yy167; if (yych <= 'z') { yyt1 = YYCURSOR; - goto yy151; + goto yy183; } - goto yy135; + goto yy167; } -yy142: +yy174: ++YYCURSOR; { end_of_rule: @@ -1144,71 +1349,71 @@ yy142: } goto yyc_init; } -yy144: +yy176: yych = *++YYCURSOR; if (yybm[0+yych] & 16) { - goto yy144; + goto yy176; } - if (yych == '\r') goto yy147; - if (yych == '.') goto yy148; -yy146: + if (yych == '\r') goto yy179; + if (yych == '.') goto yy180; +yy178: YYCURSOR = YYMARKER; if (yyaccept <= 1) { if (yyaccept == 0) { - goto yy135; + goto yy167; } else { yyt3 = yyt4 = NULL; yyt2 = YYCURSOR; - goto yy153; + goto yy185; } } else { - goto yy153; + goto yy185; } -yy147: +yy179: yych = *++YYCURSOR; - if (yych == '\n') goto yy144; - goto yy146; -yy148: + if (yych == '\n') goto yy176; + goto yy178; +yy180: ++YYCURSOR; YYCURSOR = yyt1; { lineno++; goto yyc_rule; } -yy150: +yy182: yych = *++YYCURSOR; if (yych <= '\r') { - if (yych <= 0x08) goto yy146; + if (yych <= 0x08) goto yy178; if (yych <= '\n') { yyt1 = YYCURSOR; - goto yy144; + goto yy176; } - if (yych <= '\f') goto yy146; + if (yych <= '\f') goto yy178; yyt1 = YYCURSOR; - goto yy147; + goto yy179; } else { if (yych <= ' ') { - if (yych <= 0x1F) goto yy146; + if (yych <= 0x1F) goto yy178; yyt1 = YYCURSOR; - goto yy144; + goto yy176; } else { if (yych == '.') { yyt1 = YYCURSOR; - goto yy148; + goto yy180; } - goto yy146; + goto yy178; } } -yy151: +yy183: yyaccept = 1; yych = *(YYMARKER = ++YYCURSOR); if (yybm[0+yych] & 32) { - goto yy151; + goto yy183; } if (yych == '(') { yyt2 = YYCURSOR; - goto yy154; + goto yy186; } yyt3 = yyt4 = NULL; yyt2 = YYCURSOR; -yy153: +yy185: t1 = yyt1; t2 = yyt2; t3 = yyt3; @@ -1243,110 +1448,110 @@ yy153: parsed_rule[kw_i++] = kw; goto yyc_rule; } -yy154: +yy186: yych = *++YYCURSOR; if (yych <= '@') { if (yych <= '"') { - if (yych <= '!') goto yy146; + if (yych <= '!') goto yy178; yyt3 = YYCURSOR; } else { if (yych == ')') { yyt3 = yyt4 = YYCURSOR; - goto yy157; + goto yy189; } - goto yy146; + goto yy178; } } else { if (yych <= '_') { if (yych <= 'Z') { yyt3 = YYCURSOR; - goto yy158; + goto yy190; } - if (yych <= '^') goto yy146; + if (yych <= '^') goto yy178; yyt3 = YYCURSOR; - goto yy158; + goto yy190; } else { - if (yych <= '`') goto yy146; + if (yych <= '`') goto yy178; if (yych <= 'z') { yyt3 = YYCURSOR; - goto yy158; + goto yy190; } - goto yy146; + goto yy178; } } -yy155: +yy187: yych = *++YYCURSOR; if (yybm[0+yych] & 64) { - goto yy155; + goto yy187; } - if (yych <= '\r') goto yy146; - if (yych <= '"') goto yy160; - goto yy161; -yy157: + if (yych <= '\r') goto yy178; + if (yych <= '"') goto yy192; + goto yy193; +yy189: ++YYCURSOR; - goto yy153; -yy158: + goto yy185; +yy190: yych = *++YYCURSOR; if (yych <= '@') { if (yych <= ')') { - if (yych <= '(') goto yy146; + if (yych <= '(') goto yy178; yyt4 = YYCURSOR; - goto yy157; + goto yy189; } else { - if (yych <= '/') goto yy146; - if (yych <= '9') goto yy158; - goto yy146; + if (yych <= '/') goto yy178; + if (yych <= '9') goto yy190; + goto yy178; } } else { if (yych <= '_') { - if (yych <= 'Z') goto yy158; - if (yych <= '^') goto yy146; - goto yy158; + if (yych <= 'Z') goto yy190; + if (yych <= '^') goto yy178; + goto yy190; } else { - if (yych <= '`') goto yy146; - if (yych <= 'z') goto yy158; - goto yy146; + if (yych <= '`') goto yy178; + if (yych <= 'z') goto yy190; + goto yy178; } } -yy160: +yy192: yych = *++YYCURSOR; if (yych == ')') { yyt4 = YYCURSOR; - goto yy157; + goto yy189; } - goto yy146; -yy161: + goto yy178; +yy193: yych = *++YYCURSOR; if (yybm[0+yych] & 64) { - goto yy155; + goto yy187; } - if (yych <= '\r') goto yy146; - if (yych >= '#') goto yy161; + if (yych <= '\r') goto yy178; + if (yych >= '#') goto yy193; yych = *++YYCURSOR; if (yybm[0+yych] & 128) { - goto yy161; + goto yy193; } if (yych <= '\r') { - if (yych == '\n') goto yy146; - if (yych <= '\f') goto yy155; - goto yy146; + if (yych == '\n') goto yy178; + if (yych <= '\f') goto yy187; + goto yy178; } else { if (yych <= '"') { - if (yych <= '!') goto yy155; - goto yy160; + if (yych <= '!') goto yy187; + goto yy192; } else { - if (yych != ')') goto yy155; + if (yych != ')') goto yy187; yyt4 = YYCURSOR; } } yyaccept = 2; yych = *(YYMARKER = ++YYCURSOR); if (yybm[0+yych] & 64) { - goto yy155; + goto yy187; } - if (yych <= '\r') goto yy153; - if (yych <= '"') goto yy160; - goto yy161; + if (yych <= '\r') goto yy185; + if (yych <= '"') goto yy192; + goto yy193; } } diff --git a/src/sp_config_scanner.re b/src/sp_config_scanner.re index 063d332..b0ee5d5 100644 --- a/src/sp_config_scanner.re +++ b/src/sp_config_scanner.re @@ -4,6 +4,8 @@ #define cs_log_error(fmt, ...) sp_log_err("config", fmt, ##__VA_ARGS__) #define cs_log_info(fmt, ...) sp_log_msg("config", SP_LOG_INFO, fmt, ##__VA_ARGS__) +#define cs_log_warning(fmt, ...) sp_log_warn("config", fmt, ##__VA_ARGS__) + zend_string *sp_get_arg_string(sp_parsed_keyword *kw) { if (!kw || !kw->arg) { @@ -126,6 +128,12 @@ static int sy_apply_op(char op, int a, int b) { int res = sy_apply_op(op, a, b); \ sy_res_push(res); +#define TMPSTR(tmpstr, t2, t1) \ + char tmpstr[1024]; \ + size_t tmplen = MIN(t2-t1-2, 1023); \ + strncpy(tmpstr, t1+1, tmplen); \ + tmpstr[tmplen] = 0; + zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_keyword*)) { @@ -186,14 +194,22 @@ zend_result sp_config_scan(char *data, zend_result (*process_rule)(sp_parsed_key } "@condition" ws+ { goto yyc_cond; } "@end_condition" ws* ";" { cond_res[0] = 1; goto yyc_init; } - "@log" ws+ @t1 string? @t2 { - char tmpstr[1024]; - size_t tmplen = MIN(t2-t1-2, 1023); - strncpy(tmpstr, t1+1, tmplen); - tmpstr[tmplen] = 0; + ( "@log" | "@info" ) ws+ @t1 string @t2 { + TMPSTR(tmpstr, t2, t1); cs_log_info("[line %d]: %s", lineno, tmpstr); goto yyc_init; } + ( "@warn" | "@warning" ) ws+ @t1 string @t2 { + TMPSTR(tmpstr, t2, t1); + cs_log_warning("[line %d]: %s", lineno, tmpstr); + goto yyc_init; + } + ( "@err" | "@error" ) ws+ @t1 string @t2 { + TMPSTR(tmpstr, t2, t1); + cs_log_error("[line %d]: %s", lineno, tmpstr); + goto out; + } + ws+ { goto yyc_cond; } nl { lineno++; goto yyc_cond; } -- cgit v1.3 From acb737ef367f61ee0c0d219ea7272abb56e68e34 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Wed, 5 Jan 2022 20:17:09 +0100 Subject: skip old php check for testing --- Makefile | 2 +- src/snuffleupagus.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/snuffleupagus.c') diff --git a/Makefile b/Makefile index b8236fb..78aefe2 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ compile_debug: ## compile a debug build make -C src tests: release ## compile a release build and run the testsuite - TEST_PHP_ARGS='-q' REPORT_EXIT_STATUS=1 make -C src test + TEST_PHP_ARGS='-q' REPORT_EXIT_STATUS=1 SP_SKIP_OLD_PHP_CHECK=1 make -C src test coverage: ## compile snuffleugpaus, and run the testsuite with coverage cd src; phpize diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 3baad1b..1ccc412 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -367,7 +367,7 @@ static PHP_INI_MH(OnUpdateConfiguration) { (SPCFG(disabled_functions) && zend_hash_num_elements(SPCFG(disabled_functions))) || (SPCFG(disabled_functions_ret) && zend_hash_num_elements(SPCFG(disabled_functions_ret))); - if (SPCFG(show_old_php_warning)) { + if (SPCFG(show_old_php_warning) && getenv("SP_SKIP_OLD_PHP_CHECK") == NULL) { time_t ts = time(NULL); if (PHP_VERSION_ID < 70300 || PHP_VERSION_ID < 70400 && ts >= (time_t)1638745200L || -- cgit v1.3 From 4b5afd0148cef6c845a37aff68e1fbac8f5653d7 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Thu, 6 Jan 2022 21:22:50 +0100 Subject: prevent double checks and fixed segfault on return value access --- src/snuffleupagus.c | 3 ++- src/sp_disabled_functions.c | 16 ++++++++++------ src/sp_execute.c | 19 ++++++++++++------- 3 files changed, 24 insertions(+), 14 deletions(-) (limited to 'src/snuffleupagus.c') diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 1ccc412..53db721 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -334,7 +334,6 @@ static PHP_INI_MH(OnUpdateConfiguration) { } } - hook_disabled_functions(); hook_execute(); hook_cookies(); @@ -353,6 +352,8 @@ static PHP_INI_MH(OnUpdateConfiguration) { CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY; } + hook_disabled_functions(); + // If `zend_write_default` is not NULL it is already hooked. if ((zend_hash_str_find(SPCFG(disabled_functions_hooked), ZEND_STRL("echo")) || zend_hash_str_find(SPCFG(disabled_functions_ret_hooked), ZEND_STRL("echo"))) && diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c index 1d9c6c7..c0c642b 100644 --- a/src/sp_disabled_functions.c +++ b/src/sp_disabled_functions.c @@ -400,7 +400,6 @@ static void should_drop_on_ret(const zval* return_value, bool match_type = false, match_value = false; while (config) { - const zend_string* ret_value_str = NULL; sp_disabled_function const* const config_node = (sp_disabled_function*)(config->data); @@ -444,13 +443,18 @@ static void should_drop_on_ret(const zval* return_value, } } - ret_value_str = sp_zval_to_zend_string(return_value); + const zend_string* ret_value_str = NULL; + sp_php_type ret_type = SP_PHP_TYPE_NULL; + + if (return_value) { + ret_value_str = sp_zval_to_zend_string(return_value); + ret_type = Z_TYPE_P(return_value); + } match_type = (config_node->ret_type) && - (config_node->ret_type == Z_TYPE_P(return_value)); - match_value = (config_node->ret || config_node->r_ret) && - (true == sp_match_value(ret_value_str, config_node->ret, - config_node->r_ret)); + (config_node->ret_type == ret_type); + match_value = return_value && (config_node->ret || config_node->r_ret) && + (true == sp_match_value(ret_value_str, config_node->ret, config_node->r_ret)); if (true == match_type || true == match_value) { if (true == config_node->allow) { diff --git a/src/sp_execute.c b/src/sp_execute.c index 21a68dd..aadd145 100644 --- a/src/sp_execute.c +++ b/src/sp_execute.c @@ -161,14 +161,18 @@ static inline void sp_execute_handler(INTERNAL_FUNCTION_PARAMETERS, bool interna return; } - const sp_list_node *config_disabled_functions_reg = SPCFG(disabled_functions_reg).disabled_functions; + bool is_hooked = (zend_hash_str_find(SPG(disabled_functions_hook), VAR_AND_LEN(function_name)) || zend_hash_str_find(SPG(disabled_functions_hook), VAR_AND_LEN(function_name))); + if (is_hooked) { + sp_call_orig_execute(INTERNAL_FUNCTION_PARAM_PASSTHRU, internal); + return; + } // If we're at an internal function if (!execute_data->prev_execute_data || !execute_data->prev_execute_data->func || !ZEND_USER_CODE(execute_data->prev_execute_data->func->type) || !execute_data->prev_execute_data->opline) { - should_disable_ht(execute_data, function_name, NULL, NULL, config_disabled_functions_reg, SPCFG(disabled_functions)); + should_disable_ht(execute_data, function_name, NULL, NULL, SPCFG(disabled_functions_reg).disabled_functions, SPCFG(disabled_functions)); } else { // If we're at a userland function call switch (execute_data->prev_execute_data->opline->opcode) { case ZEND_DO_FCALL: @@ -176,7 +180,7 @@ static inline void sp_execute_handler(INTERNAL_FUNCTION_PARAMETERS, bool interna case ZEND_DO_ICALL: case ZEND_DO_UCALL: case ZEND_TICKS: - should_disable_ht(execute_data, function_name, NULL, NULL, config_disabled_functions_reg, SPCFG(disabled_functions)); + should_disable_ht(execute_data, function_name, NULL, NULL, SPCFG(disabled_functions_reg).disabled_functions, SPCFG(disabled_functions)); default: break; } @@ -188,23 +192,24 @@ static inline void sp_execute_handler(INTERNAL_FUNCTION_PARAMETERS, bool interna zval ret_val; if (EX(return_value) == NULL) { memset(&ret_val, 0, sizeof(ret_val)); - EX(return_value) = &ret_val; + return_value = EX(return_value) = &ret_val; } sp_call_orig_execute(INTERNAL_FUNCTION_PARAM_PASSTHRU, internal); - should_drop_on_ret_ht(EX(return_value), function_name, SPCFG(disabled_functions_reg_ret).disabled_functions, SPCFG(disabled_functions_ret), execute_data); + should_drop_on_ret_ht(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) { - EX(return_value) = NULL; + return_value = EX(return_value) = NULL; } } static void sp_execute_ex(zend_execute_data *execute_data) { - sp_execute_handler(execute_data, NULL, false); + sp_execute_handler(execute_data, execute_data ? EX(return_value) : NULL, false); } static void sp_zend_execute_internal(INTERNAL_FUNCTION_PARAMETERS) { -- cgit v1.3 From 22aeaa944bf5e0646b6ec06995a184d64a55ded0 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Wed, 12 Jan 2022 10:39:29 +0100 Subject: fixed compiler warning + better warning message --- src/snuffleupagus.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/snuffleupagus.c') diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 53db721..caa6ba3 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -370,11 +370,11 @@ static PHP_INI_MH(OnUpdateConfiguration) { if (SPCFG(show_old_php_warning) && getenv("SP_SKIP_OLD_PHP_CHECK") == NULL) { time_t ts = time(NULL); - 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."); + 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. - Note: This message can be switched off by setting 'sp.global.show_old_php_warning.disable();' in your rules file or by setting the environment variable SP_SKIP_OLD_PHP_CHECK=1."); } } return SUCCESS; -- cgit v1.3 From c38df1077a6c1dfbca1baca049214d053e2e7684 Mon Sep 17 00:00:00 2001 From: Ben Fuhrmannek Date: Sat, 5 Feb 2022 12:23:37 +0100 Subject: added config dump/export for use with other tools --- src/snuffleupagus.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 249 insertions(+), 11 deletions(-) (limited to 'src/snuffleupagus.c') diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index caa6ba3..e8f3664 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c @@ -4,6 +4,8 @@ #include #endif +#include "zend_smart_str.h" + #include "php_snuffleupagus.h" #ifndef ZEND_EXT_API @@ -38,19 +40,10 @@ static inline void sp_op_array_handler(zend_op_array *const op) { ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) -static PHP_INI_MH(StrictMode) { - TSRMLS_FETCH(); - - SPG(allow_broken_configuration) = false; - if (new_value && zend_string_equals_literal(new_value, "1")) { - SPG(allow_broken_configuration) = true; - } - return SUCCESS; -} - PHP_INI_BEGIN() PHP_INI_ENTRY("sp.configuration_file", "", PHP_INI_SYSTEM, OnUpdateConfiguration) -PHP_INI_ENTRY("sp.allow_broken_configuration", "0", PHP_INI_SYSTEM, StrictMode) +STD_PHP_INI_BOOLEAN("sp.allow_broken_configuration", "0", PHP_INI_SYSTEM, OnUpdateBool, allow_broken_configuration, zend_snuffleupagus_globals, snuffleupagus_globals) + PHP_INI_END() ZEND_DLEXPORT zend_extension zend_extension_entry = { @@ -266,6 +259,237 @@ PHP_MINFO_FUNCTION(snuffleupagus) { DISPLAY_INI_ENTRIES(); } +#define ADD_ASSOC_ZSTR(arr, key, zstr) if (zstr) { add_assoc_str(arr, key, zstr); } else { add_assoc_null(arr, key); } +#define ADD_ASSOC_REGEXP(arr, key, regexp) if (regexp && regexp->pattern) { add_assoc_str(arr, key, regexp->pattern); } else { add_assoc_null(arr, key); } + +static void add_df_to_arr(zval *arr, sp_disabled_function *df) { + zval arr_df; + array_init(&arr_df); + + ADD_ASSOC_ZSTR(&arr_df, SP_TOKEN_FILENAME, df->filename); + ADD_ASSOC_REGEXP(&arr_df, SP_TOKEN_FILENAME_REGEXP, df->r_filename); + ADD_ASSOC_ZSTR(&arr_df, SP_TOKEN_FUNCTION, df->function); + ADD_ASSOC_REGEXP(&arr_df, SP_TOKEN_FUNCTION_REGEXP, df->r_function); + if (df->functions_list && df->functions_list->data) { + zval arr_fl; + array_init(&arr_fl); + for (sp_list_node *p = df->functions_list; p; p = p->next) { add_next_index_str(&arr_fl, p->data); } + add_assoc_zval(&arr_df, "function_list", &arr_fl); + } else { + add_assoc_null(&arr_df, "function_list"); + } + ADD_ASSOC_ZSTR(&arr_df, SP_TOKEN_HASH, df->hash); + add_assoc_bool(&arr_df, SP_TOKEN_SIM, df->simulation); + if (df->param && df->param->value) { + add_assoc_string(&arr_df, SP_TOKEN_PARAM, df->param->value); + } else { + add_assoc_null(&arr_df, SP_TOKEN_PARAM); + } + ADD_ASSOC_REGEXP(&arr_df, SP_TOKEN_PARAM_REGEXP, df->r_param); + add_assoc_long(&arr_df, SP_TOKEN_PARAM_TYPE, df->param_type); + add_assoc_long(&arr_df, SP_TOKEN_VALUE_ARG_POS, df->pos); + add_assoc_long(&arr_df, SP_TOKEN_LINE_NUMBER, df->line); + ADD_ASSOC_ZSTR(&arr_df, SP_TOKEN_RET, df->ret); + ADD_ASSOC_REGEXP(&arr_df, SP_TOKEN_RET_REGEXP, df->r_ret); + ADD_ASSOC_ZSTR(&arr_df, SP_TOKEN_VALUE, df->value); + ADD_ASSOC_REGEXP(&arr_df, SP_TOKEN_VALUE_REGEXP, df->r_value); + ADD_ASSOC_ZSTR(&arr_df, SP_TOKEN_KEY, df->key); + ADD_ASSOC_REGEXP(&arr_df, SP_TOKEN_KEY_REGEXP, df->r_key); + ADD_ASSOC_ZSTR(&arr_df, SP_TOKEN_DUMP, df->dump); + ADD_ASSOC_ZSTR(&arr_df, SP_TOKEN_ALIAS, df->alias); + add_assoc_bool(&arr_df, "param_is_array", df->param_is_array); + add_assoc_bool(&arr_df, "var_is_array", df->var_is_array); + add_assoc_bool(&arr_df, "allow", df->allow); + // todo: properly traverse tree for .var() and .param() + // sp_tree *tr = df->var; + // for (; tr; tr = tr->next) { + // sp_log_debug("tree: %s", tr->value); + // } + + if (df->var && df->var->value) { + add_assoc_string(&arr_df, SP_TOKEN_LOCAL_VAR, df->var->value); + } else { + add_assoc_null(&arr_df, SP_TOKEN_LOCAL_VAR); + } + if (df->param && df->param->value) { + add_assoc_string(&arr_df, SP_TOKEN_PARAM, df->param->value); + } else { + add_assoc_null(&arr_df, SP_TOKEN_PARAM); + } + + if (df->cidr) { + char cidrstr[INET6_ADDRSTRLEN+5]; + if (!get_ip_str(cidrstr, sizeof(cidrstr), df->cidr)) { + add_assoc_null(&arr_df, SP_TOKEN_CIDR); + } else { + add_assoc_string(&arr_df, SP_TOKEN_CIDR, cidrstr); + } + } else { + add_assoc_null(&arr_df, SP_TOKEN_CIDR); + } + + add_next_index_zval(arr, &arr_df); +} + +static void dump_config() { + zval arr; + php_serialize_data_t var_hash; + smart_str buf = {0}; + + array_init(&arr); + add_assoc_string(&arr, "version", PHP_SNUFFLEUPAGUS_VERSION); + + add_assoc_bool(&arr, SP_TOKEN_UNSERIALIZE_HMAC "." SP_TOKEN_ENABLE, SPCFG(unserialize).enable); + add_assoc_bool(&arr, SP_TOKEN_UNSERIALIZE_HMAC "." SP_TOKEN_SIM, SPCFG(unserialize).simulation); + ADD_ASSOC_ZSTR(&arr, SP_TOKEN_UNSERIALIZE_HMAC "." SP_TOKEN_DUMP, SPCFG(unserialize).dump); + + add_assoc_bool(&arr, SP_TOKEN_HARDEN_RANDOM "." SP_TOKEN_ENABLE, SPCFG(random).enable); + + add_assoc_bool(&arr, "readonly_exec.enable", SPCFG(readonly_exec).enable); + add_assoc_bool(&arr, "readonly_exec.sim", SPCFG(readonly_exec).simulation); + ADD_ASSOC_ZSTR(&arr, SP_TOKEN_READONLY_EXEC "." SP_TOKEN_DUMP, SPCFG(readonly_exec).dump); + + add_assoc_bool(&arr, "global_strict.enable", SPCFG(global_strict).enable); + + add_assoc_bool(&arr, "upload_validation.enable", SPCFG(upload_validation).enable); + add_assoc_bool(&arr, "upload_validation.sim", SPCFG(upload_validation).simulation); + ADD_ASSOC_ZSTR(&arr, SP_TOKEN_UPLOAD_VALIDATION "." SP_TOKEN_UPLOAD_SCRIPT, SPCFG(upload_validation).script); + + // global + add_assoc_bool(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_ENCRYPTION_KEY, SPCFG(encryption_key) && ZSTR_LEN(SPCFG(encryption_key))); + ADD_ASSOC_ZSTR(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_ENV_VAR, SPCFG(cookies_env_var)); + add_assoc_long(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_LOG_MEDIA, SPCFG(log_media)); + add_assoc_long(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_MAX_EXECUTION_DEPTH, SPCFG(max_execution_depth)); + add_assoc_bool(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_SERVER_ENCODE, SPCFG(server_encode)); + add_assoc_bool(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_SERVER_STRIP, SPCFG(server_strip)); + add_assoc_bool(&arr, SP_TOKEN_GLOBAL "." SP_TOKEN_SHOW_OLD_PHP_WARNING, SPCFG(show_old_php_warning)); + + add_assoc_bool(&arr, SP_TOKEN_AUTO_COOKIE_SECURE, SPCFG(auto_cookie_secure).enable); + add_assoc_bool(&arr, SP_TOKEN_XXE_PROTECTION, SPCFG(xxe_protection).enable); + + add_assoc_bool(&arr, SP_TOKEN_EVAL_BLACKLIST "." SP_TOKEN_SIM, SPCFG(eval).simulation); + ADD_ASSOC_ZSTR(&arr, SP_TOKEN_EVAL_BLACKLIST "." SP_TOKEN_DUMP, SPCFG(eval).dump); +#define ADD_ASSOC_SPLIST(arr, key, splist) \ + if (splist) { \ + zval arr_sp; \ + array_init(&arr_sp); \ + for (sp_list_node *p = splist; p; p = p->next) { add_next_index_str(&arr_sp, p->data); } \ + add_assoc_zval(arr, key, &arr_sp); \ + } else { add_assoc_null(arr, key); } + + ADD_ASSOC_SPLIST(&arr, SP_TOKEN_EVAL_BLACKLIST "." SP_TOKEN_LIST, SPCFG(eval).blacklist); + ADD_ASSOC_SPLIST(&arr, SP_TOKEN_EVAL_WHITELIST "." SP_TOKEN_LIST, SPCFG(eval).whitelist) + + add_assoc_bool(&arr, SP_TOKEN_SESSION_ENCRYPTION "." SP_TOKEN_ENCRYPT, SPCFG(session).encrypt); + add_assoc_bool(&arr, SP_TOKEN_SESSION_ENCRYPTION "." SP_TOKEN_SIM, SPCFG(session).simulation); + + add_assoc_long(&arr, SP_TOKEN_SESSION_ENCRYPTION "." SP_TOKEN_SID_MIN_LENGTH, SPCFG(session).sid_min_length); + add_assoc_long(&arr, SP_TOKEN_SESSION_ENCRYPTION "." SP_TOKEN_SID_MAX_LENGTH, SPCFG(session).sid_max_length); + add_assoc_bool(&arr, SP_TOKEN_SLOPPY_COMPARISON "." SP_TOKEN_ENABLE, SPCFG(sloppy).enable); + + ADD_ASSOC_SPLIST(&arr, SP_TOKEN_ALLOW_WRAPPERS, SPCFG(wrapper).whitelist); + + add_assoc_bool(&arr, SP_TOKEN_INI_PROTECTION "." SP_TOKEN_ENABLE, SPCFG(ini).enable); + add_assoc_bool(&arr, SP_TOKEN_INI_PROTECTION "." SP_TOKEN_SIM, SPCFG(ini).simulation); + add_assoc_bool(&arr, SP_TOKEN_INI_PROTECTION "." "policy_ro", SPCFG(ini).policy_readonly); + add_assoc_bool(&arr, SP_TOKEN_INI_PROTECTION "." "policy_silent_ro", SPCFG(ini).policy_silent_ro); + add_assoc_bool(&arr, SP_TOKEN_INI_PROTECTION "." "policy_silent_fail", SPCFG(ini).policy_silent_fail); + add_assoc_bool(&arr, SP_TOKEN_INI_PROTECTION "." "policy_drop", SPCFG(ini).policy_drop); + + if (SPCFG(ini).entries && zend_hash_num_elements(SPCFG(ini).entries) > 0) { + zval arr_ini; + array_init(&arr_ini); + + sp_ini_entry *sp_entry; + ZEND_HASH_FOREACH_PTR(SPCFG(ini).entries, sp_entry) + zval arr_ini_entry; + array_init(&arr_ini_entry); + add_assoc_bool(&arr_ini_entry, SP_TOKEN_SIM, sp_entry->simulation); + ADD_ASSOC_ZSTR(&arr_ini_entry, SP_TOKEN_KEY, sp_entry->key); + ADD_ASSOC_ZSTR(&arr_ini_entry, "msg", sp_entry->msg); + ADD_ASSOC_ZSTR(&arr_ini_entry, "set", sp_entry->set); + ADD_ASSOC_ZSTR(&arr_ini_entry, "min", sp_entry->min); + ADD_ASSOC_ZSTR(&arr_ini_entry, "max", sp_entry->max); + add_assoc_long(&arr_ini_entry, "access", sp_entry->access); + add_assoc_bool(&arr_ini_entry, "drop", sp_entry->drop); + add_assoc_bool(&arr_ini_entry, "allow_null", sp_entry->allow_null); + ADD_ASSOC_REGEXP(&arr_ini_entry, "regexp", sp_entry->regexp); + add_next_index_zval(&arr_ini, &arr_ini_entry); + ZEND_HASH_FOREACH_END(); + add_assoc_zval(&arr, SP_TOKEN_INI, &arr_ini); + } else { + add_assoc_null(&arr, SP_TOKEN_INI); + } + + if (SPCFG(cookie).cookies && SPCFG(cookie).cookies->data) { + zval arr_cookies; + array_init(&arr_cookies); + + sp_cookie *cookie; + sp_list_node *p = SPCFG(cookie).cookies; + for (; p; p = p->next) { + zval arr_cookie; + array_init(&arr_cookie); + cookie = (sp_cookie*)p->data; + + add_assoc_long(&arr_cookie, SP_TOKEN_SAMESITE, cookie->samesite); + add_assoc_bool(&arr_cookie, SP_TOKEN_ENCRYPT, cookie->encrypt); + ADD_ASSOC_ZSTR(&arr_cookie, SP_TOKEN_NAME, cookie->name); + ADD_ASSOC_REGEXP(&arr_cookie, SP_TOKEN_NAME_REGEXP, cookie->name_r); + add_assoc_bool(&arr_cookie, SP_TOKEN_SIM, cookie->simulation); + + add_next_index_zval(&arr_cookies, &arr_cookie); + } + + add_assoc_zval(&arr, SP_TOKEN_COOKIE_ENCRYPTION, &arr_cookies); + } else { + add_assoc_null(&arr, SP_TOKEN_COOKIE_ENCRYPTION); + } + + // disabled_functions + zval arr_dfs; + array_init(&arr_dfs); + size_t num_df = 0; + sp_list_node *dflist, *dfp; + ZEND_HASH_FOREACH_PTR(SPCFG(disabled_functions), dflist) + for (dfp = dflist; dfp; dfp = dfp->next) { + add_df_to_arr(&arr_dfs, dfp->data); + num_df++; + } + ZEND_HASH_FOREACH_END(); + ZEND_HASH_FOREACH_PTR(SPCFG(disabled_functions_ret), dflist) + for (dfp = dflist; dfp; dfp = dfp->next) { + add_df_to_arr(&arr_dfs, dfp->data); + num_df++; + } + ZEND_HASH_FOREACH_END(); + for (dfp = SPCFG(disabled_functions_reg).disabled_functions; dfp; dfp = dfp->next) { + add_df_to_arr(&arr_dfs, dfp->data); + num_df++; + } + for (dfp = SPCFG(disabled_functions_reg_ret).disabled_functions; dfp; dfp = dfp->next) { + add_df_to_arr(&arr_dfs, dfp->data); + num_df++; + } + + if (num_df) { + add_assoc_zval(&arr, SP_TOKEN_DISABLE_FUNC, &arr_dfs); + } else { + add_assoc_null(&arr, SP_TOKEN_DISABLE_FUNC); + } + + // serialize and print array + PHP_VAR_SERIALIZE_INIT(var_hash); + php_var_serialize(&buf, &arr, &var_hash); + PHP_VAR_SERIALIZE_DESTROY(var_hash); + + printf("%s", ZSTR_VAL(buf.s)); + sp_log_debug("--"); + + smart_str_free(&buf); + +} + static PHP_INI_MH(OnUpdateConfiguration) { sp_log_debug("(OnUpdateConfiguration)"); @@ -304,6 +528,20 @@ static PHP_INI_MH(OnUpdateConfiguration) { SPG(is_config_valid) = SP_CONFIG_VALID; + // dump config + sp_log_debug("module name? %s", sapi_module.name); + if (getenv("SP_DUMP_CONFIG")) { + sp_log_debug("env? %s", getenv("SP_DUMP_CONFIG")); + } + + if (strcmp(sapi_module.name, "cli") == 0 && getenv("SP_DUMP_CONFIG")) { + dump_config(); + return SUCCESS; + } + + + // start hooks + if (SPCFG(sloppy).enable) { hook_sloppy(); } -- cgit v1.3