diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/snuffleupagus.c | 53 | ||||
| -rw-r--r-- | src/sp_config.c | 36 | ||||
| -rw-r--r-- | src/sp_config.h | 58 | ||||
| -rw-r--r-- | src/sp_config_keywords.c | 199 | ||||
| -rw-r--r-- | src/sp_config_utils.c | 15 | ||||
| -rw-r--r-- | src/sp_config_utils.h | 2 | ||||
| -rw-r--r-- | src/sp_cookie_encryption.c | 16 | ||||
| -rw-r--r-- | src/sp_crypt.c | 29 | ||||
| -rw-r--r-- | src/sp_crypt.h | 4 | ||||
| -rw-r--r-- | src/sp_disabled_functions.c | 304 | ||||
| -rw-r--r-- | src/sp_disabled_functions.h | 9 | ||||
| -rw-r--r-- | src/sp_execute.c | 142 | ||||
| -rw-r--r-- | src/sp_execute.h | 2 | ||||
| -rw-r--r-- | src/sp_pcre_compat.h | 2 | ||||
| -rw-r--r-- | src/sp_session.c | 4 | ||||
| -rw-r--r-- | src/sp_sloppy.c | 9 | ||||
| -rw-r--r-- | src/sp_unserialize.c | 12 | ||||
| -rw-r--r-- | src/sp_upload_validation.c | 26 | ||||
| -rw-r--r-- | src/sp_utils.c | 147 | ||||
| -rw-r--r-- | src/sp_utils.h | 16 | ||||
| -rw-r--r-- | src/sp_var_value.c | 7 |
21 files changed, 632 insertions, 460 deletions
diff --git a/src/snuffleupagus.c b/src/snuffleupagus.c index 08b2083..edca185 100644 --- a/src/snuffleupagus.c +++ b/src/snuffleupagus.c | |||
| @@ -39,6 +39,14 @@ PHP_INI_ENTRY("sp.configuration_file", "", PHP_INI_SYSTEM, | |||
| 39 | OnUpdateConfiguration) | 39 | OnUpdateConfiguration) |
| 40 | PHP_INI_END() | 40 | PHP_INI_END() |
| 41 | 41 | ||
| 42 | void free_disabled_functions_hashtable(HashTable *ht) { | ||
| 43 | void* ptr = NULL; | ||
| 44 | ZEND_HASH_FOREACH_PTR(ht, ptr) { | ||
| 45 | sp_list_free(ptr); | ||
| 46 | } | ||
| 47 | ZEND_HASH_FOREACH_END(); | ||
| 48 | } | ||
| 49 | |||
| 42 | ZEND_DLEXPORT zend_extension zend_extension_entry = { | 50 | ZEND_DLEXPORT zend_extension zend_extension_entry = { |
| 43 | PHP_SNUFFLEUPAGUS_EXTNAME, | 51 | PHP_SNUFFLEUPAGUS_EXTNAME, |
| 44 | PHP_SNUFFLEUPAGUS_VERSION, | 52 | PHP_SNUFFLEUPAGUS_VERSION, |
| @@ -69,6 +77,10 @@ PHP_GINIT_FUNCTION(snuffleupagus) { | |||
| 69 | SP_INIT_HT(snuffleupagus_globals->disabled_functions_hook); | 77 | SP_INIT_HT(snuffleupagus_globals->disabled_functions_hook); |
| 70 | SP_INIT_HT(snuffleupagus_globals->sp_internal_functions_hook); | 78 | SP_INIT_HT(snuffleupagus_globals->sp_internal_functions_hook); |
| 71 | SP_INIT_HT(snuffleupagus_globals->sp_eval_blacklist_functions_hook); | 79 | SP_INIT_HT(snuffleupagus_globals->sp_eval_blacklist_functions_hook); |
| 80 | SP_INIT_HT(snuffleupagus_globals->config.config_disabled_functions); | ||
| 81 | SP_INIT_HT(snuffleupagus_globals->config.config_disabled_functions_hooked); | ||
| 82 | SP_INIT_HT(snuffleupagus_globals->config.config_disabled_functions_ret); | ||
| 83 | SP_INIT_HT(snuffleupagus_globals->config.config_disabled_functions_ret_hooked); | ||
| 72 | 84 | ||
| 73 | SP_INIT(snuffleupagus_globals->config.config_unserialize); | 85 | SP_INIT(snuffleupagus_globals->config.config_unserialize); |
| 74 | SP_INIT(snuffleupagus_globals->config.config_random); | 86 | SP_INIT(snuffleupagus_globals->config.config_random); |
| @@ -79,20 +91,15 @@ PHP_GINIT_FUNCTION(snuffleupagus) { | |||
| 79 | SP_INIT(snuffleupagus_globals->config.config_snuffleupagus); | 91 | SP_INIT(snuffleupagus_globals->config.config_snuffleupagus); |
| 80 | SP_INIT(snuffleupagus_globals->config.config_disable_xxe); | 92 | SP_INIT(snuffleupagus_globals->config.config_disable_xxe); |
| 81 | SP_INIT(snuffleupagus_globals->config.config_upload_validation); | 93 | SP_INIT(snuffleupagus_globals->config.config_upload_validation); |
| 82 | SP_INIT(snuffleupagus_globals->config.config_disabled_functions); | 94 | SP_INIT(snuffleupagus_globals->config.config_disabled_functions_reg); |
| 83 | SP_INIT(snuffleupagus_globals->config.config_disabled_functions_ret); | 95 | SP_INIT(snuffleupagus_globals->config.config_disabled_functions_reg_ret); |
| 84 | SP_INIT(snuffleupagus_globals->config.config_cookie); | 96 | SP_INIT(snuffleupagus_globals->config.config_cookie); |
| 85 | SP_INIT(snuffleupagus_globals->config.config_session); | 97 | SP_INIT(snuffleupagus_globals->config.config_session); |
| 86 | SP_INIT(snuffleupagus_globals->config.config_disabled_constructs); | ||
| 87 | SP_INIT(snuffleupagus_globals->config.config_eval); | 98 | SP_INIT(snuffleupagus_globals->config.config_eval); |
| 88 | 99 | ||
| 89 | snuffleupagus_globals->config.config_disabled_constructs->construct_include = | 100 | snuffleupagus_globals->config.config_disabled_functions_reg |
| 90 | NULL; | 101 | ->disabled_functions = NULL; |
| 91 | snuffleupagus_globals->config.config_disabled_constructs->construct_eval = | 102 | snuffleupagus_globals->config.config_disabled_functions_reg_ret |
| 92 | NULL; | ||
| 93 | snuffleupagus_globals->config.config_disabled_functions->disabled_functions = | ||
| 94 | NULL; | ||
| 95 | snuffleupagus_globals->config.config_disabled_functions_ret | ||
| 96 | ->disabled_functions = NULL; | 103 | ->disabled_functions = NULL; |
| 97 | snuffleupagus_globals->config.config_cookie->cookies = NULL; | 104 | snuffleupagus_globals->config.config_cookie->cookies = NULL; |
| 98 | snuffleupagus_globals->config.config_eval->blacklist = NULL; | 105 | snuffleupagus_globals->config.config_eval->blacklist = NULL; |
| @@ -109,12 +116,21 @@ PHP_MINIT_FUNCTION(snuffleupagus) { | |||
| 109 | } | 116 | } |
| 110 | 117 | ||
| 111 | PHP_MSHUTDOWN_FUNCTION(snuffleupagus) { | 118 | PHP_MSHUTDOWN_FUNCTION(snuffleupagus) { |
| 119 | free_disabled_functions_hashtable(SNUFFLEUPAGUS_G(config).config_disabled_functions); | ||
| 120 | free_disabled_functions_hashtable(SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked); | ||
| 121 | free_disabled_functions_hashtable(SNUFFLEUPAGUS_G(config).config_disabled_functions_ret); | ||
| 122 | free_disabled_functions_hashtable(SNUFFLEUPAGUS_G(config).config_disabled_functions_ret_hooked); | ||
| 123 | |||
| 112 | #define FREE_HT(F) \ | 124 | #define FREE_HT(F) \ |
| 113 | zend_hash_destroy(SNUFFLEUPAGUS_G(F)); \ | 125 | zend_hash_destroy(SNUFFLEUPAGUS_G(F)); \ |
| 114 | pefree(SNUFFLEUPAGUS_G(F), 1); | 126 | pefree(SNUFFLEUPAGUS_G(F), 1); |
| 115 | 127 | ||
| 116 | FREE_HT(disabled_functions_hook); | 128 | FREE_HT(disabled_functions_hook); |
| 117 | FREE_HT(sp_eval_blacklist_functions_hook); | 129 | FREE_HT(sp_eval_blacklist_functions_hook); |
| 130 | FREE_HT(config.config_disabled_functions); | ||
| 131 | FREE_HT(config.config_disabled_functions_hooked); | ||
| 132 | FREE_HT(config.config_disabled_functions_ret); | ||
| 133 | FREE_HT(config.config_disabled_functions_ret_hooked); | ||
| 118 | 134 | ||
| 119 | #undef FREE_HT | 135 | #undef FREE_HT |
| 120 | 136 | ||
| @@ -135,19 +151,16 @@ PHP_MSHUTDOWN_FUNCTION(snuffleupagus) { | |||
| 135 | sp_list_free(_n); \ | 151 | sp_list_free(_n); \ |
| 136 | } while (0) | 152 | } while (0) |
| 137 | 153 | ||
| 138 | FREE_LST_DISABLE(config.config_disabled_functions->disabled_functions); | 154 | FREE_LST_DISABLE(config.config_disabled_functions_reg->disabled_functions); |
| 139 | FREE_LST_DISABLE(config.config_disabled_functions_ret->disabled_functions); | 155 | FREE_LST_DISABLE(config.config_disabled_functions_reg_ret->disabled_functions); |
| 140 | FREE_LST_DISABLE(config.config_disabled_constructs->construct_include); | ||
| 141 | FREE_LST_DISABLE(config.config_disabled_constructs->construct_eval); | ||
| 142 | sp_list_free(SNUFFLEUPAGUS_G(config).config_cookie->cookies); | 156 | sp_list_free(SNUFFLEUPAGUS_G(config).config_cookie->cookies); |
| 143 | sp_list_free(SNUFFLEUPAGUS_G(config).config_eval->blacklist); | 157 | sp_list_free(SNUFFLEUPAGUS_G(config).config_eval->blacklist); |
| 144 | sp_list_free(SNUFFLEUPAGUS_G(config).config_eval->whitelist); | 158 | sp_list_free(SNUFFLEUPAGUS_G(config).config_eval->whitelist); |
| 145 | 159 | ||
| 146 | #undef FREE_LST_DISABLE | 160 | #undef FREE_LST_DISABLE |
| 147 | 161 | ||
| 148 | pefree(SNUFFLEUPAGUS_G(config.config_disabled_functions), 1); | 162 | pefree(SNUFFLEUPAGUS_G(config.config_disabled_functions_reg), 1); |
| 149 | pefree(SNUFFLEUPAGUS_G(config.config_disabled_functions_ret), 1); | 163 | pefree(SNUFFLEUPAGUS_G(config.config_disabled_functions_reg_ret), 1); |
| 150 | pefree(SNUFFLEUPAGUS_G(config.config_disabled_constructs), 1); | ||
| 151 | pefree(SNUFFLEUPAGUS_G(config.config_cookie), 1); | 164 | pefree(SNUFFLEUPAGUS_G(config.config_cookie), 1); |
| 152 | 165 | ||
| 153 | UNREGISTER_INI_ENTRIES(); | 166 | UNREGISTER_INI_ENTRIES(); |
| @@ -249,6 +262,12 @@ static PHP_INI_MH(OnUpdateConfiguration) { | |||
| 249 | CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY; | 262 | CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY; |
| 250 | } | 263 | } |
| 251 | 264 | ||
| 265 | SNUFFLEUPAGUS_G(config).hook_execute = | ||
| 266 | SNUFFLEUPAGUS_G(config).config_disabled_functions_reg->disabled_functions || | ||
| 267 | SNUFFLEUPAGUS_G(config).config_disabled_functions_reg_ret->disabled_functions || | ||
| 268 | zend_hash_num_elements(SNUFFLEUPAGUS_G(config).config_disabled_functions) || | ||
| 269 | zend_hash_num_elements(SNUFFLEUPAGUS_G(config).config_disabled_functions_ret); | ||
| 270 | |||
| 252 | return SUCCESS; | 271 | return SUCCESS; |
| 253 | } | 272 | } |
| 254 | 273 | ||
diff --git a/src/sp_config.c b/src/sp_config.c index eb5b324..c652984 100644 --- a/src/sp_config.c +++ b/src/sp_config.c | |||
| @@ -63,29 +63,29 @@ int parse_empty(char *restrict line, char *restrict keyword, void *retval) { | |||
| 63 | 63 | ||
| 64 | int parse_php_type(char *restrict line, char *restrict keyword, void *retval) { | 64 | int parse_php_type(char *restrict line, char *restrict keyword, void *retval) { |
| 65 | size_t consumed = 0; | 65 | size_t consumed = 0; |
| 66 | char *value = get_param(&consumed, line, SP_TYPE_STR, keyword); | 66 | zend_string *value = get_param(&consumed, line, SP_TYPE_STR, keyword); |
| 67 | if (value) { | 67 | if (value) { |
| 68 | if (0 == strcasecmp("undef", value)) { | 68 | if (zend_string_equals_literal_ci(value, "undef")) { |
| 69 | *(sp_php_type *)retval = SP_PHP_TYPE_UNDEF; | 69 | *(sp_php_type *)retval = SP_PHP_TYPE_UNDEF; |
| 70 | } else if (0 == strcasecmp("null", value)) { | 70 | } else if (zend_string_equals_literal_ci(value, "null")) { |
| 71 | *(sp_php_type *)retval = SP_PHP_TYPE_NULL; | 71 | *(sp_php_type *)retval = SP_PHP_TYPE_NULL; |
| 72 | } else if (0 == strcasecmp("true", value)) { | 72 | } else if (zend_string_equals_literal_ci(value, "true")) { |
| 73 | *(sp_php_type *)retval = SP_PHP_TYPE_TRUE; | 73 | *(sp_php_type *)retval = SP_PHP_TYPE_TRUE; |
| 74 | } else if (0 == strcasecmp("false", value)) { | 74 | } else if (zend_string_equals_literal_ci(value, "false")) { |
| 75 | *(sp_php_type *)retval = SP_PHP_TYPE_FALSE; | 75 | *(sp_php_type *)retval = SP_PHP_TYPE_FALSE; |
| 76 | } else if (0 == strcasecmp("long", value)) { | 76 | } else if (zend_string_equals_literal_ci(value, "long")) { |
| 77 | *(sp_php_type *)retval = SP_PHP_TYPE_LONG; | 77 | *(sp_php_type *)retval = SP_PHP_TYPE_LONG; |
| 78 | } else if (0 == strcasecmp("double", value)) { | 78 | } else if (zend_string_equals_literal_ci(value, "double")) { |
| 79 | *(sp_php_type *)retval = SP_PHP_TYPE_DOUBLE; | 79 | *(sp_php_type *)retval = SP_PHP_TYPE_DOUBLE; |
| 80 | } else if (0 == strcasecmp("string", value)) { | 80 | } else if (zend_string_equals_literal_ci(value, "string")) { |
| 81 | *(sp_php_type *)retval = SP_PHP_TYPE_STRING; | 81 | *(sp_php_type *)retval = SP_PHP_TYPE_STRING; |
| 82 | } else if (0 == strcasecmp("array", value)) { | 82 | } else if (zend_string_equals_literal_ci(value, "array")) { |
| 83 | *(sp_php_type *)retval = SP_PHP_TYPE_ARRAY; | 83 | *(sp_php_type *)retval = SP_PHP_TYPE_ARRAY; |
| 84 | } else if (0 == strcasecmp("object", value)) { | 84 | } else if (zend_string_equals_literal_ci(value, "object")) { |
| 85 | *(sp_php_type *)retval = SP_PHP_TYPE_OBJECT; | 85 | *(sp_php_type *)retval = SP_PHP_TYPE_OBJECT; |
| 86 | } else if (0 == strcasecmp("resource", value)) { | 86 | } else if (zend_string_equals_literal_ci(value, "resource")) { |
| 87 | *(sp_php_type *)retval = SP_PHP_TYPE_RESOURCE; | 87 | *(sp_php_type *)retval = SP_PHP_TYPE_RESOURCE; |
| 88 | } else if (0 == strcasecmp("reference", value)) { | 88 | } else if (zend_string_equals_literal_ci(value, "reference")) { |
| 89 | *(sp_php_type *)retval = SP_PHP_TYPE_REFERENCE; | 89 | *(sp_php_type *)retval = SP_PHP_TYPE_REFERENCE; |
| 90 | } else { | 90 | } else { |
| 91 | pefree(value, 1); | 91 | pefree(value, 1); |
| @@ -105,12 +105,12 @@ int parse_php_type(char *restrict line, char *restrict keyword, void *retval) { | |||
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | int parse_str(char *restrict line, char *restrict keyword, void *retval) { | 107 | int parse_str(char *restrict line, char *restrict keyword, void *retval) { |
| 108 | char *value = NULL; | 108 | zend_string *value = NULL; |
| 109 | 109 | ||
| 110 | size_t consumed = 0; | 110 | size_t consumed = 0; |
| 111 | value = get_param(&consumed, line, SP_TYPE_STR, keyword); | 111 | value = get_param(&consumed, line, SP_TYPE_STR, keyword); |
| 112 | if (value) { | 112 | if (value) { |
| 113 | *(char **)retval = value; | 113 | *(zend_string **)retval = value; |
| 114 | return consumed; | 114 | return consumed; |
| 115 | } | 115 | } |
| 116 | return -1; | 116 | return -1; |
| @@ -118,11 +118,11 @@ int parse_str(char *restrict line, char *restrict keyword, void *retval) { | |||
| 118 | 118 | ||
| 119 | int parse_cidr(char *restrict line, char *restrict keyword, void *retval) { | 119 | int parse_cidr(char *restrict line, char *restrict keyword, void *retval) { |
| 120 | size_t consumed = 0; | 120 | size_t consumed = 0; |
| 121 | char *value = get_param(&consumed, line, SP_TYPE_STR, keyword); | 121 | zend_string *value = get_param(&consumed, line, SP_TYPE_STR, keyword); |
| 122 | sp_cidr *cidr = pecalloc(sizeof(sp_cidr), 1, 1); | 122 | sp_cidr *cidr = pecalloc(sizeof(sp_cidr), 1, 1); |
| 123 | 123 | ||
| 124 | if (value) { | 124 | if (value) { |
| 125 | if (-1 == get_ip_and_cidr(value, cidr)) { | 125 | if (-1 == get_ip_and_cidr(ZSTR_VAL(value), cidr)) { |
| 126 | return -1; | 126 | return -1; |
| 127 | } | 127 | } |
| 128 | *(sp_cidr **)retval = cidr; | 128 | *(sp_cidr **)retval = cidr; |
| @@ -139,10 +139,10 @@ int parse_regexp(char *restrict line, char *restrict keyword, void *retval) { | |||
| 139 | * (http://www.pcre.org/original/doc/html/pcre_study.html) | 139 | * (http://www.pcre.org/original/doc/html/pcre_study.html) |
| 140 | * maybe not: http://sljit.sourceforge.net/pcre.html*/ | 140 | * maybe not: http://sljit.sourceforge.net/pcre.html*/ |
| 141 | size_t consumed = 0; | 141 | size_t consumed = 0; |
| 142 | char *value = get_param(&consumed, line, SP_TYPE_STR, keyword); | 142 | zend_string *value = get_param(&consumed, line, SP_TYPE_STR, keyword); |
| 143 | 143 | ||
| 144 | if (value) { | 144 | if (value) { |
| 145 | sp_pcre *compiled_re = sp_pcre_compile(value); | 145 | sp_pcre *compiled_re = sp_pcre_compile(ZSTR_VAL(value)); |
| 146 | if (NULL != compiled_re) { | 146 | if (NULL != compiled_re) { |
| 147 | *(sp_pcre **)retval = compiled_re; | 147 | *(sp_pcre **)retval = compiled_re; |
| 148 | return consumed; | 148 | return consumed; |
diff --git a/src/sp_config.h b/src/sp_config.h index 979feda..cfc3c8f 100644 --- a/src/sp_config.h +++ b/src/sp_config.h | |||
| @@ -38,15 +38,15 @@ typedef struct { | |||
| 38 | } sp_cidr; | 38 | } sp_cidr; |
| 39 | 39 | ||
| 40 | typedef struct { | 40 | typedef struct { |
| 41 | char *encryption_key; | 41 | zend_string *encryption_key; |
| 42 | char *cookies_env_var; | 42 | zend_string *cookies_env_var; |
| 43 | } sp_config_global; | 43 | } sp_config_global; |
| 44 | 44 | ||
| 45 | typedef struct { | 45 | typedef struct { |
| 46 | bool enable; | 46 | bool enable; |
| 47 | bool simulation; | 47 | bool simulation; |
| 48 | char *dump; | 48 | zend_string *dump; |
| 49 | char *textual_representation; | 49 | zend_string *textual_representation; |
| 50 | } sp_config_readonly_exec; | 50 | } sp_config_readonly_exec; |
| 51 | 51 | ||
| 52 | typedef struct { bool enable; } sp_config_global_strict; | 52 | typedef struct { bool enable; } sp_config_global_strict; |
| @@ -62,7 +62,7 @@ typedef struct { bool enable; } sp_config_disable_xxe; | |||
| 62 | typedef struct { | 62 | typedef struct { |
| 63 | enum samesite_type { strict = 1, lax = 2 } samesite; | 63 | enum samesite_type { strict = 1, lax = 2 } samesite; |
| 64 | bool encrypt; | 64 | bool encrypt; |
| 65 | char *name; | 65 | zend_string *name; |
| 66 | sp_pcre *name_r; | 66 | sp_pcre *name_r; |
| 67 | bool simulation; | 67 | bool simulation; |
| 68 | } sp_cookie; | 68 | } sp_cookie; |
| @@ -75,21 +75,21 @@ typedef struct { | |||
| 75 | typedef struct { | 75 | typedef struct { |
| 76 | bool enable; | 76 | bool enable; |
| 77 | bool simulation; | 77 | bool simulation; |
| 78 | char *dump; | 78 | zend_string *dump; |
| 79 | char *textual_representation; | 79 | zend_string *textual_representation; |
| 80 | } sp_config_unserialize; | 80 | } sp_config_unserialize; |
| 81 | 81 | ||
| 82 | typedef struct { | 82 | typedef struct { |
| 83 | char *textual_representation; | 83 | zend_string *textual_representation; |
| 84 | 84 | ||
| 85 | char *filename; | 85 | zend_string *filename; |
| 86 | sp_pcre *r_filename; | 86 | sp_pcre *r_filename; |
| 87 | 87 | ||
| 88 | char *function; | 88 | zend_string *function; |
| 89 | sp_pcre *r_function; | 89 | sp_pcre *r_function; |
| 90 | sp_list_node *functions_list; | 90 | sp_list_node *functions_list; |
| 91 | 91 | ||
| 92 | char *hash; | 92 | zend_string *hash; |
| 93 | int simulation; | 93 | int simulation; |
| 94 | 94 | ||
| 95 | sp_tree *param; | 95 | sp_tree *param; |
| @@ -98,18 +98,18 @@ typedef struct { | |||
| 98 | int pos; | 98 | int pos; |
| 99 | unsigned int line; | 99 | unsigned int line; |
| 100 | 100 | ||
| 101 | char *ret; | ||
| 102 | sp_pcre *r_ret; | 101 | sp_pcre *r_ret; |
| 102 | zend_string *ret; | ||
| 103 | sp_php_type ret_type; | 103 | sp_php_type ret_type; |
| 104 | 104 | ||
| 105 | sp_pcre *value_r; | 105 | sp_pcre *r_value; |
| 106 | char *value; | 106 | zend_string *value; |
| 107 | 107 | ||
| 108 | sp_pcre *r_key; | 108 | sp_pcre *r_key; |
| 109 | char *key; | 109 | zend_string *key; |
| 110 | 110 | ||
| 111 | char *dump; | 111 | zend_string *dump; |
| 112 | char *alias; | 112 | zend_string *alias; |
| 113 | bool param_is_array; | 113 | bool param_is_array; |
| 114 | bool var_is_array; | 114 | bool var_is_array; |
| 115 | sp_list_node *param_array_keys; | 115 | sp_list_node *param_array_keys; |
| @@ -126,8 +126,8 @@ typedef struct { | |||
| 126 | sp_list_node *blacklist; | 126 | sp_list_node *blacklist; |
| 127 | sp_list_node *whitelist; | 127 | sp_list_node *whitelist; |
| 128 | bool simulation; | 128 | bool simulation; |
| 129 | char *dump; | 129 | zend_string *dump; |
| 130 | char *textual_representation; | 130 | zend_string *textual_representation; |
| 131 | } sp_config_eval; | 131 | } sp_config_eval; |
| 132 | 132 | ||
| 133 | typedef struct { | 133 | typedef struct { |
| @@ -139,14 +139,7 @@ typedef struct { | |||
| 139 | } sp_config_cookie; | 139 | } sp_config_cookie; |
| 140 | 140 | ||
| 141 | typedef struct { | 141 | typedef struct { |
| 142 | sp_list_node | 142 | zend_string *script; |
| 143 | *construct_include; // list of rules for `(include|require)_(once)?` | ||
| 144 | sp_list_node *construct_eval; | ||
| 145 | sp_list_node *construct_echo; | ||
| 146 | } sp_config_disabled_constructs; | ||
| 147 | |||
| 148 | typedef struct { | ||
| 149 | char *script; | ||
| 150 | bool simulation; | 143 | bool simulation; |
| 151 | bool enable; | 144 | bool enable; |
| 152 | } sp_config_upload_validation; | 145 | } sp_config_upload_validation; |
| @@ -155,8 +148,6 @@ typedef struct { | |||
| 155 | sp_config_random *config_random; | 148 | sp_config_random *config_random; |
| 156 | sp_config_sloppy *config_sloppy; | 149 | sp_config_sloppy *config_sloppy; |
| 157 | sp_config_unserialize *config_unserialize; | 150 | sp_config_unserialize *config_unserialize; |
| 158 | sp_config_disabled_functions *config_disabled_functions; | ||
| 159 | sp_config_disabled_functions *config_disabled_functions_ret; | ||
| 160 | sp_config_readonly_exec *config_readonly_exec; | 151 | sp_config_readonly_exec *config_readonly_exec; |
| 161 | sp_config_upload_validation *config_upload_validation; | 152 | sp_config_upload_validation *config_upload_validation; |
| 162 | sp_config_cookie *config_cookie; | 153 | sp_config_cookie *config_cookie; |
| @@ -164,9 +155,16 @@ typedef struct { | |||
| 164 | sp_config_auto_cookie_secure *config_auto_cookie_secure; | 155 | sp_config_auto_cookie_secure *config_auto_cookie_secure; |
| 165 | sp_config_global_strict *config_global_strict; | 156 | sp_config_global_strict *config_global_strict; |
| 166 | sp_config_disable_xxe *config_disable_xxe; | 157 | sp_config_disable_xxe *config_disable_xxe; |
| 167 | sp_config_disabled_constructs *config_disabled_constructs; | ||
| 168 | sp_config_eval *config_eval; | 158 | sp_config_eval *config_eval; |
| 169 | sp_config_session *config_session; | 159 | sp_config_session *config_session; |
| 160 | bool hook_execute; | ||
| 161 | |||
| 162 | HashTable *config_disabled_functions; | ||
| 163 | HashTable *config_disabled_functions_hooked; | ||
| 164 | HashTable *config_disabled_functions_ret; | ||
| 165 | HashTable *config_disabled_functions_ret_hooked; | ||
| 166 | sp_config_disabled_functions *config_disabled_functions_reg; | ||
| 167 | sp_config_disabled_functions *config_disabled_functions_reg_ret; | ||
| 170 | } sp_config; | 168 | } sp_config; |
| 171 | 169 | ||
| 172 | typedef struct { | 170 | typedef struct { |
diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index 2a570cd..81f43f7 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c | |||
| @@ -1,39 +1,8 @@ | |||
| 1 | #include "php_snuffleupagus.h" | 1 | #include "php_snuffleupagus.h" |
| 2 | #include "zend_types.h" | ||
| 2 | 3 | ||
| 3 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | 4 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) |
| 4 | 5 | ||
| 5 | static const struct { | ||
| 6 | unsigned int type; | ||
| 7 | char *keys[5]; // Update this value if necessary | ||
| 8 | } CONSTRUCTS_TYPES[] = { | ||
| 9 | {.type = ZEND_INCLUDE_OR_EVAL, | ||
| 10 | .keys = {"include", "include_once", "require", "require_once", NULL}}, | ||
| 11 | {.type = ZEND_ECHO, .keys = {"echo", NULL}}, | ||
| 12 | {.type = ZEND_NEW, .keys = {"new", NULL}}, | ||
| 13 | {.type = ZEND_EXIT, .keys = {"exit", NULL}}, | ||
| 14 | {.type = ZEND_STRLEN, .keys = {"strlen", NULL}}, | ||
| 15 | {.type = ZEND_EVAL_CODE, .keys = {"eval", NULL}}, | ||
| 16 | {.type = 0, .keys = {NULL}}}; | ||
| 17 | |||
| 18 | static int get_construct_type(sp_disabled_function const *const df) { | ||
| 19 | for (size_t i = 0; 0 != CONSTRUCTS_TYPES[i].type; i++) { | ||
| 20 | for (size_t j = 0; NULL != CONSTRUCTS_TYPES[i].keys[j]; j++) { | ||
| 21 | assert(df->function || df->r_function); | ||
| 22 | if (df->function) { | ||
| 23 | if (0 == strcmp(df->function, CONSTRUCTS_TYPES[i].keys[j])) { | ||
| 24 | return CONSTRUCTS_TYPES[i].type; | ||
| 25 | } | ||
| 26 | } else { | ||
| 27 | if (true == sp_is_regexp_matching(df->r_function, | ||
| 28 | CONSTRUCTS_TYPES[i].keys[j])) { | ||
| 29 | return CONSTRUCTS_TYPES[i].type; | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
| 33 | } | ||
| 34 | return -1; | ||
| 35 | } | ||
| 36 | |||
| 37 | static int parse_enable(char *line, bool *restrict retval, | 6 | static int parse_enable(char *line, bool *restrict retval, |
| 38 | bool *restrict simulation) { | 7 | bool *restrict simulation) { |
| 39 | bool enable = false, disable = false; | 8 | bool enable = false, disable = false; |
| @@ -137,7 +106,7 @@ int parse_unserialize(char *line) { | |||
| 137 | {parse_str, SP_TOKEN_DUMP, &(unserialize->dump)}, | 106 | {parse_str, SP_TOKEN_DUMP, &(unserialize->dump)}, |
| 138 | {0}}; | 107 | {0}}; |
| 139 | 108 | ||
| 140 | unserialize->textual_representation = estrdup(line); | 109 | unserialize->textual_representation = zend_string_init(line, strlen(line), 1); |
| 141 | 110 | ||
| 142 | int ret = parse_keywords(sp_config_funcs, line); | 111 | int ret = parse_keywords(sp_config_funcs, line); |
| 143 | if (0 != ret) { | 112 | if (0 != ret) { |
| @@ -167,7 +136,8 @@ int parse_readonly_exec(char *line) { | |||
| 167 | {parse_str, SP_TOKEN_DUMP, &(readonly_exec->dump)}, | 136 | {parse_str, SP_TOKEN_DUMP, &(readonly_exec->dump)}, |
| 168 | {0}}; | 137 | {0}}; |
| 169 | 138 | ||
| 170 | readonly_exec->textual_representation = estrdup(line); | 139 | readonly_exec->textual_representation = |
| 140 | zend_string_init(line, strlen(line), 1); | ||
| 171 | int ret = parse_keywords(sp_config_funcs, line); | 141 | int ret = parse_keywords(sp_config_funcs, line); |
| 172 | 142 | ||
| 173 | if (0 != ret) { | 143 | if (0 != ret) { |
| @@ -196,8 +166,8 @@ int parse_global(char *line) { | |||
| 196 | } | 166 | } |
| 197 | 167 | ||
| 198 | static int parse_eval_filter_conf(char *line, sp_list_node **list) { | 168 | static int parse_eval_filter_conf(char *line, sp_list_node **list) { |
| 199 | char *token; | 169 | char *token, *tmp; |
| 200 | char *rest; | 170 | zend_string *rest = NULL; |
| 201 | sp_config_eval *eval = SNUFFLEUPAGUS_G(config).config_eval; | 171 | sp_config_eval *eval = SNUFFLEUPAGUS_G(config).config_eval; |
| 202 | 172 | ||
| 203 | sp_config_functions sp_config_funcs[] = { | 173 | sp_config_functions sp_config_funcs[] = { |
| @@ -207,15 +177,19 @@ static int parse_eval_filter_conf(char *line, sp_list_node **list) { | |||
| 207 | {parse_str, SP_TOKEN_DUMP, &(SNUFFLEUPAGUS_G(config).config_eval->dump)}, | 177 | {parse_str, SP_TOKEN_DUMP, &(SNUFFLEUPAGUS_G(config).config_eval->dump)}, |
| 208 | {0}}; | 178 | {0}}; |
| 209 | 179 | ||
| 210 | eval->textual_representation = estrdup(line); | 180 | eval->textual_representation = zend_string_init(line, strlen(line), 1); |
| 211 | 181 | ||
| 212 | int ret = parse_keywords(sp_config_funcs, line); | 182 | int ret = parse_keywords(sp_config_funcs, line); |
| 213 | if (0 != ret) { | 183 | if (0 != ret) { |
| 214 | return ret; | 184 | return ret; |
| 215 | } | 185 | } |
| 216 | 186 | ||
| 217 | while ((token = strtok_r(rest, ",", &rest))) { | 187 | tmp = ZSTR_VAL(rest); |
| 218 | *list = sp_list_insert(*list, token); | 188 | while ((token = strtok_r(tmp, ",", &tmp))) { |
| 189 | *list = sp_list_insert(*list, zend_string_init(token, strlen(token), 1)); | ||
| 190 | } | ||
| 191 | if (rest != NULL) { | ||
| 192 | pefree(rest, 1); | ||
| 219 | } | 193 | } |
| 220 | return SUCCESS; | 194 | return SUCCESS; |
| 221 | } | 195 | } |
| @@ -232,7 +206,7 @@ int parse_eval_whitelist(char *line) { | |||
| 232 | 206 | ||
| 233 | int parse_cookie(char *line) { | 207 | int parse_cookie(char *line) { |
| 234 | int ret = 0; | 208 | int ret = 0; |
| 235 | char *samesite = NULL; | 209 | zend_string *samesite = NULL; |
| 236 | sp_cookie *cookie = pecalloc(sizeof(sp_cookie), 1, 1); | 210 | sp_cookie *cookie = pecalloc(sizeof(sp_cookie), 1, 1); |
| 237 | 211 | ||
| 238 | sp_config_functions sp_config_funcs_cookie_encryption[] = { | 212 | sp_config_functions sp_config_funcs_cookie_encryption[] = { |
| @@ -274,7 +248,7 @@ int parse_cookie(char *line) { | |||
| 274 | sp_line_no); | 248 | sp_line_no); |
| 275 | return -1; | 249 | return -1; |
| 276 | } | 250 | } |
| 277 | if ((!cookie->name || '\0' == cookie->name[0]) && !cookie->name_r) { | 251 | if ((!cookie->name || 0 == ZSTR_LEN(cookie->name)) && !cookie->name_r) { |
| 278 | sp_log_err("config", | 252 | sp_log_err("config", |
| 279 | "You must specify a cookie name/regexp on line " | 253 | "You must specify a cookie name/regexp on line " |
| 280 | "%zu.", | 254 | "%zu.", |
| @@ -289,16 +263,17 @@ int parse_cookie(char *line) { | |||
| 289 | return -1; | 263 | return -1; |
| 290 | } | 264 | } |
| 291 | if (samesite) { | 265 | if (samesite) { |
| 292 | if (0 == strcasecmp(samesite, SP_TOKEN_SAMESITE_LAX)) { | 266 | if (zend_string_equals_literal_ci(samesite, SP_TOKEN_SAMESITE_LAX)) { |
| 293 | cookie->samesite = lax; | 267 | cookie->samesite = lax; |
| 294 | } else if (0 == strcasecmp(samesite, SP_TOKEN_SAMESITE_STRICT)) { | 268 | } else if (zend_string_equals_literal_ci(samesite, |
| 269 | SP_TOKEN_SAMESITE_STRICT)) { | ||
| 295 | cookie->samesite = strict; | 270 | cookie->samesite = strict; |
| 296 | } else { | 271 | } else { |
| 297 | sp_log_err( | 272 | sp_log_err( |
| 298 | "config", | 273 | "config", |
| 299 | "%s is an invalid value to samesite (expected %s or %s) on line " | 274 | "%s is an invalid value to samesite (expected %s or %s) on line " |
| 300 | "%zu.", | 275 | "%zu.", |
| 301 | samesite, SP_TOKEN_SAMESITE_LAX, SP_TOKEN_SAMESITE_STRICT, | 276 | ZSTR_VAL(samesite), SP_TOKEN_SAMESITE_LAX, SP_TOKEN_SAMESITE_STRICT, |
| 302 | sp_line_no); | 277 | sp_line_no); |
| 303 | return -1; | 278 | return -1; |
| 304 | } | 279 | } |
| @@ -308,11 +283,22 @@ int parse_cookie(char *line) { | |||
| 308 | return SUCCESS; | 283 | return SUCCESS; |
| 309 | } | 284 | } |
| 310 | 285 | ||
| 286 | int add_df_to_hashtable(HashTable *ht, sp_disabled_function *df) { | ||
| 287 | zval *list = zend_hash_find(ht, df->function); | ||
| 288 | |||
| 289 | if (NULL == list) { | ||
| 290 | zend_hash_add_ptr(ht, df->function, sp_list_insert(NULL, df)); | ||
| 291 | } else { | ||
| 292 | Z_PTR_P(list) = sp_list_insert(Z_PTR_P(list), df); | ||
| 293 | } | ||
| 294 | return SUCCESS; | ||
| 295 | } | ||
| 296 | |||
| 311 | int parse_disabled_functions(char *line) { | 297 | int parse_disabled_functions(char *line) { |
| 312 | int ret = 0; | 298 | int ret = 0; |
| 313 | bool enable = true, disable = false, allow = false, drop = false; | 299 | bool enable = true, disable = false, allow = false, drop = false; |
| 314 | char *pos = NULL, *var = NULL, *param = NULL; | 300 | zend_string *pos = NULL, *var = NULL, *param = NULL; |
| 315 | char *line_number = NULL; | 301 | zend_string *line_number = NULL; |
| 316 | sp_disabled_function *df = pecalloc(sizeof(*df), 1, 1); | 302 | sp_disabled_function *df = pecalloc(sizeof(*df), 1, 1); |
| 317 | df->pos = -1; | 303 | df->pos = -1; |
| 318 | 304 | ||
| @@ -330,7 +316,7 @@ int parse_disabled_functions(char *line) { | |||
| 330 | {parse_empty, SP_TOKEN_DROP, &(drop)}, | 316 | {parse_empty, SP_TOKEN_DROP, &(drop)}, |
| 331 | {parse_str, SP_TOKEN_HASH, &(df->hash)}, | 317 | {parse_str, SP_TOKEN_HASH, &(df->hash)}, |
| 332 | {parse_str, SP_TOKEN_PARAM, &(param)}, | 318 | {parse_str, SP_TOKEN_PARAM, &(param)}, |
| 333 | {parse_regexp, SP_TOKEN_VALUE_REGEXP, &(df->value_r)}, | 319 | {parse_regexp, SP_TOKEN_VALUE_REGEXP, &(df->r_value)}, |
| 334 | {parse_str, SP_TOKEN_VALUE, &(df->value)}, | 320 | {parse_str, SP_TOKEN_VALUE, &(df->value)}, |
| 335 | {parse_str, SP_TOKEN_KEY, &(df->key)}, | 321 | {parse_str, SP_TOKEN_KEY, &(df->key)}, |
| 336 | {parse_regexp, SP_TOKEN_KEY_REGEXP, &(df->r_key)}, | 322 | {parse_regexp, SP_TOKEN_KEY_REGEXP, &(df->r_key)}, |
| @@ -360,7 +346,7 @@ int parse_disabled_functions(char *line) { | |||
| 360 | return 1; \ | 346 | return 1; \ |
| 361 | } | 347 | } |
| 362 | 348 | ||
| 363 | MUTUALLY_EXCLUSIVE(df->value, df->value_r, "value", "regexp"); | 349 | MUTUALLY_EXCLUSIVE(df->value, df->r_value, "value", "regexp"); |
| 364 | MUTUALLY_EXCLUSIVE(df->r_function, df->function, "r_function", "function"); | 350 | MUTUALLY_EXCLUSIVE(df->r_function, df->function, "r_function", "function"); |
| 365 | MUTUALLY_EXCLUSIVE(df->filename, df->r_filename, "r_filename", "filename"); | 351 | MUTUALLY_EXCLUSIVE(df->filename, df->r_filename, "r_filename", "filename"); |
| 366 | MUTUALLY_EXCLUSIVE(df->ret, df->r_ret, "r_ret", "ret"); | 352 | MUTUALLY_EXCLUSIVE(df->ret, df->r_ret, "r_ret", "ret"); |
| @@ -375,25 +361,38 @@ int parse_disabled_functions(char *line) { | |||
| 375 | "'.r_param', '.param' and '.pos' are mutually exclusive on line %zu.", | 361 | "'.r_param', '.param' and '.pos' are mutually exclusive on line %zu.", |
| 376 | line, sp_line_no); | 362 | line, sp_line_no); |
| 377 | return -1; | 363 | return -1; |
| 378 | } else if ((df->r_key || df->key) && (df->value_r || df->value)) { | 364 | } else if ((df->r_key || df->key) && (df->r_value || df->value)) { |
| 379 | sp_log_err("config", | 365 | sp_log_err("config", |
| 380 | "Invalid configuration line: 'sp.disabled_functions%s':" | 366 | "Invalid configuration line: 'sp.disabled_functions%s':" |
| 381 | "`key` and `value` are mutually exclusive on line %zu.", | 367 | "`key` and `value` are mutually exclusive on line %zu.", |
| 382 | line, sp_line_no); | 368 | line, sp_line_no); |
| 383 | return -1; | 369 | return -1; |
| 384 | } else if ((df->r_ret || df->ret) && (df->r_param || param)) { | 370 | } else if ((df->r_ret || df->ret || df->ret_type) && (df->r_param || param)) { |
| 385 | sp_log_err("config", | 371 | sp_log_err("config", |
| 386 | "Invalid configuration line: 'sp.disabled_functions%s':" | 372 | "Invalid configuration line: 'sp.disabled_functions%s':" |
| 387 | "`ret` and `param` are mutually exclusive on line %zu.", | 373 | "`ret` and `param` are mutually exclusive on line %zu.", |
| 388 | line, sp_line_no); | 374 | line, sp_line_no); |
| 389 | return -1; | 375 | return -1; |
| 376 | } else if ((df->r_ret || df->ret || df->ret_type) && (var)) { | ||
| 377 | sp_log_err("config", | ||
| 378 | "Invalid configuration line: 'sp.disabled_functions%s':" | ||
| 379 | "`ret` and `var` are mutually exclusive on line %zu.", | ||
| 380 | line, sp_line_no); | ||
| 381 | return -1; | ||
| 382 | } else if ((df->r_ret || df->ret || df->ret_type) && | ||
| 383 | (df->value || df->r_value)) { | ||
| 384 | sp_log_err("config", | ||
| 385 | "Invalid configuration line: 'sp.disabled_functions%s':" | ||
| 386 | "`ret` and `value` are mutually exclusive on line %zu.", | ||
| 387 | line, sp_line_no); | ||
| 388 | return -1; | ||
| 390 | } else if (!(df->r_function || df->function)) { | 389 | } else if (!(df->r_function || df->function)) { |
| 391 | sp_log_err("config", | 390 | sp_log_err("config", |
| 392 | "Invalid configuration line: 'sp.disabled_functions%s':" | 391 | "Invalid configuration line: 'sp.disabled_functions%s':" |
| 393 | " must take a function name on line %zu.", | 392 | " must take a function name on line %zu.", |
| 394 | line, sp_line_no); | 393 | line, sp_line_no); |
| 395 | return -1; | 394 | return -1; |
| 396 | } else if (df->filename && *df->filename != '/') { | 395 | } else if (df->filename && *ZSTR_VAL(df->filename) != '/') { |
| 397 | sp_log_err("config", | 396 | sp_log_err("config", |
| 398 | "Invalid configuration line: 'sp.disabled_functions%s':" | 397 | "Invalid configuration line: 'sp.disabled_functions%s':" |
| 399 | "'.filename' must be an absolute path on line %zu.", | 398 | "'.filename' must be an absolute path on line %zu.", |
| @@ -410,10 +409,10 @@ int parse_disabled_functions(char *line) { | |||
| 410 | if (pos) { | 409 | if (pos) { |
| 411 | errno = 0; | 410 | errno = 0; |
| 412 | char *endptr; | 411 | char *endptr; |
| 413 | df->pos = (int)strtol(pos, &endptr, 10); | 412 | df->pos = (int)strtol(ZSTR_VAL(pos), &endptr, 10); |
| 414 | if (errno != 0 || endptr == pos) { | 413 | if (errno != 0 || endptr == ZSTR_VAL(pos)) { |
| 415 | sp_log_err("config", "Failed to parse arg '%s' of `pos` on line %zu.", | 414 | sp_log_err("config", "Failed to parse arg '%s' of `pos` on line %zu.", |
| 416 | pos, sp_line_no); | 415 | ZSTR_VAL(pos), sp_line_no); |
| 417 | return -1; | 416 | return -1; |
| 418 | } | 417 | } |
| 419 | } | 418 | } |
| @@ -421,46 +420,46 @@ int parse_disabled_functions(char *line) { | |||
| 421 | if (line_number) { | 420 | if (line_number) { |
| 422 | errno = 0; | 421 | errno = 0; |
| 423 | char *endptr; | 422 | char *endptr; |
| 424 | df->line = (unsigned int)strtoul(line_number, &endptr, 10); | 423 | df->line = (unsigned int)strtoul(ZSTR_VAL(line_number), &endptr, 10); |
| 425 | if (errno != 0 || endptr == line_number) { | 424 | if (errno != 0 || endptr == ZSTR_VAL(line_number)) { |
| 426 | sp_log_err("config", "Failed to parse arg '%s' of `line` on line %zu.", | 425 | sp_log_err("config", "Failed to parse arg '%s' of `line` on line %zu.", |
| 427 | line_number, sp_line_no); | 426 | ZSTR_VAL(line_number), sp_line_no); |
| 428 | return -1; | 427 | return -1; |
| 429 | } | 428 | } |
| 430 | } | 429 | } |
| 431 | df->allow = allow; | 430 | df->allow = allow; |
| 432 | df->textual_representation = estrdup(line); | 431 | df->textual_representation = zend_string_init(line, strlen(line), 1); |
| 433 | 432 | ||
| 434 | if (df->function) { | 433 | if (df->function) { |
| 435 | df->functions_list = parse_functions_list(df->function); | 434 | df->functions_list = parse_functions_list(ZSTR_VAL(df->function)); |
| 436 | } | 435 | } |
| 437 | 436 | ||
| 438 | if (param) { | 437 | if (param) { |
| 439 | if (strlen(param) > 0 && param[0] != '$') { | 438 | if (ZSTR_LEN(param) > 0 && ZSTR_VAL(param)[0] != '$') { |
| 440 | /* This is an ugly hack. We're prefixing with a `$` because otherwise | 439 | /* This is an ugly hack. We're prefixing with a `$` because otherwise |
| 441 | * the parser treats this as a constant. | 440 | * the parser treats this as a constant. |
| 442 | * FIXME: Remove this, and improve our (weird) parser. */ | 441 | * FIXME: Remove this, and improve our (weird) parser. */ |
| 443 | char *new = pecalloc(strlen(param) + 2, 1, 1); | 442 | char *new = pecalloc(ZSTR_LEN(param) + 2, 1, 1); |
| 444 | new[0] = '$'; | 443 | new[0] = '$'; |
| 445 | memcpy(new + 1, param, strlen(param)); | 444 | memcpy(new + 1, ZSTR_VAL(param), ZSTR_LEN(param)); |
| 446 | df->param = sp_parse_var(new); | 445 | df->param = sp_parse_var(new); |
| 447 | free(new); | 446 | free(new); |
| 448 | } else { | 447 | } else { |
| 449 | df->param = sp_parse_var(param); | 448 | df->param = sp_parse_var(ZSTR_VAL(param)); |
| 450 | } | 449 | } |
| 451 | if (!df->param) { | 450 | if (!df->param) { |
| 452 | sp_log_err("config", "Invalid value '%s' for `param` on line %zu.", param, | 451 | sp_log_err("config", "Invalid value '%s' for `param` on line %zu.", |
| 453 | sp_line_no); | 452 | ZSTR_VAL(param), sp_line_no); |
| 454 | return -1; | 453 | return -1; |
| 455 | } | 454 | } |
| 456 | } | 455 | } |
| 457 | 456 | ||
| 458 | if (var) { | 457 | if (var) { |
| 459 | if (*var) { | 458 | if (ZSTR_LEN(var)) { |
| 460 | df->var = sp_parse_var(var); | 459 | df->var = sp_parse_var(ZSTR_VAL(var)); |
| 461 | if (!df->var) { | 460 | if (!df->var) { |
| 462 | sp_log_err("config", "Invalid value '%s' for `var` on line %zu.", var, | 461 | sp_log_err("config", "Invalid value '%s' for `var` on line %zu.", |
| 463 | sp_line_no); | 462 | ZSTR_VAL(var), sp_line_no); |
| 464 | return -1; | 463 | return -1; |
| 465 | } | 464 | } |
| 466 | } else { | 465 | } else { |
| @@ -469,38 +468,33 @@ int parse_disabled_functions(char *line) { | |||
| 469 | } | 468 | } |
| 470 | } | 469 | } |
| 471 | 470 | ||
| 472 | switch (get_construct_type(df)) { | ||
| 473 | case ZEND_INCLUDE_OR_EVAL: | ||
| 474 | SNUFFLEUPAGUS_G(config) | ||
| 475 | .config_disabled_constructs->construct_include = sp_list_insert( | ||
| 476 | SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_include, | ||
| 477 | df); | ||
| 478 | return ret; | ||
| 479 | case ZEND_EVAL_CODE: | ||
| 480 | SNUFFLEUPAGUS_G(config) | ||
| 481 | .config_disabled_constructs->construct_eval = sp_list_insert( | ||
| 482 | SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval, | ||
| 483 | df); | ||
| 484 | return ret; | ||
| 485 | case ZEND_ECHO: | ||
| 486 | default: | ||
| 487 | break; | ||
| 488 | } | ||
| 489 | |||
| 490 | if (true == disable) { | 471 | if (true == disable) { |
| 491 | return ret; | 472 | return ret; |
| 492 | } | 473 | } |
| 493 | 474 | ||
| 494 | if (df->ret || df->r_ret || df->ret_type) { | 475 | if (df->function && !df->functions_list) { |
| 495 | SNUFFLEUPAGUS_G(config).config_disabled_functions_ret->disabled_functions = | 476 | if (df->ret || df->r_ret || df->ret_type) { |
| 496 | sp_list_insert(SNUFFLEUPAGUS_G(config) | 477 | add_df_to_hashtable(SNUFFLEUPAGUS_G(config).config_disabled_functions_ret, |
| 497 | .config_disabled_functions_ret->disabled_functions, | 478 | df); |
| 498 | df); | 479 | } else { |
| 480 | add_df_to_hashtable(SNUFFLEUPAGUS_G(config).config_disabled_functions, | ||
| 481 | df); | ||
| 482 | } | ||
| 499 | } else { | 483 | } else { |
| 500 | SNUFFLEUPAGUS_G(config) | 484 | if (df->ret || df->r_ret || df->ret_type) { |
| 501 | .config_disabled_functions->disabled_functions = sp_list_insert( | 485 | SNUFFLEUPAGUS_G(config) |
| 502 | SNUFFLEUPAGUS_G(config).config_disabled_functions->disabled_functions, | 486 | .config_disabled_functions_reg_ret->disabled_functions = |
| 503 | df); | 487 | sp_list_insert( |
| 488 | SNUFFLEUPAGUS_G(config) | ||
| 489 | .config_disabled_functions_reg_ret->disabled_functions, | ||
| 490 | df); | ||
| 491 | } else { | ||
| 492 | SNUFFLEUPAGUS_G(config) | ||
| 493 | .config_disabled_functions_reg->disabled_functions = | ||
| 494 | sp_list_insert(SNUFFLEUPAGUS_G(config) | ||
| 495 | .config_disabled_functions_reg->disabled_functions, | ||
| 496 | df); | ||
| 497 | } | ||
| 504 | } | 498 | } |
| 505 | return ret; | 499 | return ret; |
| 506 | } | 500 | } |
| @@ -529,20 +523,21 @@ int parse_upload_validation(char *line) { | |||
| 529 | } | 523 | } |
| 530 | SNUFFLEUPAGUS_G(config).config_upload_validation->enable = enable; | 524 | SNUFFLEUPAGUS_G(config).config_upload_validation->enable = enable; |
| 531 | 525 | ||
| 532 | char const *script = SNUFFLEUPAGUS_G(config).config_upload_validation->script; | 526 | zend_string const *script = |
| 527 | SNUFFLEUPAGUS_G(config).config_upload_validation->script; | ||
| 533 | 528 | ||
| 534 | if (!script) { | 529 | if (!script) { |
| 535 | sp_log_err("config", | 530 | sp_log_err("config", |
| 536 | "The `script` directive is mandatory in '%s' on line %zu.", line, | 531 | "The `script` directive is mandatory in '%s' on line %zu.", line, |
| 537 | sp_line_no); | 532 | sp_line_no); |
| 538 | return -1; | 533 | return -1; |
| 539 | } else if (-1 == access(script, F_OK)) { | 534 | } else if (-1 == access(ZSTR_VAL(script), F_OK)) { |
| 540 | sp_log_err("config", "The `script` (%s) doesn't exist on line %zu.", script, | 535 | sp_log_err("config", "The `script` (%s) doesn't exist on line %zu.", |
| 541 | sp_line_no); | 536 | ZSTR_VAL(script), sp_line_no); |
| 542 | return -1; | 537 | return -1; |
| 543 | } else if (-1 == access(script, X_OK)) { | 538 | } else if (-1 == access(ZSTR_VAL(script), X_OK)) { |
| 544 | sp_log_err("config", "The `script` (%s) isn't executable on line %zu.", | 539 | sp_log_err("config", "The `script` (%s) isn't executable on line %zu.", |
| 545 | script, sp_line_no); | 540 | ZSTR_VAL(script), sp_line_no); |
| 546 | return -1; | 541 | return -1; |
| 547 | } | 542 | } |
| 548 | 543 | ||
diff --git a/src/sp_config_utils.c b/src/sp_config_utils.c index 130f07e..d72561b 100644 --- a/src/sp_config_utils.c +++ b/src/sp_config_utils.c | |||
| @@ -32,18 +32,18 @@ int parse_keywords(sp_config_functions *funcs, char *line) { | |||
| 32 | return 0; | 32 | return 0; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | char *get_param(size_t *consumed, char *restrict line, sp_type type, | 35 | zend_string *get_param(size_t *consumed, char *restrict line, sp_type type, |
| 36 | const char *restrict keyword) { | 36 | const char *restrict keyword) { |
| 37 | enum { IN_ESCAPE, NONE } state = NONE; | 37 | enum { IN_ESCAPE, NONE } state = NONE; |
| 38 | char *original_line = line; | 38 | char *original_line = line; |
| 39 | size_t j = 0; | 39 | size_t j = 0; |
| 40 | 40 | ||
| 41 | char *ret = NULL; | 41 | zend_string *ret = NULL; |
| 42 | if (NULL == line || '\0' == *line) { | 42 | if (NULL == line || '\0' == *line) { |
| 43 | goto err; | 43 | goto err; |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | ret = pecalloc(sizeof(char), strlen(original_line) + 1, 1); | 46 | ret = zend_string_alloc(strlen(line) + 1, 1); |
| 47 | 47 | ||
| 48 | /* The first char of a string is always '"', since they MUST be quoted. */ | 48 | /* The first char of a string is always '"', since they MUST be quoted. */ |
| 49 | if ('"' == *line) { | 49 | if ('"' == *line) { |
| @@ -65,6 +65,11 @@ char *get_param(size_t *consumed, char *restrict line, sp_type type, | |||
| 65 | 2. the SP_TOKEN_END_PARAM | 65 | 2. the SP_TOKEN_END_PARAM |
| 66 | */ | 66 | */ |
| 67 | *consumed = i + 2; | 67 | *consumed = i + 2; |
| 68 | // Make sure that the string we return is the right size, | ||
| 69 | // as it can be smaller than strlen(line) | ||
| 70 | ret = zend_string_truncate(ret, j, 1); | ||
| 71 | // truncate does not add a \0 | ||
| 72 | ZSTR_VAL(ret)[ZSTR_LEN(ret)] = 0; | ||
| 68 | return ret; | 73 | return ret; |
| 69 | } else if (state == IN_ESCAPE) { | 74 | } else if (state == IN_ESCAPE) { |
| 70 | break; // we're on an escped double quote | 75 | break; // we're on an escped double quote |
| @@ -82,7 +87,7 @@ char *get_param(size_t *consumed, char *restrict line, sp_type type, | |||
| 82 | if (state == IN_ESCAPE) { | 87 | if (state == IN_ESCAPE) { |
| 83 | state = NONE; | 88 | state = NONE; |
| 84 | } | 89 | } |
| 85 | ret[j++] = line[i]; | 90 | ZSTR_VAL(ret)[j++] = line[i]; |
| 86 | } | 91 | } |
| 87 | err: | 92 | err: |
| 88 | if (0 == j) { | 93 | if (0 == j) { |
diff --git a/src/sp_config_utils.h b/src/sp_config_utils.h index 9fef996..a63cadc 100644 --- a/src/sp_config_utils.h +++ b/src/sp_config_utils.h | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | #define SP_CONFIG_UTILS | 2 | #define SP_CONFIG_UTILS |
| 3 | 3 | ||
| 4 | int parse_keywords(sp_config_functions *, char *); | 4 | int parse_keywords(sp_config_functions *, char *); |
| 5 | char *get_param(size_t *, char *restrict, sp_type, const char *restrict); | 5 | zend_string *get_param(size_t *, char *restrict, sp_type, const char *restrict); |
| 6 | int array_to_list(char **, sp_list_node **); | 6 | int array_to_list(char **, sp_list_node **); |
| 7 | sp_list_node *parse_functions_list(char *value); | 7 | sp_list_node *parse_functions_list(char *value); |
| 8 | 8 | ||
diff --git a/src/sp_cookie_encryption.c b/src/sp_cookie_encryption.c index 6cb1ff7..3f58fb0 100644 --- a/src/sp_cookie_encryption.c +++ b/src/sp_cookie_encryption.c | |||
| @@ -4,8 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | 5 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) |
| 6 | 6 | ||
| 7 | static inline const sp_cookie *sp_lookup_cookie_config(const char *key) { | 7 | static inline const sp_cookie *sp_lookup_cookie_config(const zend_string *key) { |
| 8 | sp_list_node *it = SNUFFLEUPAGUS_G(config).config_cookie->cookies; | 8 | const sp_list_node *it = SNUFFLEUPAGUS_G(config).config_cookie->cookies; |
| 9 | 9 | ||
| 10 | while (it) { | 10 | while (it) { |
| 11 | const sp_cookie *config = it->data; | 11 | const sp_cookie *config = it->data; |
| @@ -20,7 +20,7 @@ static inline const sp_cookie *sp_lookup_cookie_config(const char *key) { | |||
| 20 | /* called at RINIT time with each cookie, eventually decrypt said cookie */ | 20 | /* called at RINIT time with each cookie, eventually decrypt said cookie */ |
| 21 | int decrypt_cookie(zval *pDest, int num_args, va_list args, | 21 | int decrypt_cookie(zval *pDest, int num_args, va_list args, |
| 22 | zend_hash_key *hash_key) { | 22 | zend_hash_key *hash_key) { |
| 23 | const sp_cookie *cookie = sp_lookup_cookie_config(ZSTR_VAL(hash_key->key)); | 23 | const sp_cookie *cookie = sp_lookup_cookie_config(hash_key->key); |
| 24 | 24 | ||
| 25 | /* If the cookie isn't in the conf, it shouldn't be encrypted. */ | 25 | /* If the cookie isn't in the conf, it shouldn't be encrypted. */ |
| 26 | if (!cookie || !cookie->encrypt) { | 26 | if (!cookie || !cookie->encrypt) { |
| @@ -35,9 +35,9 @@ int decrypt_cookie(zval *pDest, int num_args, va_list args, | |||
| 35 | return decrypt_zval(pDest, cookie->simulation, hash_key); | 35 | return decrypt_zval(pDest, cookie->simulation, hash_key); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | static zend_string *encrypt_data(char *data, unsigned long long data_len) { | 38 | static zend_string *encrypt_data(zend_string *data) { |
| 39 | zend_string *z = encrypt_zval(data, data_len); | 39 | zend_string *z = encrypt_zval(data); |
| 40 | sp_log_debug("cookie_encryption", "Cookie value:%s:", z->val); | 40 | sp_log_debug("cookie_encryption", "Cookie value:%s:", ZSTR_VAL(z)); |
| 41 | return z; | 41 | return z; |
| 42 | } | 42 | } |
| 43 | 43 | ||
| @@ -77,7 +77,7 @@ PHP_FUNCTION(sp_setcookie) { | |||
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | /* lookup existing configuration for said cookie */ | 79 | /* lookup existing configuration for said cookie */ |
| 80 | cookie_node = sp_lookup_cookie_config(ZSTR_VAL(name)); | 80 | cookie_node = sp_lookup_cookie_config(name); |
| 81 | 81 | ||
| 82 | /* If the cookie's value is encrypted, it won't be usable by | 82 | /* If the cookie's value is encrypted, it won't be usable by |
| 83 | * javascript anyway. | 83 | * javascript anyway. |
| @@ -88,7 +88,7 @@ PHP_FUNCTION(sp_setcookie) { | |||
| 88 | 88 | ||
| 89 | /* Shall we encrypt the cookie's value? */ | 89 | /* Shall we encrypt the cookie's value? */ |
| 90 | if (cookie_node && cookie_node->encrypt && value) { | 90 | if (cookie_node && cookie_node->encrypt && value) { |
| 91 | zend_string *encrypted_data = encrypt_data(value->val, value->len); | 91 | zend_string *encrypted_data = encrypt_data(value); |
| 92 | ZVAL_STR_COPY(¶ms[1], encrypted_data); | 92 | ZVAL_STR_COPY(¶ms[1], encrypted_data); |
| 93 | zend_string_release(encrypted_data); | 93 | zend_string_release(encrypted_data); |
| 94 | } else if (value) { | 94 | } else if (value) { |
diff --git a/src/sp_crypt.c b/src/sp_crypt.c index 6a46d06..d3588b4 100644 --- a/src/sp_crypt.c +++ b/src/sp_crypt.c | |||
| @@ -7,10 +7,13 @@ ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | |||
| 7 | void generate_key(unsigned char *key) { | 7 | void generate_key(unsigned char *key) { |
| 8 | PHP_SHA256_CTX ctx; | 8 | PHP_SHA256_CTX ctx; |
| 9 | const char *user_agent = getenv("HTTP_USER_AGENT"); | 9 | const char *user_agent = getenv("HTTP_USER_AGENT"); |
| 10 | const char *env_var = | 10 | const zend_string *env_var_zend = |
| 11 | getenv(SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var); | 11 | SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var; |
| 12 | const char *encryption_key = | 12 | const zend_string *encryption_key_zend = |
| 13 | SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key; | 13 | SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key; |
| 14 | const char *env_var = (env_var_zend ? getenv(ZSTR_VAL(env_var_zend)) : NULL); | ||
| 15 | const char *encryption_key = | ||
| 16 | (encryption_key_zend ? ZSTR_VAL(encryption_key_zend) : NULL); | ||
| 14 | 17 | ||
| 15 | assert(32 == crypto_secretbox_KEYBYTES); // 32 is the size of a SHA256. | 18 | assert(32 == crypto_secretbox_KEYBYTES); // 32 is the size of a SHA256. |
| 16 | assert(encryption_key); // Encryption key can't be NULL | 19 | assert(encryption_key); // Encryption key can't be NULL |
| @@ -24,10 +27,12 @@ void generate_key(unsigned char *key) { | |||
| 24 | if (env_var) { | 27 | if (env_var) { |
| 25 | PHP_SHA256Update(&ctx, (unsigned char *)env_var, strlen(env_var)); | 28 | PHP_SHA256Update(&ctx, (unsigned char *)env_var, strlen(env_var)); |
| 26 | } else { | 29 | } else { |
| 27 | sp_log_err("cookie_encryption", | 30 | sp_log_err( |
| 28 | "The environment variable '%s'" | 31 | "cookie_encryption", |
| 29 | "is empty, cookies are weakly encrypted.", | 32 | "The environment variable '%s'" |
| 30 | SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var); | 33 | "is empty, cookies are weakly encrypted.", |
| 34 | ZSTR_VAL( | ||
| 35 | SNUFFLEUPAGUS_G(config).config_snuffleupagus->cookies_env_var)); | ||
| 31 | } | 36 | } |
| 32 | 37 | ||
| 33 | if (encryption_key) { | 38 | if (encryption_key) { |
| @@ -119,8 +124,9 @@ int decrypt_zval(zval *pDest, bool simulation, zend_hash_key *hash_key) { | |||
| 119 | ** form `base64(nonce | encrypted_data)` (with `|` being the concatenation | 124 | ** form `base64(nonce | encrypted_data)` (with `|` being the concatenation |
| 120 | ** operation). | 125 | ** operation). |
| 121 | */ | 126 | */ |
| 122 | zend_string *encrypt_zval(char *data, unsigned long long data_len) { | 127 | zend_string *encrypt_zval(zend_string *data) { |
| 123 | const size_t encrypted_msg_len = crypto_secretbox_ZEROBYTES + data_len + 1; | 128 | const size_t encrypted_msg_len = |
| 129 | crypto_secretbox_ZEROBYTES + ZSTR_LEN(data) + 1; | ||
| 124 | // FIXME : We know that this len is too long | 130 | // FIXME : We know that this len is too long |
| 125 | const size_t emsg_and_nonce_len = | 131 | const size_t emsg_and_nonce_len = |
| 126 | encrypted_msg_len + crypto_secretbox_NONCEBYTES; | 132 | encrypted_msg_len + crypto_secretbox_NONCEBYTES; |
| @@ -137,7 +143,8 @@ zend_string *encrypt_zval(char *data, unsigned long long data_len) { | |||
| 137 | 143 | ||
| 138 | /* tweetnacl's API requires the message to be padded with | 144 | /* tweetnacl's API requires the message to be padded with |
| 139 | crypto_secretbox_ZEROBYTES zeroes. */ | 145 | crypto_secretbox_ZEROBYTES zeroes. */ |
| 140 | memcpy(data_to_encrypt + crypto_secretbox_ZEROBYTES, data, data_len); | 146 | memcpy(data_to_encrypt + crypto_secretbox_ZEROBYTES, ZSTR_VAL(data), |
| 147 | ZSTR_LEN(data)); | ||
| 141 | 148 | ||
| 142 | assert(sizeof(zend_long) <= crypto_secretbox_NONCEBYTES); | 149 | assert(sizeof(zend_long) <= crypto_secretbox_NONCEBYTES); |
| 143 | 150 | ||
| @@ -149,4 +156,4 @@ zend_string *encrypt_zval(char *data, unsigned long long data_len) { | |||
| 149 | zend_string *z = php_base64_encode(encrypted_data, emsg_and_nonce_len); | 156 | zend_string *z = php_base64_encode(encrypted_data, emsg_and_nonce_len); |
| 150 | 157 | ||
| 151 | return z; | 158 | return z; |
| 152 | } \ No newline at end of file | 159 | } |
diff --git a/src/sp_crypt.h b/src/sp_crypt.h index 3ede104..22a571e 100644 --- a/src/sp_crypt.h +++ b/src/sp_crypt.h | |||
| @@ -12,6 +12,6 @@ | |||
| 12 | 12 | ||
| 13 | void generate_key(unsigned char *key); | 13 | void generate_key(unsigned char *key); |
| 14 | int decrypt_zval(zval *pDest, bool simulation, zend_hash_key *hask_key); | 14 | int decrypt_zval(zval *pDest, bool simulation, zend_hash_key *hask_key); |
| 15 | zend_string *encrypt_zval(char *data, unsigned long long data_len); | 15 | zend_string *encrypt_zval(zend_string *); |
| 16 | 16 | ||
| 17 | #endif /*__SP_CRYPT */ \ No newline at end of file | 17 | #endif /*__SP_CRYPT */ |
diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c index 341c0a4..14783f6 100644 --- a/src/sp_disabled_functions.c +++ b/src/sp_disabled_functions.c | |||
| @@ -65,7 +65,7 @@ static bool is_functions_list_matching(zend_execute_data* execute_data, | |||
| 65 | static bool is_local_var_matching( | 65 | static bool is_local_var_matching( |
| 66 | zend_execute_data* execute_data, | 66 | zend_execute_data* execute_data, |
| 67 | const sp_disabled_function* const config_node) { | 67 | const sp_disabled_function* const config_node) { |
| 68 | zval* var_value; | 68 | zval* var_value = {0}; |
| 69 | 69 | ||
| 70 | var_value = sp_get_var_value(execute_data, config_node->var, false); | 70 | var_value = sp_get_var_value(execute_data, config_node->var, false); |
| 71 | if (var_value) { | 71 | if (var_value) { |
| @@ -76,14 +76,13 @@ static bool is_local_var_matching( | |||
| 76 | return true; | 76 | return true; |
| 77 | } | 77 | } |
| 78 | } else if (sp_match_array_value(var_value, config_node->value, | 78 | } else if (sp_match_array_value(var_value, config_node->value, |
| 79 | config_node->value_r)) { | 79 | config_node->r_value)) { |
| 80 | return true; | 80 | return true; |
| 81 | } | 81 | } |
| 82 | } else { | 82 | } else { |
| 83 | char* var_value_str = sp_convert_to_string(var_value); | 83 | const zend_string* var_value_str = sp_zval_to_zend_string(var_value); |
| 84 | bool match = sp_match_value(var_value_str, config_node->value, | 84 | bool match = sp_match_value(var_value_str, config_node->value, |
| 85 | config_node->value_r); | 85 | config_node->r_value); |
| 86 | efree(var_value_str); | ||
| 87 | 86 | ||
| 88 | if (true == match) { | 87 | if (true == match) { |
| 89 | return true; | 88 | return true; |
| @@ -93,28 +92,12 @@ static bool is_local_var_matching( | |||
| 93 | return false; | 92 | return false; |
| 94 | } | 93 | } |
| 95 | 94 | ||
| 96 | static inline const sp_list_node* get_config_node(const char* builtin_name) { | ||
| 97 | if (EXPECTED(!builtin_name)) { | ||
| 98 | return SNUFFLEUPAGUS_G(config) | ||
| 99 | .config_disabled_functions->disabled_functions; | ||
| 100 | } else if (!strcmp(builtin_name, "eval")) { | ||
| 101 | return SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval; | ||
| 102 | } else if (!strcmp(builtin_name, "include") || | ||
| 103 | !strcmp(builtin_name, "include_once") || | ||
| 104 | !strcmp(builtin_name, "require") || | ||
| 105 | !strcmp(builtin_name, "require_once")) { | ||
| 106 | return SNUFFLEUPAGUS_G(config) | ||
| 107 | .config_disabled_constructs->construct_include; | ||
| 108 | } | ||
| 109 | ZEND_ASSUME(0); | ||
| 110 | } | ||
| 111 | |||
| 112 | static bool is_param_matching(zend_execute_data* execute_data, | 95 | static bool is_param_matching(zend_execute_data* execute_data, |
| 113 | sp_disabled_function const* const config_node, | 96 | sp_disabled_function const* const config_node, |
| 114 | const char* builtin_name, | 97 | const zend_string* builtin_param, |
| 115 | const char* builtin_param, const char** arg_name, | 98 | const char** arg_name, |
| 116 | const char* builtin_param_name, | 99 | const char* builtin_param_name, |
| 117 | const char** arg_value_str) { | 100 | const zend_string** arg_value_str) { |
| 118 | int nb_param = ZEND_CALL_NUM_ARGS(execute_data); | 101 | int nb_param = ZEND_CALL_NUM_ARGS(execute_data); |
| 119 | int i = 0; | 102 | int i = 0; |
| 120 | zval* arg_value; | 103 | zval* arg_value; |
| @@ -136,14 +119,14 @@ static bool is_param_matching(zend_execute_data* execute_data, | |||
| 136 | } | 119 | } |
| 137 | } | 120 | } |
| 138 | 121 | ||
| 139 | if (builtin_name) { | 122 | if (builtin_param) { |
| 140 | /* We're matching on a language construct (here named "builtin"), | 123 | /* We're matching on a language construct (here named "builtin"), |
| 141 | * and they can only take a single argument, but PHP considers them | 124 | * and they can only take a single argument, but PHP considers them |
| 142 | * differently than functions arguments. */ | 125 | * differently than functions arguments. */ |
| 143 | *arg_name = builtin_param_name; | 126 | *arg_name = builtin_param_name; |
| 144 | *arg_value_str = builtin_param; | 127 | *arg_value_str = builtin_param; |
| 145 | return sp_match_value(builtin_param, config_node->value, | 128 | return sp_match_value(builtin_param, config_node->value, |
| 146 | config_node->value_r); | 129 | config_node->r_value); |
| 147 | } else if (config_node->r_param || config_node->pos != -1) { | 130 | } else if (config_node->r_param || config_node->pos != -1) { |
| 148 | // We're matching on a function (and not a language construct) | 131 | // We're matching on a function (and not a language construct) |
| 149 | for (; i < nb_param; i++) { | 132 | for (; i < nb_param; i++) { |
| @@ -165,20 +148,20 @@ static bool is_param_matching(zend_execute_data* execute_data, | |||
| 165 | return true; | 148 | return true; |
| 166 | } | 149 | } |
| 167 | } else if (Z_TYPE_P(arg_value) == IS_ARRAY) { | 150 | } else if (Z_TYPE_P(arg_value) == IS_ARRAY) { |
| 168 | *arg_value_str = sp_convert_to_string(arg_value); | 151 | *arg_value_str = sp_zval_to_zend_string(arg_value); |
| 169 | if (config_node->key || config_node->r_key) { | 152 | if (config_node->key || config_node->r_key) { |
| 170 | if (sp_match_array_key(arg_value, config_node->key, | 153 | if (sp_match_array_key(arg_value, config_node->key, |
| 171 | config_node->r_key)) { | 154 | config_node->r_key)) { |
| 172 | return true; | 155 | return true; |
| 173 | } | 156 | } |
| 174 | } else if (sp_match_array_value(arg_value, config_node->value, | 157 | } else if (sp_match_array_value(arg_value, config_node->value, |
| 175 | config_node->value_r)) { | 158 | config_node->r_value)) { |
| 176 | return true; | 159 | return true; |
| 177 | } | 160 | } |
| 178 | } else { | 161 | } else { |
| 179 | *arg_value_str = sp_convert_to_string(arg_value); | 162 | *arg_value_str = sp_zval_to_zend_string(arg_value); |
| 180 | if (sp_match_value(*arg_value_str, config_node->value, | 163 | if (sp_match_value(*arg_value_str, config_node->value, |
| 181 | config_node->value_r)) { | 164 | config_node->r_value)) { |
| 182 | return true; | 165 | return true; |
| 183 | } | 166 | } |
| 184 | } | 167 | } |
| @@ -189,7 +172,7 @@ static bool is_param_matching(zend_execute_data* execute_data, | |||
| 189 | arg_value = sp_get_var_value(execute_data, config_node->param, true); | 172 | arg_value = sp_get_var_value(execute_data, config_node->param, true); |
| 190 | 173 | ||
| 191 | if (arg_value) { | 174 | if (arg_value) { |
| 192 | *arg_value_str = sp_convert_to_string(arg_value); | 175 | *arg_value_str = sp_zval_to_zend_string(arg_value); |
| 193 | if (config_node->param_type) { // Are we matching on the `type`? | 176 | if (config_node->param_type) { // Are we matching on the `type`? |
| 194 | if (config_node->param_type == Z_TYPE_P(arg_value)) { | 177 | if (config_node->param_type == Z_TYPE_P(arg_value)) { |
| 195 | return true; | 178 | return true; |
| @@ -201,11 +184,11 @@ static bool is_param_matching(zend_execute_data* execute_data, | |||
| 201 | return true; | 184 | return true; |
| 202 | } | 185 | } |
| 203 | } else if (sp_match_array_value(arg_value, config_node->value, | 186 | } else if (sp_match_array_value(arg_value, config_node->value, |
| 204 | config_node->value_r)) { | 187 | config_node->r_value)) { |
| 205 | return true; | 188 | return true; |
| 206 | } | 189 | } |
| 207 | } else if (sp_match_value(*arg_value_str, config_node->value, | 190 | } else if (sp_match_value(*arg_value_str, config_node->value, |
| 208 | config_node->value_r)) { | 191 | config_node->r_value)) { |
| 209 | return true; | 192 | return true; |
| 210 | } | 193 | } |
| 211 | } | 194 | } |
| @@ -216,7 +199,7 @@ static bool is_param_matching(zend_execute_data* execute_data, | |||
| 216 | static zend_execute_data* is_file_matching( | 199 | static zend_execute_data* is_file_matching( |
| 217 | zend_execute_data* const execute_data, | 200 | zend_execute_data* const execute_data, |
| 218 | sp_disabled_function const* const config_node, | 201 | sp_disabled_function const* const config_node, |
| 219 | char const* const current_filename) { | 202 | zend_string const* const current_filename) { |
| 220 | #define ITERATE(ex) \ | 203 | #define ITERATE(ex) \ |
| 221 | ex = ex->prev_execute_data; \ | 204 | ex = ex->prev_execute_data; \ |
| 222 | while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) \ | 205 | while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) \ |
| @@ -225,22 +208,21 @@ static zend_execute_data* is_file_matching( | |||
| 225 | 208 | ||
| 226 | zend_execute_data* ex = execute_data; | 209 | zend_execute_data* ex = execute_data; |
| 227 | if (config_node->filename) { | 210 | if (config_node->filename) { |
| 228 | if (0 == strcmp(current_filename, config_node->filename)) { | 211 | if (zend_string_equals_literal(current_filename, config_node->filename)) { |
| 229 | return ex; | 212 | return ex; |
| 230 | } | 213 | } |
| 231 | ITERATE(ex); | 214 | ITERATE(ex); |
| 232 | if (0 == | 215 | if (zend_string_equals_literal(ex->func->op_array.filename, |
| 233 | strcmp(ZSTR_VAL(ex->func->op_array.filename), config_node->filename)) { | 216 | config_node->filename)) { |
| 234 | return ex; | 217 | return ex; |
| 235 | } | 218 | } |
| 236 | } else if (config_node->r_filename) { | 219 | } else if (config_node->r_filename) { |
| 237 | if (true == | 220 | if (sp_is_regexp_matching_zend(config_node->r_filename, current_filename)) { |
| 238 | sp_is_regexp_matching(config_node->r_filename, current_filename)) { | ||
| 239 | return ex; | 221 | return ex; |
| 240 | } | 222 | } |
| 241 | ITERATE(ex); | 223 | ITERATE(ex); |
| 242 | if (true == sp_is_regexp_matching(config_node->r_filename, | 224 | if (sp_is_regexp_matching_zend(config_node->r_filename, |
| 243 | ZSTR_VAL(ex->func->op_array.filename))) { | 225 | ex->func->op_array.filename)) { |
| 244 | return ex; | 226 | return ex; |
| 245 | } | 227 | } |
| 246 | } | 228 | } |
| @@ -251,10 +233,10 @@ static zend_execute_data* is_file_matching( | |||
| 251 | static bool check_is_builtin_name( | 233 | static bool check_is_builtin_name( |
| 252 | sp_disabled_function const* const config_node) { | 234 | sp_disabled_function const* const config_node) { |
| 253 | if (config_node->function) { | 235 | if (config_node->function) { |
| 254 | return (!strcmp(config_node->function, "include") || | 236 | return (zend_string_equals_literal(config_node->function, "include") || |
| 255 | !strcmp(config_node->function, "include_once") || | 237 | zend_string_equals_literal(config_node->function, "include_once") || |
| 256 | !strcmp(config_node->function, "require") || | 238 | zend_string_equals_literal(config_node->function, "require") || |
| 257 | !strcmp(config_node->function, "require_once")); | 239 | zend_string_equals_literal(config_node->function, "require_once")); |
| 258 | } | 240 | } |
| 259 | if (config_node->r_function) { | 241 | if (config_node->r_function) { |
| 260 | return (sp_is_regexp_matching(config_node->r_function, "include") || | 242 | return (sp_is_regexp_matching(config_node->r_function, "include") || |
| @@ -265,43 +247,67 @@ static bool check_is_builtin_name( | |||
| 265 | return false; | 247 | return false; |
| 266 | } | 248 | } |
| 267 | 249 | ||
| 268 | bool should_disable(zend_execute_data* execute_data, const char* builtin_name, | 250 | bool should_disable_ht(zend_execute_data* execute_data, |
| 269 | const char* builtin_param, const char* builtin_param_name) { | 251 | const char* builtin_name, |
| 270 | char current_file_hash[SHA256_SIZE * 2 + 1] = {0}; | 252 | const zend_string* builtin_param, |
| 271 | const sp_list_node* config = get_config_node(builtin_name); | 253 | const char* builtin_param_name, |
| 272 | char* complete_path_function = NULL; | 254 | const sp_list_node* config, const HashTable* ht) { |
| 273 | const char* current_filename = NULL; | 255 | char* complete_function_path = NULL; |
| 274 | unsigned int line = 0; | 256 | const sp_list_node* ht_entry = NULL; |
| 275 | char* filename = NULL; | 257 | bool ret = false; |
| 258 | zend_string* current_filename; | ||
| 276 | 259 | ||
| 277 | if (!execute_data) { | 260 | if (!execute_data) { |
| 278 | return false; | 261 | return false; |
| 279 | } | 262 | } |
| 280 | 263 | ||
| 281 | if (!config || !config->data) { | 264 | if (builtin_name) { |
| 282 | return false; | 265 | complete_function_path = estrdup(builtin_name); |
| 266 | } else { | ||
| 267 | complete_function_path = get_complete_function_path(execute_data); | ||
| 268 | if (!complete_function_path) { | ||
| 269 | return false; | ||
| 270 | } | ||
| 283 | } | 271 | } |
| 284 | 272 | ||
| 285 | if (UNEXPECTED(builtin_name && !strcmp(builtin_name, "eval"))) { | 273 | if (UNEXPECTED(builtin_param && !strcmp(complete_function_path, "eval"))) { |
| 286 | current_filename = get_eval_filename(zend_get_executed_filename()); | 274 | current_filename = get_eval_filename(zend_get_executed_filename()); |
| 287 | } else { | 275 | } else { |
| 288 | current_filename = zend_get_executed_filename(); | 276 | const char* tmp = zend_get_executed_filename(); |
| 277 | current_filename = zend_string_init(tmp, strlen(tmp), 0); | ||
| 289 | } | 278 | } |
| 290 | 279 | ||
| 291 | complete_path_function = get_complete_function_path(execute_data); | 280 | ht_entry = zend_hash_str_find_ptr(ht, complete_function_path, |
| 292 | if (!complete_path_function) { | 281 | strlen(complete_function_path)); |
| 293 | if (builtin_name) { | 282 | |
| 294 | complete_path_function = estrdup(builtin_name); | 283 | if (ht_entry && |
| 295 | } else { | 284 | should_disable(execute_data, complete_function_path, builtin_param, |
| 296 | return false; | 285 | builtin_param_name, ht_entry, current_filename)) { |
| 297 | } | 286 | ret = true; |
| 287 | } else if (config && config->data) { | ||
| 288 | ret = should_disable(execute_data, complete_function_path, builtin_param, | ||
| 289 | builtin_param_name, config, current_filename); | ||
| 298 | } | 290 | } |
| 299 | 291 | ||
| 292 | efree(complete_function_path); | ||
| 293 | efree(current_filename); | ||
| 294 | return ret; | ||
| 295 | } | ||
| 296 | |||
| 297 | bool should_disable(zend_execute_data* execute_data, | ||
| 298 | const char* complete_function_path, | ||
| 299 | const zend_string* builtin_param, | ||
| 300 | const char* builtin_param_name, const sp_list_node* config, | ||
| 301 | const zend_string* current_filename) { | ||
| 302 | char current_file_hash[SHA256_SIZE * 2 + 1] = {0}; | ||
| 303 | unsigned int line = 0; | ||
| 304 | char* filename = NULL; | ||
| 305 | |||
| 300 | while (config) { | 306 | while (config) { |
| 301 | sp_disabled_function const* const config_node = | 307 | sp_disabled_function const* const config_node = |
| 302 | (sp_disabled_function*)(config->data); | 308 | (sp_disabled_function*)(config->data); |
| 303 | const char* arg_name = NULL; | 309 | const char* arg_name = NULL; |
| 304 | const char* arg_value_str = NULL; | 310 | const zend_string* arg_value_str = NULL; |
| 305 | 311 | ||
| 306 | /* The order matters, since when we have `config_node->functions_list`, | 312 | /* The order matters, since when we have `config_node->functions_list`, |
| 307 | we also do have `config_node->function` */ | 313 | we also do have `config_node->function` */ |
| @@ -311,12 +317,13 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name, | |||
| 311 | goto next; | 317 | goto next; |
| 312 | } | 318 | } |
| 313 | } else if (config_node->function) { | 319 | } else if (config_node->function) { |
| 314 | if (0 != strcmp(config_node->function, complete_path_function)) { | 320 | if (0 != |
| 321 | strcmp(ZSTR_VAL(config_node->function), complete_function_path)) { | ||
| 315 | goto next; | 322 | goto next; |
| 316 | } | 323 | } |
| 317 | } else if (config_node->r_function) { | 324 | } else if (config_node->r_function) { |
| 318 | if (false == sp_is_regexp_matching(config_node->r_function, | 325 | if (false == sp_is_regexp_matching(config_node->r_function, |
| 319 | complete_path_function)) { | 326 | complete_function_path)) { |
| 320 | goto next; | 327 | goto next; |
| 321 | } | 328 | } |
| 322 | } | 329 | } |
| @@ -350,9 +357,10 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name, | |||
| 350 | 357 | ||
| 351 | if (config_node->hash) { | 358 | if (config_node->hash) { |
| 352 | if ('\0' == current_file_hash[0]) { | 359 | if ('\0' == current_file_hash[0]) { |
| 353 | compute_hash(current_filename, current_file_hash); | 360 | compute_hash(ZSTR_VAL(current_filename), current_file_hash); |
| 354 | } | 361 | } |
| 355 | if (0 != strncmp(current_file_hash, config_node->hash, SHA256_SIZE)) { | 362 | if (0 != strncmp(current_file_hash, ZSTR_VAL(config_node->hash), |
| 363 | SHA256_SIZE)) { | ||
| 356 | goto next; | 364 | goto next; |
| 357 | } | 365 | } |
| 358 | } | 366 | } |
| @@ -360,25 +368,25 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name, | |||
| 360 | /* Check if we filter on parameter value*/ | 368 | /* Check if we filter on parameter value*/ |
| 361 | if (config_node->param || config_node->r_param || | 369 | if (config_node->param || config_node->r_param || |
| 362 | (config_node->pos != -1)) { | 370 | (config_node->pos != -1)) { |
| 363 | if (!builtin_name && execute_data->func->op_array.arg_info->is_variadic) { | 371 | if (!builtin_param && |
| 372 | execute_data->func->op_array.arg_info->is_variadic) { | ||
| 364 | sp_log_err( | 373 | sp_log_err( |
| 365 | "disable_function", | 374 | "disable_function", |
| 366 | "Snuffleupagus doesn't support variadic functions yet, sorry. " | 375 | "Snuffleupagus doesn't support variadic functions yet, sorry. " |
| 367 | "Check https://github.com/nbs-system/snuffleupagus/issues/164 for " | 376 | "Check https://github.com/nbs-system/snuffleupagus/issues/164 for " |
| 368 | "details."); | 377 | "details."); |
| 369 | } else if (false == is_param_matching(execute_data, config_node, | 378 | } else if (false == is_param_matching( |
| 370 | builtin_name, builtin_param, | 379 | execute_data, config_node, builtin_param, |
| 371 | &arg_name, builtin_param_name, | 380 | &arg_name, builtin_param_name, &arg_value_str)) { |
| 372 | &arg_value_str)) { | ||
| 373 | goto next; | 381 | goto next; |
| 374 | } | 382 | } |
| 375 | } | 383 | } |
| 376 | 384 | ||
| 377 | if (config_node->value_r || config_node->value) { | 385 | if (config_node->r_value || config_node->value) { |
| 378 | if (check_is_builtin_name(config_node)) { | 386 | if (check_is_builtin_name(config_node)) { |
| 379 | if (false == is_param_matching(execute_data, config_node, builtin_name, | 387 | if (false == is_param_matching(execute_data, config_node, builtin_param, |
| 380 | builtin_param, &arg_name, | 388 | &arg_name, builtin_param_name, |
| 381 | builtin_param_name, &arg_value_str)) { | 389 | &arg_value_str)) { |
| 382 | goto next; | 390 | goto next; |
| 383 | } | 391 | } |
| 384 | } | 392 | } |
| @@ -390,63 +398,76 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name, | |||
| 390 | } | 398 | } |
| 391 | 399 | ||
| 392 | if (config_node->functions_list) { | 400 | if (config_node->functions_list) { |
| 393 | sp_log_disable(config_node->function, arg_name, arg_value_str, | 401 | sp_log_disable(ZSTR_VAL(config_node->function), arg_name, arg_value_str, |
| 394 | config_node, line, filename); | 402 | config_node, line, filename); |
| 395 | } else { | 403 | } else { |
| 396 | sp_log_disable(complete_path_function, arg_name, arg_value_str, | 404 | sp_log_disable(complete_function_path, arg_name, arg_value_str, |
| 397 | config_node, line, filename); | 405 | config_node, line, filename); |
| 398 | } | 406 | } |
| 399 | if (true == config_node->simulation) { | 407 | if (true == config_node->simulation) { |
| 400 | goto next; | 408 | goto next; |
| 401 | } else { // We've got a match, the function won't be executed | 409 | } else { // We've got a match, the function won't be executed |
| 402 | efree(complete_path_function); | ||
| 403 | return true; | 410 | return true; |
| 404 | } | 411 | } |
| 405 | next: | 412 | next: |
| 406 | config = config->next; | 413 | config = config->next; |
| 407 | } | 414 | } |
| 408 | allow: | 415 | allow: |
| 409 | efree(complete_path_function); | ||
| 410 | return false; | 416 | return false; |
| 411 | } | 417 | } |
| 412 | 418 | ||
| 413 | bool should_drop_on_ret(zval* return_value, | 419 | bool should_drop_on_ret_ht(zval* return_value, |
| 414 | const zend_execute_data* const execute_data) { | 420 | const zend_execute_data* const execute_data, |
| 415 | const sp_list_node* config = | 421 | const sp_list_node* config, const HashTable* ht) { |
| 416 | SNUFFLEUPAGUS_G(config).config_disabled_functions_ret->disabled_functions; | 422 | char* complete_function_path = get_complete_function_path(execute_data); |
| 417 | char* complete_path_function = get_complete_function_path(execute_data); | 423 | const sp_list_node* ht_entry = NULL; |
| 418 | const char* current_filename = zend_get_executed_filename(TSRMLS_C); | 424 | bool ret = false; |
| 419 | char current_file_hash[SHA256_SIZE * 2 + 1] = {0}; | ||
| 420 | bool match_type = false, match_value = false; | ||
| 421 | 425 | ||
| 422 | if (!complete_path_function) { | 426 | if (!complete_function_path) { |
| 423 | return false; | 427 | return ret; |
| 424 | } | 428 | } |
| 425 | 429 | ||
| 426 | if (!config || !config->data) { | 430 | ht_entry = zend_hash_str_find_ptr(ht, complete_function_path, |
| 427 | return false; | 431 | strlen(complete_function_path)); |
| 432 | |||
| 433 | if (ht_entry && | ||
| 434 | should_drop_on_ret(return_value, ht_entry, complete_function_path)) { | ||
| 435 | ret = true; | ||
| 436 | } else if (config && config->data) { | ||
| 437 | ret = should_drop_on_ret(return_value, config, complete_function_path); | ||
| 428 | } | 438 | } |
| 429 | 439 | ||
| 440 | efree(complete_function_path); | ||
| 441 | return ret; | ||
| 442 | } | ||
| 443 | |||
| 444 | bool should_drop_on_ret(zval* return_value, const sp_list_node* config, | ||
| 445 | const char* complete_function_path) { | ||
| 446 | const char* current_filename = zend_get_executed_filename(TSRMLS_C); | ||
| 447 | char current_file_hash[SHA256_SIZE * 2 + 1] = {0}; | ||
| 448 | bool match_type = false, match_value = false; | ||
| 449 | |||
| 430 | while (config) { | 450 | while (config) { |
| 431 | char* ret_value_str = NULL; | 451 | const zend_string* ret_value_str = NULL; |
| 432 | sp_disabled_function const* const config_node = | 452 | sp_disabled_function const* const config_node = |
| 433 | (sp_disabled_function*)(config->data); | 453 | (sp_disabled_function*)(config->data); |
| 434 | 454 | ||
| 435 | assert(config_node->function || config_node->r_function); | 455 | assert(config_node->function || config_node->r_function); |
| 436 | 456 | ||
| 437 | if (config_node->function) { | 457 | if (config_node->function) { |
| 438 | if (0 != strcmp(config_node->function, complete_path_function)) { | 458 | if (0 != |
| 459 | strcmp(ZSTR_VAL(config_node->function), complete_function_path)) { | ||
| 439 | goto next; | 460 | goto next; |
| 440 | } | 461 | } |
| 441 | } else if (config_node->r_function) { | 462 | } else if (config_node->r_function) { |
| 442 | if (false == sp_is_regexp_matching(config_node->r_function, | 463 | if (false == sp_is_regexp_matching(config_node->r_function, |
| 443 | complete_path_function)) { | 464 | complete_function_path)) { |
| 444 | goto next; | 465 | goto next; |
| 445 | } | 466 | } |
| 446 | } | 467 | } |
| 447 | 468 | ||
| 448 | if (config_node->filename) { /* Check the current file name. */ | 469 | if (config_node->filename) { /* Check the current file name. */ |
| 449 | if (0 != strcmp(current_filename, config_node->filename)) { | 470 | if (0 != strcmp(current_filename, ZSTR_VAL(config_node->filename))) { |
| 450 | goto next; | 471 | goto next; |
| 451 | } | 472 | } |
| 452 | } else if (config_node->r_filename) { | 473 | } else if (config_node->r_filename) { |
| @@ -460,12 +481,13 @@ bool should_drop_on_ret(zval* return_value, | |||
| 460 | if ('\0' == current_file_hash[0]) { | 481 | if ('\0' == current_file_hash[0]) { |
| 461 | compute_hash(current_filename, current_file_hash); | 482 | compute_hash(current_filename, current_file_hash); |
| 462 | } | 483 | } |
| 463 | if (0 != strncmp(current_file_hash, config_node->hash, SHA256_SIZE)) { | 484 | if (0 != strncmp(current_file_hash, ZSTR_VAL(config_node->hash), |
| 485 | SHA256_SIZE)) { | ||
| 464 | goto next; | 486 | goto next; |
| 465 | } | 487 | } |
| 466 | } | 488 | } |
| 467 | 489 | ||
| 468 | ret_value_str = sp_convert_to_string(return_value); | 490 | ret_value_str = sp_zval_to_zend_string(return_value); |
| 469 | 491 | ||
| 470 | match_type = (config_node->ret_type) && | 492 | match_type = (config_node->ret_type) && |
| 471 | (config_node->ret_type == Z_TYPE_P(return_value)); | 493 | (config_node->ret_type == Z_TYPE_P(return_value)); |
| @@ -475,22 +497,16 @@ bool should_drop_on_ret(zval* return_value, | |||
| 475 | 497 | ||
| 476 | if (true == match_type || true == match_value) { | 498 | if (true == match_type || true == match_value) { |
| 477 | if (true == config_node->allow) { | 499 | if (true == config_node->allow) { |
| 478 | efree(complete_path_function); | ||
| 479 | efree(ret_value_str); | ||
| 480 | return false; | 500 | return false; |
| 481 | } | 501 | } |
| 482 | sp_log_disable_ret(complete_path_function, ret_value_str, config_node); | 502 | sp_log_disable_ret(complete_function_path, ret_value_str, config_node); |
| 483 | if (false == config_node->simulation) { | 503 | if (false == config_node->simulation) { |
| 484 | efree(complete_path_function); | ||
| 485 | efree(ret_value_str); | ||
| 486 | return true; | 504 | return true; |
| 487 | } | 505 | } |
| 488 | } | 506 | } |
| 489 | next: | 507 | next: |
| 490 | efree(ret_value_str); | ||
| 491 | config = config->next; | 508 | config = config->next; |
| 492 | } | 509 | } |
| 493 | efree(complete_path_function); | ||
| 494 | return false; | 510 | return false; |
| 495 | } | 511 | } |
| 496 | 512 | ||
| @@ -498,7 +514,11 @@ ZEND_FUNCTION(check_disabled_function) { | |||
| 498 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); | 514 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); |
| 499 | const char* current_function_name = get_active_function_name(TSRMLS_C); | 515 | const char* current_function_name = get_active_function_name(TSRMLS_C); |
| 500 | 516 | ||
| 501 | if (true == should_disable(execute_data, NULL, NULL, NULL)) { | 517 | if (true == should_disable_ht( |
| 518 | execute_data, NULL, NULL, NULL, | ||
| 519 | SNUFFLEUPAGUS_G(config) | ||
| 520 | .config_disabled_functions_reg->disabled_functions, | ||
| 521 | SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked)) { | ||
| 502 | sp_terminate(); | 522 | sp_terminate(); |
| 503 | } | 523 | } |
| 504 | 524 | ||
| @@ -506,23 +526,29 @@ ZEND_FUNCTION(check_disabled_function) { | |||
| 506 | SNUFFLEUPAGUS_G(disabled_functions_hook), current_function_name, | 526 | SNUFFLEUPAGUS_G(disabled_functions_hook), current_function_name, |
| 507 | strlen(current_function_name)); | 527 | strlen(current_function_name)); |
| 508 | orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); | 528 | orig_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU); |
| 509 | if (true == should_drop_on_ret(return_value, execute_data)) { | 529 | if (true == |
| 530 | should_drop_on_ret_ht( | ||
| 531 | return_value, execute_data, | ||
| 532 | SNUFFLEUPAGUS_G(config) | ||
| 533 | .config_disabled_functions_reg_ret->disabled_functions, | ||
| 534 | SNUFFLEUPAGUS_G(config).config_disabled_functions_ret_hooked)) { | ||
| 510 | sp_terminate(); | 535 | sp_terminate(); |
| 511 | } | 536 | } |
| 512 | } | 537 | } |
| 513 | 538 | ||
| 514 | static int hook_functions(const sp_list_node* config) { | 539 | static int hook_functions_regexp(const sp_list_node* config) { |
| 515 | while (config && config->data) { | 540 | while (config && config->data) { |
| 516 | const char* function_name = ((sp_disabled_function*)config->data)->function; | 541 | const zend_string* function_name = |
| 542 | ((sp_disabled_function*)config->data)->function; | ||
| 517 | const sp_pcre* function_name_regexp = | 543 | const sp_pcre* function_name_regexp = |
| 518 | ((sp_disabled_function*)config->data)->r_function; | 544 | ((sp_disabled_function*)config->data)->r_function; |
| 519 | 545 | ||
| 520 | assert(function_name || function_name_regexp); | 546 | assert(function_name || function_name_regexp); |
| 521 | 547 | ||
| 522 | if (NULL != function_name) { // hook function by name | 548 | if (function_name) { |
| 523 | HOOK_FUNCTION(function_name, disabled_functions_hook, | 549 | HOOK_FUNCTION(ZSTR_VAL(function_name), disabled_functions_hook, |
| 524 | PHP_FN(check_disabled_function)); | 550 | PHP_FN(check_disabled_function)); |
| 525 | } else if (NULL != function_name_regexp) { // hook function by regexp | 551 | } else { |
| 526 | HOOK_FUNCTION_BY_REGEXP(function_name_regexp, disabled_functions_hook, | 552 | HOOK_FUNCTION_BY_REGEXP(function_name_regexp, disabled_functions_hook, |
| 527 | PHP_FN(check_disabled_function)); | 553 | PHP_FN(check_disabled_function)); |
| 528 | } | 554 | } |
| @@ -532,16 +558,36 @@ static int hook_functions(const sp_list_node* config) { | |||
| 532 | return SUCCESS; | 558 | return SUCCESS; |
| 533 | } | 559 | } |
| 534 | 560 | ||
| 561 | static int hook_functions(HashTable* to_hook_ht, HashTable* hooked_ht) { | ||
| 562 | zend_string* key; | ||
| 563 | zval* value; | ||
| 564 | |||
| 565 | ZEND_HASH_FOREACH_STR_KEY_VAL(to_hook_ht, key, value) { | ||
| 566 | if (!HOOK_FUNCTION(ZSTR_VAL(key), disabled_functions_hook, | ||
| 567 | PHP_FN(check_disabled_function)) || | ||
| 568 | check_is_builtin_name(((sp_list_node*)Z_PTR_P(value))->data)) { | ||
| 569 | zend_symtable_add_new(hooked_ht, key, value); | ||
| 570 | zend_hash_del(to_hook_ht, key); | ||
| 571 | } | ||
| 572 | } | ||
| 573 | ZEND_HASH_FOREACH_END(); | ||
| 574 | return SUCCESS; | ||
| 575 | } | ||
| 576 | |||
| 535 | ZEND_FUNCTION(eval_blacklist_callback) { | 577 | ZEND_FUNCTION(eval_blacklist_callback) { |
| 536 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); | 578 | void (*orig_handler)(INTERNAL_FUNCTION_PARAMETERS); |
| 537 | const char* current_function_name = get_active_function_name(TSRMLS_C); | 579 | const char* current_function_name = get_active_function_name(TSRMLS_C); |
| 580 | zend_string* tmp = | ||
| 581 | zend_string_init(current_function_name, strlen(current_function_name), 0); | ||
| 538 | 582 | ||
| 539 | if (true == check_is_in_eval_whitelist(current_function_name)) { | 583 | if (true == check_is_in_eval_whitelist(tmp)) { |
| 584 | zend_string_release(tmp); | ||
| 540 | goto whitelisted; | 585 | goto whitelisted; |
| 541 | } | 586 | } |
| 587 | zend_string_release(tmp); | ||
| 542 | 588 | ||
| 543 | if (SNUFFLEUPAGUS_G(in_eval) > 0) { | 589 | if (SNUFFLEUPAGUS_G(in_eval) > 0) { |
| 544 | char* filename = get_eval_filename(zend_get_executed_filename()); | 590 | zend_string* filename = get_eval_filename(zend_get_executed_filename()); |
| 545 | const int line_number = zend_get_executed_lineno(TSRMLS_C); | 591 | const int line_number = zend_get_executed_lineno(TSRMLS_C); |
| 546 | if (SNUFFLEUPAGUS_G(config).config_eval->dump) { | 592 | if (SNUFFLEUPAGUS_G(config).config_eval->dump) { |
| 547 | sp_log_request( | 593 | sp_log_request( |
| @@ -549,14 +595,14 @@ ZEND_FUNCTION(eval_blacklist_callback) { | |||
| 549 | SNUFFLEUPAGUS_G(config).config_eval->textual_representation, | 595 | SNUFFLEUPAGUS_G(config).config_eval->textual_representation, |
| 550 | SP_TOKEN_EVAL_BLACKLIST); | 596 | SP_TOKEN_EVAL_BLACKLIST); |
| 551 | } | 597 | } |
| 552 | if (1 == SNUFFLEUPAGUS_G(config).config_eval->simulation) { | 598 | if (SNUFFLEUPAGUS_G(config).config_eval->simulation) { |
| 553 | sp_log_msg("eval", SP_LOG_SIMULATION, | 599 | sp_log_msg("eval", SP_LOG_SIMULATION, |
| 554 | "A call to %s was tried in eval, in %s:%d, logging it.", | 600 | "A call to %s was tried in eval, in %s:%d, logging it.", |
| 555 | current_function_name, filename, line_number); | 601 | current_function_name, ZSTR_VAL(filename), line_number); |
| 556 | } else { | 602 | } else { |
| 557 | sp_log_msg("eval", SP_LOG_DROP, | 603 | sp_log_msg("eval", SP_LOG_DROP, |
| 558 | "A call to %s was tried in eval, in %s:%d, dropping it.", | 604 | "A call to %s was tried in eval, in %s:%d, dropping it.", |
| 559 | current_function_name, filename, line_number); | 605 | current_function_name, ZSTR_VAL(filename), line_number); |
| 560 | sp_terminate(); | 606 | sp_terminate(); |
| 561 | } | 607 | } |
| 562 | efree(filename); | 608 | efree(filename); |
| @@ -574,21 +620,31 @@ int hook_disabled_functions(void) { | |||
| 574 | 620 | ||
| 575 | int ret = SUCCESS; | 621 | int ret = SUCCESS; |
| 576 | 622 | ||
| 623 | ret |= | ||
| 624 | hook_functions(SNUFFLEUPAGUS_G(config).config_disabled_functions, | ||
| 625 | SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked); | ||
| 626 | |||
| 577 | ret |= hook_functions( | 627 | ret |= hook_functions( |
| 578 | SNUFFLEUPAGUS_G(config).config_disabled_functions->disabled_functions); | 628 | SNUFFLEUPAGUS_G(config).config_disabled_functions_ret, |
| 579 | ret |= hook_functions(SNUFFLEUPAGUS_G(config) | 629 | SNUFFLEUPAGUS_G(config).config_disabled_functions_ret_hooked); |
| 580 | .config_disabled_functions_ret->disabled_functions); | 630 | |
| 631 | ret |= hook_functions_regexp( | ||
| 632 | SNUFFLEUPAGUS_G(config) | ||
| 633 | .config_disabled_functions_reg->disabled_functions); | ||
| 634 | |||
| 635 | ret |= hook_functions_regexp( | ||
| 636 | SNUFFLEUPAGUS_G(config) | ||
| 637 | .config_disabled_functions_reg_ret->disabled_functions); | ||
| 581 | 638 | ||
| 582 | if (NULL != SNUFFLEUPAGUS_G(config).config_eval->blacklist) { | 639 | if (NULL != SNUFFLEUPAGUS_G(config).config_eval->blacklist) { |
| 583 | sp_list_node* it = SNUFFLEUPAGUS_G(config).config_eval->blacklist; | 640 | sp_list_node* it = SNUFFLEUPAGUS_G(config).config_eval->blacklist; |
| 584 | 641 | ||
| 585 | while (it) { | 642 | while (it) { |
| 586 | hook_function((char*)it->data, | 643 | hook_function(ZSTR_VAL((zend_string*)it->data), |
| 587 | SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook), | 644 | SNUFFLEUPAGUS_G(sp_eval_blacklist_functions_hook), |
| 588 | PHP_FN(eval_blacklist_callback)); | 645 | PHP_FN(eval_blacklist_callback)); |
| 589 | it = it->next; | 646 | it = it->next; |
| 590 | } | 647 | } |
| 591 | } | 648 | } |
| 592 | |||
| 593 | return ret; | 649 | return ret; |
| 594 | } | 650 | } |
diff --git a/src/sp_disabled_functions.h b/src/sp_disabled_functions.h index f80c9c2..4e795a1 100644 --- a/src/sp_disabled_functions.h +++ b/src/sp_disabled_functions.h | |||
| @@ -2,8 +2,11 @@ | |||
| 2 | #define __SP_DISABLE_FUNCTIONS_H | 2 | #define __SP_DISABLE_FUNCTIONS_H |
| 3 | 3 | ||
| 4 | int hook_disabled_functions(); | 4 | int hook_disabled_functions(); |
| 5 | bool should_disable(zend_execute_data *, const char *, const char *, | 5 | bool should_disable(zend_execute_data *, const char *, const zend_string *, |
| 6 | const char *); | 6 | const char *, const sp_list_node *, const zend_string *); |
| 7 | bool should_drop_on_ret(zval *, const zend_execute_data *const); | 7 | bool should_disable_ht(zend_execute_data *, const char *, const zend_string *, |
| 8 | const char *, const sp_list_node *, const HashTable *); | ||
| 9 | bool should_drop_on_ret_ht(zval *, const zend_execute_data *const, const sp_list_node* config, const HashTable *); | ||
| 10 | bool should_drop_on_ret(zval *, const sp_list_node* config, const char *); | ||
| 8 | 11 | ||
| 9 | #endif /* __SP_DISABLE_FUNCTIONS_H */ | 12 | #endif /* __SP_DISABLE_FUNCTIONS_H */ |
diff --git a/src/sp_execute.c b/src/sp_execute.c index fb956ca..6e38c75 100644 --- a/src/sp_execute.c +++ b/src/sp_execute.c | |||
| @@ -36,16 +36,21 @@ ZEND_COLD static inline void terminate_if_writable(const char *filename) { | |||
| 36 | } | 36 | } |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | inline static void is_builtin_matching(const char *restrict const filename, | 39 | inline static void is_builtin_matching( |
| 40 | const char *restrict const function_name, | 40 | const zend_string *restrict const param_value, |
| 41 | const char *restrict const param_name, | 41 | const char *restrict const function_name, |
| 42 | const sp_list_node *config) { | 42 | const char *restrict const param_name, const sp_list_node *config, |
| 43 | const HashTable *ht) { | ||
| 43 | if (!config || !config->data) { | 44 | if (!config || !config->data) { |
| 44 | return; | 45 | return; |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | if (true == should_disable(EG(current_execute_data), function_name, filename, | 48 | if (true == |
| 48 | param_name)) { | 49 | should_disable_ht(EG(current_execute_data), function_name, param_value, |
| 50 | param_name, | ||
| 51 | SNUFFLEUPAGUS_G(config) | ||
| 52 | .config_disabled_functions_reg->disabled_functions, | ||
| 53 | ht)) { | ||
| 49 | sp_terminate(); | 54 | sp_terminate(); |
| 50 | } | 55 | } |
| 51 | } | 56 | } |
| @@ -70,7 +75,7 @@ is_in_eval_and_whitelisted(const zend_execute_data *execute_data) { | |||
| 70 | return; | 75 | return; |
| 71 | } | 76 | } |
| 72 | 77 | ||
| 73 | char const *const current_function = ZSTR_VAL(EX(func)->common.function_name); | 78 | zend_string const *const current_function = EX(func)->common.function_name; |
| 74 | 79 | ||
| 75 | if (EXPECTED(NULL != current_function)) { | 80 | if (EXPECTED(NULL != current_function)) { |
| 76 | if (UNEXPECTED(false == check_is_in_eval_whitelist(current_function))) { | 81 | if (UNEXPECTED(false == check_is_in_eval_whitelist(current_function))) { |
| @@ -84,13 +89,13 @@ is_in_eval_and_whitelisted(const zend_execute_data *execute_data) { | |||
| 84 | sp_log_msg( | 89 | sp_log_msg( |
| 85 | "Eval_whitelist", SP_LOG_SIMULATION, | 90 | "Eval_whitelist", SP_LOG_SIMULATION, |
| 86 | "The function '%s' isn't in the eval whitelist, logging its call.", | 91 | "The function '%s' isn't in the eval whitelist, logging its call.", |
| 87 | current_function); | 92 | ZSTR_VAL(current_function)); |
| 88 | return; | 93 | return; |
| 89 | } else { | 94 | } else { |
| 90 | sp_log_msg( | 95 | sp_log_msg( |
| 91 | "Eval_whitelist", SP_LOG_DROP, | 96 | "Eval_whitelist", SP_LOG_DROP, |
| 92 | "The function '%s' isn't in the eval whitelist, dropping its call.", | 97 | "The function '%s' isn't in the eval whitelist, dropping its call.", |
| 93 | current_function); | 98 | ZSTR_VAL(current_function)); |
| 94 | sp_terminate(); | 99 | sp_terminate(); |
| 95 | } | 100 | } |
| 96 | } | 101 | } |
| @@ -100,15 +105,15 @@ is_in_eval_and_whitelisted(const zend_execute_data *execute_data) { | |||
| 100 | /* This function gets the filename in which `eval()` is called from, | 105 | /* This function gets the filename in which `eval()` is called from, |
| 101 | * since it looks like "foo.php(1) : eval()'d code", so we're starting | 106 | * since it looks like "foo.php(1) : eval()'d code", so we're starting |
| 102 | * from the end of the string until the second closing parenthesis. */ | 107 | * from the end of the string until the second closing parenthesis. */ |
| 103 | char *get_eval_filename(const char *const filename) { | 108 | zend_string *get_eval_filename(const char *const filename) { |
| 104 | size_t i = strlen(filename); | ||
| 105 | int count = 0; | 109 | int count = 0; |
| 106 | char *clean_filename = estrdup(filename); | 110 | zend_string *clean_filename = zend_string_init(filename, strlen(filename), 0); |
| 107 | 111 | ||
| 108 | while (i--) { | 112 | for (int i = ZSTR_LEN(clean_filename); i >= 0; i--) { |
| 109 | if (clean_filename[i] == '(') { | 113 | if (ZSTR_VAL(clean_filename)[i] == '(') { |
| 110 | if (count == 1) { | 114 | if (count == 1) { |
| 111 | clean_filename[i] = '\0'; | 115 | ZSTR_VAL(clean_filename)[i] = '\0'; |
| 116 | clean_filename = zend_string_truncate(clean_filename, i, 0); | ||
| 112 | break; | 117 | break; |
| 113 | } | 118 | } |
| 114 | count++; | 119 | count++; |
| @@ -125,11 +130,12 @@ static void sp_execute_ex(zend_execute_data *execute_data) { | |||
| 125 | } | 130 | } |
| 126 | 131 | ||
| 127 | if (UNEXPECTED(EX(func)->op_array.type == ZEND_EVAL_CODE)) { | 132 | if (UNEXPECTED(EX(func)->op_array.type == ZEND_EVAL_CODE)) { |
| 128 | const sp_list_node *config = | 133 | const sp_list_node *config = zend_hash_str_find_ptr( |
| 129 | SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_eval; | 134 | SNUFFLEUPAGUS_G(config).config_disabled_functions, "eval", 4); |
| 130 | char *filename = get_eval_filename((char *)zend_get_executed_filename()); | 135 | zend_string *filename = get_eval_filename(zend_get_executed_filename()); |
| 131 | is_builtin_matching(filename, "eval", NULL, config); | 136 | is_builtin_matching(filename, "eval", NULL, config, |
| 132 | efree(filename); | 137 | SNUFFLEUPAGUS_G(config).config_disabled_functions); |
| 138 | zend_string_release(filename); | ||
| 133 | 139 | ||
| 134 | SNUFFLEUPAGUS_G(in_eval)++; | 140 | SNUFFLEUPAGUS_G(in_eval)++; |
| 135 | orig_execute_ex(execute_data); | 141 | orig_execute_ex(execute_data); |
| @@ -137,34 +143,54 @@ static void sp_execute_ex(zend_execute_data *execute_data) { | |||
| 137 | return; | 143 | return; |
| 138 | } | 144 | } |
| 139 | 145 | ||
| 140 | if (!execute_data->prev_execute_data || | ||
| 141 | !execute_data->prev_execute_data->func || | ||
| 142 | !ZEND_USER_CODE(execute_data->prev_execute_data->func->type) || | ||
| 143 | !execute_data->prev_execute_data->opline) { | ||
| 144 | if (UNEXPECTED(true == should_disable(execute_data, NULL, NULL, NULL))) { | ||
| 145 | sp_terminate(); | ||
| 146 | } | ||
| 147 | } else if ((execute_data->prev_execute_data->opline->opcode == | ||
| 148 | ZEND_DO_FCALL || | ||
| 149 | execute_data->prev_execute_data->opline->opcode == | ||
| 150 | ZEND_DO_UCALL || | ||
| 151 | execute_data->prev_execute_data->opline->opcode == | ||
| 152 | ZEND_DO_FCALL_BY_NAME)) { | ||
| 153 | if (UNEXPECTED(true == should_disable(execute_data, NULL, NULL, NULL))) { | ||
| 154 | sp_terminate(); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | if (NULL != EX(func)->op_array.filename) { | 146 | if (NULL != EX(func)->op_array.filename) { |
| 159 | if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { | 147 | if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { |
| 160 | terminate_if_writable(ZSTR_VAL(EX(func)->op_array.filename)); | 148 | terminate_if_writable(ZSTR_VAL(EX(func)->op_array.filename)); |
| 161 | } | 149 | } |
| 162 | } | 150 | } |
| 163 | 151 | ||
| 164 | orig_execute_ex(execute_data); | 152 | if (SNUFFLEUPAGUS_G(config).hook_execute) { |
| 153 | if (!execute_data->prev_execute_data || | ||
| 154 | !execute_data->prev_execute_data->func || | ||
| 155 | !ZEND_USER_CODE(execute_data->prev_execute_data->func->type) || | ||
| 156 | !execute_data->prev_execute_data->opline) { | ||
| 157 | if (UNEXPECTED(true == | ||
| 158 | should_disable_ht( | ||
| 159 | execute_data, NULL, NULL, NULL, | ||
| 160 | SNUFFLEUPAGUS_G(config) | ||
| 161 | .config_disabled_functions_reg->disabled_functions, | ||
| 162 | SNUFFLEUPAGUS_G(config).config_disabled_functions))) { | ||
| 163 | sp_terminate(); | ||
| 164 | } | ||
| 165 | } else if ((execute_data->prev_execute_data->opline->opcode == | ||
| 166 | ZEND_DO_FCALL || | ||
| 167 | execute_data->prev_execute_data->opline->opcode == | ||
| 168 | ZEND_DO_UCALL || | ||
| 169 | execute_data->prev_execute_data->opline->opcode == | ||
| 170 | ZEND_DO_FCALL_BY_NAME)) { | ||
| 171 | if (UNEXPECTED(true == | ||
| 172 | should_disable_ht( | ||
| 173 | execute_data, NULL, NULL, NULL, | ||
| 174 | SNUFFLEUPAGUS_G(config) | ||
| 175 | .config_disabled_functions_reg->disabled_functions, | ||
| 176 | SNUFFLEUPAGUS_G(config).config_disabled_functions))) { | ||
| 177 | sp_terminate(); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | orig_execute_ex(execute_data); | ||
| 165 | 182 | ||
| 166 | if (UNEXPECTED(true == should_drop_on_ret(EX(return_value), execute_data))) { | 183 | if (UNEXPECTED( |
| 167 | sp_terminate(); | 184 | true == |
| 185 | should_drop_on_ret_ht( | ||
| 186 | EX(return_value), execute_data, | ||
| 187 | SNUFFLEUPAGUS_G(config) | ||
| 188 | .config_disabled_functions_reg_ret->disabled_functions, | ||
| 189 | SNUFFLEUPAGUS_G(config).config_disabled_functions_ret))) { | ||
| 190 | sp_terminate(); | ||
| 191 | } | ||
| 192 | } else { | ||
| 193 | orig_execute_ex(execute_data); | ||
| 168 | } | 194 | } |
| 169 | } | 195 | } |
| 170 | 196 | ||
| @@ -186,31 +212,49 @@ static int sp_stream_open(const char *filename, zend_file_handle *handle) { | |||
| 186 | goto end; | 212 | goto end; |
| 187 | } | 213 | } |
| 188 | 214 | ||
| 215 | zend_string *zend_filename = zend_string_init(filename, strlen(filename), 0); | ||
| 189 | switch (data->opline->opcode) { | 216 | switch (data->opline->opcode) { |
| 190 | case ZEND_INCLUDE_OR_EVAL: | 217 | case ZEND_INCLUDE_OR_EVAL: |
| 191 | if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { | 218 | if (true == SNUFFLEUPAGUS_G(config).config_readonly_exec->enable) { |
| 192 | terminate_if_writable(filename); | 219 | terminate_if_writable(filename); |
| 193 | } | 220 | } |
| 194 | const sp_list_node *config = | ||
| 195 | SNUFFLEUPAGUS_G(config).config_disabled_constructs->construct_include; | ||
| 196 | switch (data->opline->extended_value) { | 221 | switch (data->opline->extended_value) { |
| 197 | case ZEND_INCLUDE: | 222 | case ZEND_INCLUDE: |
| 198 | is_builtin_matching(filename, "include", "inclusion path", config); | 223 | is_builtin_matching( |
| 224 | zend_filename, "include", "inclusion path", | ||
| 225 | zend_hash_str_find_ptr( | ||
| 226 | SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked, | ||
| 227 | "include", 7), | ||
| 228 | SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked); | ||
| 199 | break; | 229 | break; |
| 200 | case ZEND_REQUIRE: | 230 | case ZEND_REQUIRE: |
| 201 | is_builtin_matching(filename, "require", "inclusion path", config); | 231 | is_builtin_matching( |
| 232 | zend_filename, "require", "inclusion path", | ||
| 233 | zend_hash_str_find_ptr( | ||
| 234 | SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked, | ||
| 235 | "require", 7), | ||
| 236 | SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked); | ||
| 202 | break; | 237 | break; |
| 203 | case ZEND_REQUIRE_ONCE: | 238 | case ZEND_REQUIRE_ONCE: |
| 204 | is_builtin_matching(filename, "require_once", "inclusion path", | 239 | is_builtin_matching( |
| 205 | config); | 240 | zend_filename, "require_once", "inclusion path", |
| 241 | zend_hash_str_find_ptr( | ||
| 242 | SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked, | ||
| 243 | "require_once", 12), | ||
| 244 | SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked); | ||
| 206 | break; | 245 | break; |
| 207 | case ZEND_INCLUDE_ONCE: | 246 | case ZEND_INCLUDE_ONCE: |
| 208 | is_builtin_matching(filename, "include_once", "inclusion path", | 247 | is_builtin_matching( |
| 209 | config); | 248 | zend_filename, "include_once", "inclusion path", |
| 249 | zend_hash_str_find_ptr( | ||
| 250 | SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked, | ||
| 251 | "include_once", 12), | ||
| 252 | SNUFFLEUPAGUS_G(config).config_disabled_functions_hooked); | ||
| 210 | break; | 253 | break; |
| 211 | EMPTY_SWITCH_DEFAULT_CASE(); | 254 | EMPTY_SWITCH_DEFAULT_CASE(); |
| 212 | } | 255 | } |
| 213 | } | 256 | } |
| 257 | efree(zend_filename); | ||
| 214 | 258 | ||
| 215 | end: | 259 | end: |
| 216 | return orig_zend_stream_open(filename, handle); | 260 | return orig_zend_stream_open(filename, handle); |
diff --git a/src/sp_execute.h b/src/sp_execute.h index fcd0e11..d9eeee8 100644 --- a/src/sp_execute.h +++ b/src/sp_execute.h | |||
| @@ -2,6 +2,6 @@ | |||
| 2 | #define SP_EXECUTE_H | 2 | #define SP_EXECUTE_H |
| 3 | 3 | ||
| 4 | int hook_execute(void); | 4 | int hook_execute(void); |
| 5 | char *get_eval_filename(const char * const filename); | 5 | zend_string *get_eval_filename(const char * const filename); |
| 6 | 6 | ||
| 7 | #endif /* SP_EXECUTE_H */ | 7 | #endif /* SP_EXECUTE_H */ |
diff --git a/src/sp_pcre_compat.h b/src/sp_pcre_compat.h index a9eb253..6658316 100644 --- a/src/sp_pcre_compat.h +++ b/src/sp_pcre_compat.h | |||
| @@ -27,6 +27,8 @@ | |||
| 27 | #endif | 27 | #endif |
| 28 | 28 | ||
| 29 | sp_pcre* sp_pcre_compile(const char* str); | 29 | sp_pcre* sp_pcre_compile(const char* str); |
| 30 | #define sp_is_regexp_matching_zend(regexp, zstr) \ | ||
| 31 | sp_is_regexp_matching_len(regexp, ZSTR_VAL(zstr), ZSTR_LEN(zstr)) | ||
| 30 | #define sp_is_regexp_matching(regexp, str) \ | 32 | #define sp_is_regexp_matching(regexp, str) \ |
| 31 | sp_is_regexp_matching_len(regexp, str, strlen(str)) | 33 | sp_is_regexp_matching_len(regexp, str, strlen(str)) |
| 32 | bool sp_is_regexp_matching_len(const sp_pcre* regexp, const char* str, size_t len); | 34 | bool sp_is_regexp_matching_len(const sp_pcre* regexp, const char* str, size_t len); |
diff --git a/src/sp_session.c b/src/sp_session.c index ce852ad..ea65f57 100644 --- a/src/sp_session.c +++ b/src/sp_session.c | |||
| @@ -51,7 +51,7 @@ static int sp_hook_s_read(PS_READ_ARGS) { | |||
| 51 | 51 | ||
| 52 | static int sp_hook_s_write(PS_WRITE_ARGS) { | 52 | static int sp_hook_s_write(PS_WRITE_ARGS) { |
| 53 | if (ZSTR_LEN(val) > 0 && SNUFFLEUPAGUS_G(config).config_session->encrypt) { | 53 | if (ZSTR_LEN(val) > 0 && SNUFFLEUPAGUS_G(config).config_session->encrypt) { |
| 54 | zend_string *new_val = encrypt_zval(ZSTR_VAL(val), ZSTR_LEN(val)); | 54 | zend_string *new_val = encrypt_zval(val); |
| 55 | return old_s_write(mod_data, key, new_val, maxlifetime); | 55 | return old_s_write(mod_data, key, new_val, maxlifetime); |
| 56 | } | 56 | } |
| 57 | return old_s_write(mod_data, key, val, maxlifetime); | 57 | return old_s_write(mod_data, key, val, maxlifetime); |
| @@ -150,4 +150,4 @@ void hook_session() { | |||
| 150 | s_module = NULL; | 150 | s_module = NULL; |
| 151 | 151 | ||
| 152 | sp_hook_session_module(); | 152 | sp_hook_session_module(); |
| 153 | } \ No newline at end of file | 153 | } |
diff --git a/src/sp_sloppy.c b/src/sp_sloppy.c index 05d2505..09e79d8 100644 --- a/src/sp_sloppy.c +++ b/src/sp_sloppy.c | |||
| @@ -1,7 +1,9 @@ | |||
| 1 | #include "sp_sloppy.h" | 1 | #include "sp_sloppy.h" |
| 2 | 2 | ||
| 3 | ZEND_API zend_op_array* (*zend_compile_file_default)(zend_file_handle* file_handle, int type) = NULL; | 3 | ZEND_API zend_op_array* (*zend_compile_file_default)( |
| 4 | ZEND_API zend_op_array* (*zend_compile_string_default)(zval* source_string, char* filename) = NULL; | 4 | zend_file_handle* file_handle, int type) = NULL; |
| 5 | ZEND_API zend_op_array* (*zend_compile_string_default)(zval* source_string, | ||
| 6 | char* filename) = NULL; | ||
| 5 | 7 | ||
| 6 | static void modify_opcode(zend_op_array* opline) { | 8 | static void modify_opcode(zend_op_array* opline) { |
| 7 | if (NULL != opline) { | 9 | if (NULL != opline) { |
| @@ -24,7 +26,8 @@ ZEND_API zend_op_array* sp_compile_string(zval* source_string, char* filename) { | |||
| 24 | return opline; | 26 | return opline; |
| 25 | } | 27 | } |
| 26 | 28 | ||
| 27 | ZEND_API zend_op_array* sp_compile_file(zend_file_handle* file_handle, int type) { | 29 | ZEND_API zend_op_array* sp_compile_file(zend_file_handle* file_handle, |
| 30 | int type) { | ||
| 28 | zend_op_array* opline = zend_compile_file_default(file_handle, type); | 31 | zend_op_array* opline = zend_compile_file_default(file_handle, type); |
| 29 | modify_opcode(opline); | 32 | modify_opcode(opline); |
| 30 | return opline; | 33 | return opline; |
diff --git a/src/sp_unserialize.c b/src/sp_unserialize.c index 60ef7be..db99389 100644 --- a/src/sp_unserialize.c +++ b/src/sp_unserialize.c | |||
| @@ -18,8 +18,9 @@ PHP_FUNCTION(sp_serialize) { | |||
| 18 | ZVAL_STRING(&func_name, "hash_hmac"); | 18 | ZVAL_STRING(&func_name, "hash_hmac"); |
| 19 | ZVAL_STRING(¶ms[0], "sha256"); | 19 | ZVAL_STRING(¶ms[0], "sha256"); |
| 20 | params[1] = *return_value; | 20 | params[1] = *return_value; |
| 21 | ZVAL_STRING(¶ms[2], | 21 | ZVAL_STRING( |
| 22 | SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key); | 22 | ¶ms[2], |
| 23 | ZSTR_VAL(SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)); | ||
| 23 | call_user_function(CG(function_table), NULL, &func_name, &hmac, 3, params); | 24 | call_user_function(CG(function_table), NULL, &func_name, &hmac, 3, params); |
| 24 | 25 | ||
| 25 | size_t len = Z_STRLEN_P(return_value) + Z_STRLEN(hmac); | 26 | size_t len = Z_STRLEN_P(return_value) + Z_STRLEN(hmac); |
| @@ -66,8 +67,9 @@ PHP_FUNCTION(sp_unserialize) { | |||
| 66 | zval params[3]; | 67 | zval params[3]; |
| 67 | ZVAL_STRING(¶ms[0], "sha256"); | 68 | ZVAL_STRING(¶ms[0], "sha256"); |
| 68 | ZVAL_STRING(¶ms[1], serialized_str); | 69 | ZVAL_STRING(¶ms[1], serialized_str); |
| 69 | ZVAL_STRING(¶ms[2], | 70 | ZVAL_STRING( |
| 70 | SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key); | 71 | ¶ms[2], |
| 72 | ZSTR_VAL(SNUFFLEUPAGUS_G(config).config_snuffleupagus->encryption_key)); | ||
| 71 | call_user_function(CG(function_table), NULL, &func_name, &expected_hmac, 3, | 73 | call_user_function(CG(function_table), NULL, &func_name, &expected_hmac, 3, |
| 72 | params); | 74 | params); |
| 73 | 75 | ||
| @@ -113,4 +115,4 @@ int hook_serialize(void) { | |||
| 113 | PHP_FN(sp_unserialize)); | 115 | PHP_FN(sp_unserialize)); |
| 114 | 116 | ||
| 115 | return SUCCESS; | 117 | return SUCCESS; |
| 116 | } \ No newline at end of file | 118 | } |
diff --git a/src/sp_upload_validation.c b/src/sp_upload_validation.c index 73244ae..794c61f 100644 --- a/src/sp_upload_validation.c +++ b/src/sp_upload_validation.c | |||
| @@ -41,12 +41,14 @@ int sp_rfc1867_callback(unsigned int event, void *event_data, void **extra) { | |||
| 41 | char *cmd[3] = {0}; | 41 | char *cmd[3] = {0}; |
| 42 | char *env[5] = {0}; | 42 | char *env[5] = {0}; |
| 43 | 43 | ||
| 44 | sp_log_debug("Filename: %s\nTmpname: %s\nSize: %d\nError: %d\nScript: %s", | 44 | sp_log_debug( |
| 45 | filename, tmp_name, filesize, | 45 | "Filename: %s\nTmpname: %s\nSize: %d\nError: %d\nScript: %s", |
| 46 | Z_LVAL_P(zend_hash_str_find(Z_ARRVAL_P(file), "error", 5)), | 46 | filename, tmp_name, filesize, |
| 47 | SNUFFLEUPAGUS_G(config).config_upload_validation->script); | 47 | Z_LVAL_P(zend_hash_str_find(Z_ARRVAL_P(file), "error", 5)), |
| 48 | ZSTR_VAL(SNUFFLEUPAGUS_G(config).config_upload_validation->script)); | ||
| 48 | 49 | ||
| 49 | cmd[0] = SNUFFLEUPAGUS_G(config).config_upload_validation->script; | 50 | cmd[0] = |
| 51 | ZSTR_VAL(SNUFFLEUPAGUS_G(config).config_upload_validation->script); | ||
| 50 | cmd[1] = tmp_name; | 52 | cmd[1] = tmp_name; |
| 51 | cmd[2] = NULL; | 53 | cmd[2] = NULL; |
| 52 | 54 | ||
| @@ -58,11 +60,15 @@ int sp_rfc1867_callback(unsigned int event, void *event_data, void **extra) { | |||
| 58 | env[4] = NULL; | 60 | env[4] = NULL; |
| 59 | 61 | ||
| 60 | if ((pid = fork()) == 0) { | 62 | if ((pid = fork()) == 0) { |
| 61 | if (execve(SNUFFLEUPAGUS_G(config).config_upload_validation->script, | 63 | if (execve( |
| 62 | cmd, env) == -1) { | 64 | ZSTR_VAL( |
| 63 | sp_log_err("upload_validation", "Could not call '%s' : %s", | 65 | SNUFFLEUPAGUS_G(config).config_upload_validation->script), |
| 64 | SNUFFLEUPAGUS_G(config).config_upload_validation->script, | 66 | cmd, env) == -1) { |
| 65 | strerror(errno)); | 67 | sp_log_err( |
| 68 | "upload_validation", "Could not call '%s' : %s", | ||
| 69 | ZSTR_VAL( | ||
| 70 | SNUFFLEUPAGUS_G(config).config_upload_validation->script), | ||
| 71 | strerror(errno)); | ||
| 66 | EFREE_3(env); | 72 | EFREE_3(env); |
| 67 | exit(1); | 73 | exit(1); |
| 68 | } | 74 | } |
diff --git a/src/sp_utils.c b/src/sp_utils.c index 8b7ce49..a94ab2a 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c | |||
| @@ -19,6 +19,14 @@ static inline void _sp_log_err(const char* fmt, ...) { | |||
| 19 | php_log_err(msg); | 19 | php_log_err(msg); |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | static bool sp_zend_string_equals(const zend_string* s1, | ||
| 23 | const zend_string* s2) { | ||
| 24 | // We can't use `zend_string_equals` here because it doesn't work on | ||
| 25 | // `const` zend_string. | ||
| 26 | return ZSTR_LEN(s1) == ZSTR_LEN(s2) && | ||
| 27 | !memcmp(ZSTR_VAL(s1), ZSTR_VAL(s2), ZSTR_LEN(s1)); | ||
| 28 | } | ||
| 29 | |||
| 22 | void sp_log_msg(char const* feature, char const* level, const char* fmt, ...) { | 30 | void sp_log_msg(char const* feature, char const* level, const char* fmt, ...) { |
| 23 | char* msg; | 31 | char* msg; |
| 24 | va_list args; | 32 | va_list args; |
| @@ -56,14 +64,15 @@ int compute_hash(const char* const filename, char* file_hash) { | |||
| 56 | return SUCCESS; | 64 | return SUCCESS; |
| 57 | } | 65 | } |
| 58 | 66 | ||
| 59 | static int construct_filename(char* filename, const char* folder, | 67 | static int construct_filename(char* filename, const zend_string* folder, |
| 60 | const char* textual) { | 68 | const zend_string* textual) { |
| 61 | PHP_SHA256_CTX context; | 69 | PHP_SHA256_CTX context; |
| 62 | unsigned char digest[SHA256_SIZE] = {0}; | 70 | unsigned char digest[SHA256_SIZE] = {0}; |
| 63 | char strhash[65] = {0}; | 71 | char strhash[65] = {0}; |
| 64 | 72 | ||
| 65 | if (-1 == mkdir(folder, 0700) && errno != EEXIST) { | 73 | if (-1 == mkdir(ZSTR_VAL(folder), 0700) && errno != EEXIST) { |
| 66 | sp_log_err("request_logging", "Unable to create the folder '%s'.", folder); | 74 | sp_log_err("request_logging", "Unable to create the folder '%s'.", |
| 75 | ZSTR_VAL(folder)); | ||
| 67 | return -1; | 76 | return -1; |
| 68 | } | 77 | } |
| 69 | 78 | ||
| @@ -71,15 +80,17 @@ static int construct_filename(char* filename, const char* folder, | |||
| 71 | * as filename, in order to only have one dump per rule, to migitate | 80 | * as filename, in order to only have one dump per rule, to migitate |
| 72 | * DoS attacks. */ | 81 | * DoS attacks. */ |
| 73 | PHP_SHA256Init(&context); | 82 | PHP_SHA256Init(&context); |
| 74 | PHP_SHA256Update(&context, (const unsigned char*)textual, strlen(textual)); | 83 | PHP_SHA256Update(&context, (const unsigned char*)ZSTR_VAL(textual), |
| 84 | ZSTR_LEN(textual)); | ||
| 75 | PHP_SHA256Final(digest, &context); | 85 | PHP_SHA256Final(digest, &context); |
| 76 | make_digest_ex(strhash, digest, SHA256_SIZE); | 86 | make_digest_ex(strhash, digest, SHA256_SIZE); |
| 77 | snprintf(filename, PATH_MAX - 1, "%s/sp_dump.%s", folder, strhash); | 87 | snprintf(filename, PATH_MAX - 1, "%s/sp_dump.%s", ZSTR_VAL(folder), strhash); |
| 78 | 88 | ||
| 79 | return 0; | 89 | return 0; |
| 80 | } | 90 | } |
| 81 | 91 | ||
| 82 | int sp_log_request(const char* folder, const char* text_repr, char* from) { | 92 | int sp_log_request(const zend_string* folder, const zend_string* text_repr, |
| 93 | char* from) { | ||
| 83 | FILE* file; | 94 | FILE* file; |
| 84 | const char* current_filename = zend_get_executed_filename(TSRMLS_C); | 95 | const char* current_filename = zend_get_executed_filename(TSRMLS_C); |
| 85 | const int current_line = zend_get_executed_lineno(TSRMLS_C); | 96 | const int current_line = zend_get_executed_lineno(TSRMLS_C); |
| @@ -100,7 +111,7 @@ int sp_log_request(const char* folder, const char* text_repr, char* from) { | |||
| 100 | return -1; | 111 | return -1; |
| 101 | } | 112 | } |
| 102 | 113 | ||
| 103 | fprintf(file, "RULE: sp%s%s\n", from, text_repr); | 114 | fprintf(file, "RULE: sp%s%s\n", from, ZSTR_VAL(text_repr)); |
| 104 | 115 | ||
| 105 | fprintf(file, "FILE: %s:%d\n", current_filename, current_line); | 116 | fprintf(file, "FILE: %s:%d\n", current_filename, current_line); |
| 106 | for (size_t i = 0; i < (sizeof(zones) / sizeof(zones[0])) - 1; i++) { | 117 | for (size_t i = 0; i < (sizeof(zones) / sizeof(zones[0])) - 1; i++) { |
| @@ -130,57 +141,65 @@ int sp_log_request(const char* folder, const char* text_repr, char* from) { | |||
| 130 | return 0; | 141 | return 0; |
| 131 | } | 142 | } |
| 132 | 143 | ||
| 133 | static char* zv_str_to_char(zval* zv) { | 144 | static char* zend_string_to_char(const zend_string* zs) { |
| 134 | zval copy; | 145 | // Remove \0 from the middle of a string |
| 146 | char* copy = emalloc(ZSTR_LEN(zs) + 1); | ||
| 135 | 147 | ||
| 136 | ZVAL_ZVAL(©, zv, 1, 0); | 148 | copy[ZSTR_LEN(zs)] = 0; |
| 137 | for (size_t i = 0; i < Z_STRLEN(copy); i++) { | 149 | for (size_t i = 0; i < ZSTR_LEN(zs); i++) { |
| 138 | if (Z_STRVAL(copy)[i] == '\0') { | 150 | if (ZSTR_VAL(zs)[i] == '\0') { |
| 139 | Z_STRVAL(copy)[i] = '0'; | 151 | copy[i] = '0'; |
| 152 | } else { | ||
| 153 | copy[i] = ZSTR_VAL(zs)[i]; | ||
| 140 | } | 154 | } |
| 141 | } | 155 | } |
| 142 | return estrdup(Z_STRVAL(copy)); | 156 | return copy; |
| 143 | } | 157 | } |
| 144 | 158 | ||
| 145 | char* sp_convert_to_string(zval* zv) { | 159 | const zend_string* sp_zval_to_zend_string(zval* zv) { |
| 146 | switch (Z_TYPE_P(zv)) { | 160 | switch (Z_TYPE_P(zv)) { |
| 147 | case IS_FALSE: | ||
| 148 | return estrdup("FALSE"); | ||
| 149 | case IS_TRUE: | ||
| 150 | return estrdup("TRUE"); | ||
| 151 | case IS_NULL: | ||
| 152 | return estrdup("NULL"); | ||
| 153 | case IS_LONG: { | 161 | case IS_LONG: { |
| 154 | char* msg; | 162 | char* msg; |
| 155 | spprintf(&msg, 0, ZEND_LONG_FMT, Z_LVAL_P(zv)); | 163 | spprintf(&msg, 0, ZEND_LONG_FMT, Z_LVAL_P(zv)); |
| 156 | return msg; | 164 | zend_string* zs = zend_string_init(msg, strlen(msg), 0); |
| 165 | efree(msg); | ||
| 166 | return zs; | ||
| 157 | } | 167 | } |
| 158 | case IS_DOUBLE: { | 168 | case IS_DOUBLE: { |
| 159 | char* msg; | 169 | char* msg; |
| 160 | spprintf(&msg, 0, "%f", Z_DVAL_P(zv)); | 170 | spprintf(&msg, 0, "%f", Z_DVAL_P(zv)); |
| 161 | return msg; | 171 | zend_string* zs = zend_string_init(msg, strlen(msg), 0); |
| 172 | efree(msg); | ||
| 173 | return zs; | ||
| 162 | } | 174 | } |
| 163 | case IS_STRING: { | 175 | case IS_STRING: { |
| 164 | return zv_str_to_char(zv); | 176 | return Z_STR_P(zv); |
| 165 | } | 177 | } |
| 178 | case IS_FALSE: | ||
| 179 | return zend_string_init("FALSE", 5, 0); | ||
| 180 | case IS_TRUE: | ||
| 181 | return zend_string_init("TRUE", 4, 0); | ||
| 182 | case IS_NULL: | ||
| 183 | return zend_string_init("NULL", 4, 0); | ||
| 166 | case IS_OBJECT: | 184 | case IS_OBJECT: |
| 167 | return estrdup("OBJECT"); | 185 | return zend_string_init("OBJECT", 6, 0); |
| 168 | case IS_ARRAY: | 186 | case IS_ARRAY: |
| 169 | return estrdup("ARRAY"); | 187 | return zend_string_init("ARRAY", 5, 0); |
| 170 | case IS_RESOURCE: | 188 | case IS_RESOURCE: |
| 171 | return estrdup("RESOURCE"); | 189 | return zend_string_init("RESOURCE", 8, 0); |
| 172 | } | 190 | } |
| 173 | return estrdup(""); | 191 | return zend_string_init("", 0, 0); |
| 174 | } | 192 | } |
| 175 | 193 | ||
| 176 | bool sp_match_value(const char* value, const char* to_match, | 194 | bool sp_match_value(const zend_string* value, const zend_string* to_match, |
| 177 | const sp_pcre* rx) { | 195 | const sp_pcre* rx) { |
| 178 | if (to_match) { | 196 | if (to_match) { |
| 179 | if (0 == strcmp(to_match, value)) { | 197 | return (sp_zend_string_equals(to_match, value)); |
| 180 | return true; | ||
| 181 | } | ||
| 182 | } else if (rx) { | 198 | } else if (rx) { |
| 183 | return sp_is_regexp_matching(rx, value); | 199 | char* tmp = zend_string_to_char(value); |
| 200 | bool ret = sp_is_regexp_matching(rx, tmp); | ||
| 201 | efree(tmp); | ||
| 202 | return ret; | ||
| 184 | } else { | 203 | } else { |
| 185 | return true; | 204 | return true; |
| 186 | } | 205 | } |
| @@ -188,35 +207,41 @@ bool sp_match_value(const char* value, const char* to_match, | |||
| 188 | } | 207 | } |
| 189 | 208 | ||
| 190 | void sp_log_disable(const char* restrict path, const char* restrict arg_name, | 209 | void sp_log_disable(const char* restrict path, const char* restrict arg_name, |
| 191 | const char* restrict arg_value, | 210 | const zend_string* restrict arg_value, |
| 192 | const sp_disabled_function* config_node, unsigned int line, | 211 | const sp_disabled_function* config_node, unsigned int line, |
| 193 | const char* restrict filename) { | 212 | const char* restrict filename) { |
| 194 | const char* dump = config_node->dump; | 213 | const zend_string* dump = config_node->dump; |
| 195 | const char* alias = config_node->alias; | 214 | const zend_string* alias = config_node->alias; |
| 196 | const int sim = config_node->simulation; | 215 | const int sim = config_node->simulation; |
| 197 | 216 | ||
| 198 | filename = filename ? filename : zend_get_executed_filename(TSRMLS_C); | 217 | filename = filename ? filename : zend_get_executed_filename(TSRMLS_C); |
| 199 | line = line ? line : zend_get_executed_lineno(TSRMLS_C); | 218 | line = line ? line : zend_get_executed_lineno(TSRMLS_C); |
| 200 | 219 | ||
| 201 | if (arg_name) { | 220 | if (arg_name) { |
| 221 | char* char_repr = NULL; | ||
| 222 | if (arg_value) { | ||
| 223 | char_repr = zend_string_to_char(arg_value); | ||
| 224 | } | ||
| 202 | if (alias) { | 225 | if (alias) { |
| 203 | sp_log_msg( | 226 | sp_log_msg( |
| 204 | "disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP, | 227 | "disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP, |
| 205 | "Aborted execution on call of the function '%s' in %s:%d, " | 228 | "Aborted execution on call of the function '%s' in %s:%d, " |
| 206 | "because its argument '%s' content (%s) matched the rule '%s'.", | 229 | "because its argument '%s' content (%s) matched the rule '%s'.", |
| 207 | path, filename, line, arg_name, arg_value ? arg_value : "?", alias); | 230 | path, filename, line, arg_name, char_repr ? char_repr : "?", |
| 231 | ZSTR_VAL(alias)); | ||
| 208 | } else { | 232 | } else { |
| 209 | sp_log_msg("disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP, | 233 | sp_log_msg("disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP, |
| 210 | "Aborted execution on call of the function '%s' in %s:%d, " | 234 | "Aborted execution on call of the function '%s' in %s:%d, " |
| 211 | "because its argument '%s' content (%s) matched a rule.", | 235 | "because its argument '%s' content (%s) matched a rule.", |
| 212 | path, filename, line, arg_name, arg_value ? arg_value : "?"); | 236 | path, filename, line, arg_name, char_repr ? char_repr : "?"); |
| 213 | } | 237 | } |
| 238 | efree(char_repr); | ||
| 214 | } else { | 239 | } else { |
| 215 | if (alias) { | 240 | if (alias) { |
| 216 | sp_log_msg("disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP, | 241 | sp_log_msg("disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP, |
| 217 | "Aborted execution on call of the function '%s' in %s:%d, " | 242 | "Aborted execution on call of the function '%s' in %s:%d, " |
| 218 | "because of the the rule '%s'.", | 243 | "because of the the rule '%s'.", |
| 219 | path, filename, line, alias); | 244 | path, filename, line, ZSTR_VAL(alias)); |
| 220 | } else { | 245 | } else { |
| 221 | sp_log_msg("disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP, | 246 | sp_log_msg("disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP, |
| 222 | "Aborted execution on call of the function '%s' in %s:%d.", | 247 | "Aborted execution on call of the function '%s' in %s:%d.", |
| @@ -230,45 +255,53 @@ void sp_log_disable(const char* restrict path, const char* restrict arg_name, | |||
| 230 | } | 255 | } |
| 231 | 256 | ||
| 232 | void sp_log_disable_ret(const char* restrict path, | 257 | void sp_log_disable_ret(const char* restrict path, |
| 233 | const char* restrict ret_value, | 258 | const zend_string* restrict ret_value, |
| 234 | const sp_disabled_function* config_node) { | 259 | const sp_disabled_function* config_node) { |
| 235 | const char* dump = config_node->dump; | 260 | const zend_string* dump = config_node->dump; |
| 236 | const char* alias = config_node->alias; | 261 | const zend_string* alias = config_node->alias; |
| 237 | const int sim = config_node->simulation; | 262 | const int sim = config_node->simulation; |
| 263 | char* char_repr = NULL; | ||
| 264 | |||
| 265 | if (ret_value) { | ||
| 266 | char_repr = zend_string_to_char(ret_value); | ||
| 267 | } | ||
| 238 | if (alias) { | 268 | if (alias) { |
| 239 | sp_log_msg( | 269 | sp_log_msg( |
| 240 | "disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP, | 270 | "disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP, |
| 241 | "Aborted execution on return of the function '%s' in %s:%d, " | 271 | "Aborted execution on return of the function '%s' in %s:%d, " |
| 242 | "because the function returned '%s', which matched the rule '%s'.", | 272 | "because the function returned '%s', which matched the rule '%s'.", |
| 243 | path, zend_get_executed_filename(TSRMLS_C), | 273 | path, zend_get_executed_filename(TSRMLS_C), |
| 244 | zend_get_executed_lineno(TSRMLS_C), ret_value ? ret_value : "?", alias); | 274 | zend_get_executed_lineno(TSRMLS_C), char_repr ? char_repr : "?", |
| 275 | ZSTR_VAL(alias)); | ||
| 245 | } else { | 276 | } else { |
| 246 | sp_log_msg("disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP, | 277 | sp_log_msg("disabled_function", sim ? SP_LOG_SIMULATION : SP_LOG_DROP, |
| 247 | "Aborted execution on return of the function '%s' in %s:%d, " | 278 | "Aborted execution on return of the function '%s' in %s:%d, " |
| 248 | "because the function returned '%s', which matched a rule.", | 279 | "because the function returned '%s', which matched a rule.", |
| 249 | path, zend_get_executed_filename(TSRMLS_C), | 280 | path, zend_get_executed_filename(TSRMLS_C), |
| 250 | zend_get_executed_lineno(TSRMLS_C), ret_value ? ret_value : "?"); | 281 | zend_get_executed_lineno(TSRMLS_C), char_repr ? char_repr : "?"); |
| 251 | } | 282 | } |
| 283 | efree(char_repr); | ||
| 252 | if (dump) { | 284 | if (dump) { |
| 253 | sp_log_request(dump, config_node->textual_representation, | 285 | sp_log_request(dump, config_node->textual_representation, |
| 254 | SP_TOKEN_DISABLE_FUNC); | 286 | SP_TOKEN_DISABLE_FUNC); |
| 255 | } | 287 | } |
| 256 | } | 288 | } |
| 257 | 289 | ||
| 258 | bool sp_match_array_key(const zval* zv, const char* to_match, | 290 | bool sp_match_array_key(const zval* zv, const zend_string* to_match, |
| 259 | const sp_pcre* rx) { | 291 | const sp_pcre* rx) { |
| 260 | zend_string* key; | 292 | zend_string* key; |
| 261 | zend_ulong idx; | 293 | zend_ulong idx; |
| 262 | 294 | ||
| 263 | ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(zv), idx, key) { | 295 | ZEND_HASH_FOREACH_KEY(Z_ARRVAL_P(zv), idx, key) { |
| 264 | if (key) { | 296 | if (key) { |
| 265 | if (sp_match_value(ZSTR_VAL(key), to_match, rx)) { | 297 | if (sp_match_value(key, to_match, rx)) { |
| 266 | return true; | 298 | return true; |
| 267 | } | 299 | } |
| 268 | } else { | 300 | } else { |
| 269 | char* idx_str = NULL; | 301 | char* idx_str = NULL; |
| 270 | spprintf(&idx_str, 0, "%lu", idx); | 302 | spprintf(&idx_str, 0, "%lu", idx); |
| 271 | if (sp_match_value(idx_str, to_match, rx)) { | 303 | zend_string* tmp = zend_string_init(idx_str, strlen(idx_str), 0); |
| 304 | if (sp_match_value(tmp, to_match, rx)) { | ||
| 272 | efree(idx_str); | 305 | efree(idx_str); |
| 273 | return true; | 306 | return true; |
| 274 | } | 307 | } |
| @@ -279,18 +312,16 @@ bool sp_match_array_key(const zval* zv, const char* to_match, | |||
| 279 | return false; | 312 | return false; |
| 280 | } | 313 | } |
| 281 | 314 | ||
| 282 | bool sp_match_array_value(const zval* arr, const char* to_match, | 315 | bool sp_match_array_value(const zval* arr, const zend_string* to_match, |
| 283 | const sp_pcre* rx) { | 316 | const sp_pcre* rx) { |
| 284 | zval* value; | 317 | zval* value; |
| 285 | 318 | ||
| 286 | ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), value) { | 319 | ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), value) { |
| 287 | if (Z_TYPE_P(value) != IS_ARRAY) { | 320 | if (Z_TYPE_P(value) != IS_ARRAY) { |
| 288 | char* value_str = sp_convert_to_string(value); | 321 | const zend_string* value_str = sp_zval_to_zend_string(value); |
| 289 | if (sp_match_value(value_str, to_match, rx)) { | 322 | if (sp_match_value(value_str, to_match, rx)) { |
| 290 | efree(value_str); | ||
| 291 | return true; | 323 | return true; |
| 292 | } else { | 324 | } else { |
| 293 | efree(value_str); | ||
| 294 | } | 325 | } |
| 295 | } else if (sp_match_array_value(value, to_match, rx)) { | 326 | } else if (sp_match_array_value(value, to_match, rx)) { |
| 296 | return true; | 327 | return true; |
| @@ -303,6 +334,7 @@ bool sp_match_array_value(const zval* arr, const char* to_match, | |||
| 303 | int hook_function(const char* original_name, HashTable* hook_table, | 334 | int hook_function(const char* original_name, HashTable* hook_table, |
| 304 | void (*new_function)(INTERNAL_FUNCTION_PARAMETERS)) { | 335 | void (*new_function)(INTERNAL_FUNCTION_PARAMETERS)) { |
| 305 | zend_internal_function* func; | 336 | zend_internal_function* func; |
| 337 | bool ret = FAILURE; | ||
| 306 | 338 | ||
| 307 | /* The `mb` module likes to hook functions, like strlen->mb_strlen, | 339 | /* The `mb` module likes to hook functions, like strlen->mb_strlen, |
| 308 | * so we have to hook both of them. */ | 340 | * so we have to hook both of them. */ |
| @@ -317,6 +349,7 @@ int hook_function(const char* original_name, HashTable* hook_table, | |||
| 317 | return FAILURE; | 349 | return FAILURE; |
| 318 | } | 350 | } |
| 319 | func->handler = new_function; | 351 | func->handler = new_function; |
| 352 | ret = SUCCESS; | ||
| 320 | } else { | 353 | } else { |
| 321 | return SUCCESS; | 354 | return SUCCESS; |
| 322 | } | 355 | } |
| @@ -326,7 +359,7 @@ int hook_function(const char* original_name, HashTable* hook_table, | |||
| 326 | CG(compiler_options) |= ZEND_COMPILE_NO_BUILTIN_STRLEN; | 359 | CG(compiler_options) |= ZEND_COMPILE_NO_BUILTIN_STRLEN; |
| 327 | if (zend_hash_str_find(CG(function_table), | 360 | if (zend_hash_str_find(CG(function_table), |
| 328 | VAR_AND_LEN(original_name + 3))) { | 361 | VAR_AND_LEN(original_name + 3))) { |
| 329 | hook_function(original_name + 3, hook_table, new_function); | 362 | return hook_function(original_name + 3, hook_table, new_function); |
| 330 | } | 363 | } |
| 331 | } else { // TODO this can be moved somewhere else to gain some marginal perfs | 364 | } else { // TODO this can be moved somewhere else to gain some marginal perfs |
| 332 | CG(compiler_options) |= ZEND_COMPILE_NO_BUILTIN_STRLEN; | 365 | CG(compiler_options) |= ZEND_COMPILE_NO_BUILTIN_STRLEN; |
| @@ -334,11 +367,11 @@ int hook_function(const char* original_name, HashTable* hook_table, | |||
| 334 | memcpy(mb_name, "mb_", 3); | 367 | memcpy(mb_name, "mb_", 3); |
| 335 | memcpy(mb_name + 3, VAR_AND_LEN(original_name)); | 368 | memcpy(mb_name + 3, VAR_AND_LEN(original_name)); |
| 336 | if (zend_hash_str_find(CG(function_table), VAR_AND_LEN(mb_name))) { | 369 | if (zend_hash_str_find(CG(function_table), VAR_AND_LEN(mb_name))) { |
| 337 | hook_function(mb_name, hook_table, new_function); | 370 | return hook_function(mb_name, hook_table, new_function); |
| 338 | } | 371 | } |
| 339 | } | 372 | } |
| 340 | 373 | ||
| 341 | return SUCCESS; | 374 | return ret; |
| 342 | } | 375 | } |
| 343 | 376 | ||
| 344 | int hook_regexp(const sp_pcre* regexp, HashTable* hook_table, | 377 | int hook_regexp(const sp_pcre* regexp, HashTable* hook_table, |
| @@ -356,7 +389,7 @@ int hook_regexp(const sp_pcre* regexp, HashTable* hook_table, | |||
| 356 | return SUCCESS; | 389 | return SUCCESS; |
| 357 | } | 390 | } |
| 358 | 391 | ||
| 359 | bool check_is_in_eval_whitelist(const char* const function_name) { | 392 | bool check_is_in_eval_whitelist(const zend_string* const function_name) { |
| 360 | const sp_list_node* it = SNUFFLEUPAGUS_G(config).config_eval->whitelist; | 393 | const sp_list_node* it = SNUFFLEUPAGUS_G(config).config_eval->whitelist; |
| 361 | 394 | ||
| 362 | if (!it) { | 395 | if (!it) { |
| @@ -366,7 +399,7 @@ bool check_is_in_eval_whitelist(const char* const function_name) { | |||
| 366 | /* yes, we could use a HashTable instead, but since the list is pretty | 399 | /* yes, we could use a HashTable instead, but since the list is pretty |
| 367 | * small, it doesn't maka a difference in practise. */ | 400 | * small, it doesn't maka a difference in practise. */ |
| 368 | while (it && it->data) { | 401 | while (it && it->data) { |
| 369 | if (0 == strcmp(function_name, (char*)(it->data))) { | 402 | if (sp_zend_string_equals(function_name, (const zend_string*)(it->data))) { |
| 370 | /* We've got a match, the function is whiteslited. */ | 403 | /* We've got a match, the function is whiteslited. */ |
| 371 | return true; | 404 | return true; |
| 372 | } | 405 | } |
diff --git a/src/sp_utils.h b/src/sp_utils.h index 61a23f9..a21a4b0 100644 --- a/src/sp_utils.h +++ b/src/sp_utils.h | |||
| @@ -44,20 +44,20 @@ | |||
| 44 | 44 | ||
| 45 | void sp_log_msg(char const *feature, char const *level, const char *fmt, ...); | 45 | void sp_log_msg(char const *feature, char const *level, const char *fmt, ...); |
| 46 | int compute_hash(const char *const filename, char *file_hash); | 46 | int compute_hash(const char *const filename, char *file_hash); |
| 47 | char *sp_convert_to_string(zval *); | 47 | const zend_string* sp_zval_to_zend_string(zval *); |
| 48 | bool sp_match_value(const char *, const char *, const sp_pcre *); | 48 | bool sp_match_value(const zend_string *, const zend_string *, const sp_pcre *); |
| 49 | bool sp_match_array_key(const zval *, const char *, const sp_pcre *); | 49 | bool sp_match_array_key(const zval *, const zend_string *, const sp_pcre *); |
| 50 | bool sp_match_array_value(const zval *, const char *, const sp_pcre *); | 50 | bool sp_match_array_value(const zval *, const zend_string *, const sp_pcre *); |
| 51 | void sp_log_disable(const char *restrict, const char *restrict, | 51 | void sp_log_disable(const char *restrict, const char *restrict, |
| 52 | const char *restrict, const sp_disabled_function *, | 52 | const zend_string *restrict, const sp_disabled_function *, |
| 53 | unsigned int, const char*restrict); | 53 | unsigned int, const char*restrict); |
| 54 | void sp_log_disable_ret(const char *restrict, const char *restrict, | 54 | void sp_log_disable_ret(const char *restrict, const zend_string *restrict, |
| 55 | const sp_disabled_function *); | 55 | const sp_disabled_function *); |
| 56 | int hook_function(const char *, HashTable *, | 56 | int hook_function(const char *, HashTable *, |
| 57 | void (*)(INTERNAL_FUNCTION_PARAMETERS)); | 57 | void (*)(INTERNAL_FUNCTION_PARAMETERS)); |
| 58 | int hook_regexp(const sp_pcre *, HashTable *, | 58 | int hook_regexp(const sp_pcre *, HashTable *, |
| 59 | void (*)(INTERNAL_FUNCTION_PARAMETERS)); | 59 | void (*)(INTERNAL_FUNCTION_PARAMETERS)); |
| 60 | bool check_is_in_eval_whitelist(const char * const function_name); | 60 | bool check_is_in_eval_whitelist(const zend_string * const function_name); |
| 61 | int sp_log_request(const char* folder, const char* text_repr, char* from); | 61 | int sp_log_request(const zend_string* folder, const zend_string* text_repr, char* from); |
| 62 | 62 | ||
| 63 | #endif /* SP_UTILS_H */ | 63 | #endif /* SP_UTILS_H */ |
diff --git a/src/sp_var_value.c b/src/sp_var_value.c index 7ed8dfa..e91c3d8 100644 --- a/src/sp_var_value.c +++ b/src/sp_var_value.c | |||
| @@ -107,10 +107,9 @@ static zval *get_array_value(zend_execute_data *ed, zval *zvalue, | |||
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | if (Z_TYPE_P(zvalue) == IS_ARRAY) { | 109 | if (Z_TYPE_P(zvalue) == IS_ARRAY) { |
| 110 | char *idx = sp_convert_to_string(idx_value); | 110 | const zend_string *idx = sp_zval_to_zend_string(idx_value); |
| 111 | zval *ret = get_entry_hashtable(Z_ARRVAL_P(zvalue), idx, strlen(idx)); | 111 | return get_entry_hashtable(Z_ARRVAL_P(zvalue), ZSTR_VAL(idx), |
| 112 | efree(idx); | 112 | ZSTR_LEN(idx)); |
| 113 | return ret; | ||
| 114 | } | 113 | } |
| 115 | 114 | ||
| 116 | return NULL; | 115 | return NULL; |
