diff options
| author | jvoisin | 2018-02-05 17:27:45 +0100 |
|---|---|---|
| committer | GitHub | 2018-02-05 17:27:45 +0100 |
| commit | 4cbca117a3f2ef2d6695504970378ec4c483d19f (patch) | |
| tree | 2fe9d10ddf5fdff1c1c0f4cf0cf7cbb16d274e27 | |
| parent | f0a956e825a83ff3a58d4714a92fbb945f6c8841 (diff) | |
Compatibility layer for pcre2
This should close #129
| -rw-r--r-- | .travis.yml | 17 | ||||
| -rw-r--r-- | src/config.m4 | 1 | ||||
| -rw-r--r-- | src/php_snuffleupagus.h | 13 | ||||
| -rw-r--r-- | src/sp_config.c | 12 | ||||
| -rw-r--r-- | src/sp_config.h | 14 | ||||
| -rw-r--r-- | src/sp_config_keywords.c | 2 | ||||
| -rw-r--r-- | src/sp_cookie_encryption.c | 2 | ||||
| -rw-r--r-- | src/sp_disabled_functions.c | 12 | ||||
| -rw-r--r-- | src/sp_pcre_compat.c | 50 | ||||
| -rw-r--r-- | src/sp_pcre_compat.h | 34 | ||||
| -rw-r--r-- | src/sp_utils.c | 33 | ||||
| -rw-r--r-- | src/sp_utils.h | 9 | ||||
| -rw-r--r-- | src/sp_var_parser.c | 16 | ||||
| -rw-r--r-- | src/tests/broken_conf_config_regexp.phpt | 4 | ||||
| -rw-r--r-- | src/tests/broken_conf_shown_in_phpinfo.phpt | 4 | ||||
| -rw-r--r-- | src/tests/broken_regexp.phpt | 2 |
16 files changed, 129 insertions, 96 deletions
diff --git a/.travis.yml b/.travis.yml index 457503d..ae102d5 100644 --- a/.travis.yml +++ b/.travis.yml | |||
| @@ -1,10 +1,5 @@ | |||
| 1 | language: php | 1 | language: php |
| 2 | 2 | ||
| 3 | addons: | ||
| 4 | apt: | ||
| 5 | packages: | ||
| 6 | - valgrind | ||
| 7 | |||
| 8 | env: | 3 | env: |
| 9 | - secure: "fjx/arfcdoqWUIzlQXzQdW9gqXRG7Vpo8dTwJip0uJH8oFeTfYhw1V9EMS4JtKVGwQo3vaagehMflVr7swaoe9Nf4YoCjaEq8x6ZMJH3bLHNgtigfS03Uqop9FI/a/Jau/BL7ibIEkZRNfEIx8z+NyfY4bAeK35W/Ru5k2BHyp1GLKwBpizHdJsshG/ukM+4W8PY9BAeXVavqxQRywseQEsqmGruGLcYFuuh04D7cnNqyuYgbdaq7YMKZfVGxM7N5eeL5xSlw0Sl9yOutRzkxUmL1WSmYMFrkRLcc37hRTu67tCmP60tiGLGY2Ll8nUh6rkc3RwBgc1wOC7jRMrtoGvlgsLxz7kLOtpQ31PdJKefe99rQMkcYKLwCxXf7WQdOHY4YsTmjqlPyzfTKT3mNtGhUwp1rEvlcygZZK8osHtc46BUD6BKNRCvTyLNyLTx2IoA4WfrzWOaQ+A1gNRD5L9Jbqi0kY6teENCzzlHUe80mH7wBarCTRoDAD73w/EPgSn3+CeLALXXEu+r9Sm/e5YpaFfLdeKDC6fr1KwU69ddHUKWZqjFM8vEHjrIbmAdNwVsuCo8LeWdCCXdQlWrISQ4OUDBBEmnwlKoojSjIYP5SKoH1txZemGok1/TN/tvjlyrx2RYYxy7AdUulENKXXeqlwWsiwVZCZLR4tt+wEQ=" | 4 | - secure: "fjx/arfcdoqWUIzlQXzQdW9gqXRG7Vpo8dTwJip0uJH8oFeTfYhw1V9EMS4JtKVGwQo3vaagehMflVr7swaoe9Nf4YoCjaEq8x6ZMJH3bLHNgtigfS03Uqop9FI/a/Jau/BL7ibIEkZRNfEIx8z+NyfY4bAeK35W/Ru5k2BHyp1GLKwBpizHdJsshG/ukM+4W8PY9BAeXVavqxQRywseQEsqmGruGLcYFuuh04D7cnNqyuYgbdaq7YMKZfVGxM7N5eeL5xSlw0Sl9yOutRzkxUmL1WSmYMFrkRLcc37hRTu67tCmP60tiGLGY2Ll8nUh6rkc3RwBgc1wOC7jRMrtoGvlgsLxz7kLOtpQ31PdJKefe99rQMkcYKLwCxXf7WQdOHY4YsTmjqlPyzfTKT3mNtGhUwp1rEvlcygZZK8osHtc46BUD6BKNRCvTyLNyLTx2IoA4WfrzWOaQ+A1gNRD5L9Jbqi0kY6teENCzzlHUe80mH7wBarCTRoDAD73w/EPgSn3+CeLALXXEu+r9Sm/e5YpaFfLdeKDC6fr1KwU69ddHUKWZqjFM8vEHjrIbmAdNwVsuCo8LeWdCCXdQlWrISQ4OUDBBEmnwlKoojSjIYP5SKoH1txZemGok1/TN/tvjlyrx2RYYxy7AdUulENKXXeqlwWsiwVZCZLR4tt+wEQ=" |
| 10 | 5 | ||
| @@ -36,23 +31,19 @@ matrix: | |||
| 36 | php: '7.1' | 31 | php: '7.1' |
| 37 | - env: TARGET="clang php7.2" CC="clang" | 32 | - env: TARGET="clang php7.2" CC="clang" |
| 38 | php: '7.2' | 33 | php: '7.2' |
| 39 | allow_failures: | ||
| 40 | - env: TARGET="clang php nightly with valgrind" CC="clang" | ||
| 41 | php: nightly | ||
| 42 | - env: TARGET="gcc php nightly" CC="gcc" | 34 | - env: TARGET="gcc php nightly" CC="gcc" |
| 43 | before_install: pip install --user cpp-coveralls | 35 | before_install: pip install --user cpp-coveralls |
| 44 | php: nightly | 36 | php: nightly |
| 37 | allow_failures: | ||
| 38 | - env: TARGET="clang php nightly" CC="clang" # https://bugs.llvm.org/show_bug.cgi?id=9295 | ||
| 39 | php: nightly | ||
| 45 | 40 | ||
| 46 | script: | 41 | script: |
| 47 | - cd src | 42 | - cd src |
| 48 | - phpize | 43 | - phpize |
| 49 | - ./configure --enable-snuffleupagus --enable-coverage | 44 | - ./configure --enable-snuffleupagus --enable-coverage |
| 50 | - make -j 2 | 45 | - make -j 2 |
| 51 | - 'if [ "${TARGET}" = "clang php nightly with valgrind" ]; then | 46 | - TEST_PHP_ARGS="-q" REPORT_EXIT_STATUS=1 make test |
| 52 | TEST_PHP_ARGS="-q -m" REPORT_EXIT_STATUS=1 make test ; | ||
| 53 | else | ||
| 54 | TEST_PHP_ARGS="-q" REPORT_EXIT_STATUS=1 make test ; | ||
| 55 | fi' | ||
| 56 | 47 | ||
| 57 | after_success: | 48 | after_success: |
| 58 | - 'if [ "${TARGET}" = "gcc php nightly" ]; then | 49 | - 'if [ "${TARGET}" = "gcc php nightly" ]; then |
diff --git a/src/config.m4 b/src/config.m4 index 3d4c1ba..8d5278e 100644 --- a/src/config.m4 +++ b/src/config.m4 | |||
| @@ -6,6 +6,7 @@ sources="$sources sp_unserialize.c sp_utils.c sp_disable_xxe.c sp_list.c" | |||
| 6 | sources="$sources sp_disabled_functions.c sp_execute.c sp_upload_validation.c" | 6 | sources="$sources sp_disabled_functions.c sp_execute.c sp_upload_validation.c" |
| 7 | sources="$sources sp_cookie_encryption.c sp_network_utils.c tweetnacl.c" | 7 | sources="$sources sp_cookie_encryption.c sp_network_utils.c tweetnacl.c" |
| 8 | sources="$sources sp_config_keywords.c sp_var_parser.c sp_var_value.c sp_tree.c" | 8 | sources="$sources sp_config_keywords.c sp_var_parser.c sp_var_value.c sp_tree.c" |
| 9 | sources="$sources sp_pcre_compat.c" | ||
| 9 | 10 | ||
| 10 | PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support, | 11 | PHP_ARG_ENABLE(snuffleupagus, whether to enable snuffleupagus support, |
| 11 | [ --enable-snuffleupagus Enable snuffleupagus support]) | 12 | [ --enable-snuffleupagus Enable snuffleupagus support]) |
diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index 95f271d..52bcc93 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include "zend_string.h" | 24 | #include "zend_string.h" |
| 25 | #include "zend_extensions.h" | 25 | #include "zend_extensions.h" |
| 26 | 26 | ||
| 27 | #include "sp_pcre_compat.h" | ||
| 27 | #include "sp_list.h" | 28 | #include "sp_list.h" |
| 28 | #include "sp_tree.h" | 29 | #include "sp_tree.h" |
| 29 | #include "sp_var_parser.h" | 30 | #include "sp_var_parser.h" |
| @@ -71,18 +72,6 @@ ZEND_END_MODULE_GLOBALS(snuffleupagus) | |||
| 71 | ZEND_TSRMLS_CACHE_EXTERN() | 72 | ZEND_TSRMLS_CACHE_EXTERN() |
| 72 | #endif | 73 | #endif |
| 73 | 74 | ||
| 74 | #if HAVE_BUNDLED_PCRE | ||
| 75 | #include "ext/pcre/pcrelib/pcre.h" | ||
| 76 | #undef pcre_exec | ||
| 77 | #undef pcre_compile | ||
| 78 | #define sp_pcre_exec pcre_exec | ||
| 79 | #define sp_pcre_compile pcre_compile | ||
| 80 | #else | ||
| 81 | #include "pcre.h" | ||
| 82 | #define sp_pcre_exec pcre_exec | ||
| 83 | #define sp_pcre_compile pcre_compile | ||
| 84 | #endif | ||
| 85 | |||
| 86 | PHP_FUNCTION(check_disabled_function); | 75 | PHP_FUNCTION(check_disabled_function); |
| 87 | PHP_FUNCTION(eval_blacklist_callback); | 76 | PHP_FUNCTION(eval_blacklist_callback); |
| 88 | 77 | ||
diff --git a/src/sp_config.c b/src/sp_config.c index 7a38a45..1236ebd 100644 --- a/src/sp_config.c +++ b/src/sp_config.c | |||
| @@ -140,15 +140,9 @@ int parse_regexp(char *restrict line, char *restrict keyword, void *retval) { | |||
| 140 | char *value = get_param(&consumed, line, SP_TYPE_STR, keyword); | 140 | char *value = get_param(&consumed, line, SP_TYPE_STR, keyword); |
| 141 | 141 | ||
| 142 | if (value) { | 142 | if (value) { |
| 143 | const char *pcre_error; | 143 | sp_pcre *compiled_re = sp_pcre_compile(value); |
| 144 | int pcre_error_offset; | 144 | if (NULL != compiled_re) { |
| 145 | pcre *compiled_re = sp_pcre_compile(value, PCRE_CASELESS, &pcre_error, | 145 | *(sp_pcre **)retval = compiled_re; |
| 146 | &pcre_error_offset, NULL); | ||
| 147 | if (NULL == compiled_re) { | ||
| 148 | sp_log_err("config", "Failed to compile '%s': %s on line %zu.", value, | ||
| 149 | pcre_error, sp_line_no); | ||
| 150 | } else { | ||
| 151 | *(pcre **)retval = compiled_re; | ||
| 152 | return consumed; | 146 | return consumed; |
| 153 | } | 147 | } |
| 154 | } | 148 | } |
diff --git a/src/sp_config.h b/src/sp_config.h index 25963f1..75ee83d 100644 --- a/src/sp_config.h +++ b/src/sp_config.h | |||
| @@ -59,7 +59,7 @@ typedef struct { | |||
| 59 | enum samesite_type { strict = 1, lax = 2 } samesite; | 59 | enum samesite_type { strict = 1, lax = 2 } samesite; |
| 60 | bool encrypt; | 60 | bool encrypt; |
| 61 | char *name; | 61 | char *name; |
| 62 | pcre *name_r; | 62 | sp_pcre *name_r; |
| 63 | bool simulation; | 63 | bool simulation; |
| 64 | } sp_cookie; | 64 | } sp_cookie; |
| 65 | 65 | ||
| @@ -72,29 +72,29 @@ typedef struct { | |||
| 72 | char *textual_representation; | 72 | char *textual_representation; |
| 73 | 73 | ||
| 74 | char *filename; | 74 | char *filename; |
| 75 | pcre *r_filename; | 75 | sp_pcre *r_filename; |
| 76 | 76 | ||
| 77 | char *function; | 77 | char *function; |
| 78 | pcre *r_function; | 78 | sp_pcre *r_function; |
| 79 | sp_list_node *functions_list; | 79 | sp_list_node *functions_list; |
| 80 | 80 | ||
| 81 | char *hash; | 81 | char *hash; |
| 82 | int simulation; | 82 | int simulation; |
| 83 | 83 | ||
| 84 | sp_tree *param; | 84 | sp_tree *param; |
| 85 | pcre *r_param; | 85 | sp_pcre *r_param; |
| 86 | sp_php_type param_type; | 86 | sp_php_type param_type; |
| 87 | int pos; | 87 | int pos; |
| 88 | unsigned int line; | 88 | unsigned int line; |
| 89 | 89 | ||
| 90 | char *ret; | 90 | char *ret; |
| 91 | pcre *r_ret; | 91 | sp_pcre *r_ret; |
| 92 | sp_php_type ret_type; | 92 | sp_php_type ret_type; |
| 93 | 93 | ||
| 94 | pcre *value_r; | 94 | sp_pcre *value_r; |
| 95 | char *value; | 95 | char *value; |
| 96 | 96 | ||
| 97 | pcre *r_key; | 97 | sp_pcre *r_key; |
| 98 | char *key; | 98 | char *key; |
| 99 | 99 | ||
| 100 | char *dump; | 100 | char *dump; |
diff --git a/src/sp_config_keywords.c b/src/sp_config_keywords.c index 93c3da9..5df3d97 100644 --- a/src/sp_config_keywords.c +++ b/src/sp_config_keywords.c | |||
| @@ -25,7 +25,7 @@ static int get_construct_type(sp_disabled_function const *const df) { | |||
| 25 | } | 25 | } |
| 26 | } else { | 26 | } else { |
| 27 | if (true == | 27 | if (true == |
| 28 | is_regexp_matching(df->r_function, CONSTRUCTS_TYPES[i].keys[j])) { | 28 | sp_is_regexp_matching(df->r_function, CONSTRUCTS_TYPES[i].keys[j])) { |
| 29 | return CONSTRUCTS_TYPES[i].type; | 29 | return CONSTRUCTS_TYPES[i].type; |
| 30 | } | 30 | } |
| 31 | } | 31 | } |
diff --git a/src/sp_cookie_encryption.c b/src/sp_cookie_encryption.c index 29e96b1..09cf884 100644 --- a/src/sp_cookie_encryption.c +++ b/src/sp_cookie_encryption.c | |||
| @@ -167,7 +167,7 @@ static zend_string *encrypt_data(char *data, unsigned long long data_len) { | |||
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | PHP_FUNCTION(sp_setcookie) { | 169 | PHP_FUNCTION(sp_setcookie) { |
| 170 | zval params[7] = {0}; | 170 | zval params[7] = {{{0}}}; |
| 171 | zend_string *name = NULL, *value = NULL, *path = NULL, *domain = NULL, | 171 | zend_string *name = NULL, *value = NULL, *path = NULL, *domain = NULL, |
| 172 | *samesite = NULL; | 172 | *samesite = NULL; |
| 173 | zend_long expires = 0; | 173 | zend_long expires = 0; |
diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c index 8396cae..f8c21d2 100644 --- a/src/sp_disabled_functions.c +++ b/src/sp_disabled_functions.c | |||
| @@ -155,7 +155,7 @@ static bool is_param_matching(zend_execute_data* execute_data, | |||
| 155 | } | 155 | } |
| 156 | const bool pcre_matching = | 156 | const bool pcre_matching = |
| 157 | config_node->r_param && | 157 | config_node->r_param && |
| 158 | (true == is_regexp_matching(config_node->r_param, *arg_name)); | 158 | (true == sp_is_regexp_matching(config_node->r_param, *arg_name)); |
| 159 | 159 | ||
| 160 | /* This is the parameter name we're looking for. */ | 160 | /* This is the parameter name we're looking for. */ |
| 161 | if (true == pcre_matching || config_node->pos != -1) { | 161 | if (true == pcre_matching || config_node->pos != -1) { |
| @@ -259,7 +259,7 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name, | |||
| 259 | } | 259 | } |
| 260 | } else if (config_node->r_function) { | 260 | } else if (config_node->r_function) { |
| 261 | if (false == | 261 | if (false == |
| 262 | is_regexp_matching(config_node->r_function, complete_path_function)) { | 262 | sp_is_regexp_matching(config_node->r_function, complete_path_function)) { |
| 263 | goto next; | 263 | goto next; |
| 264 | } | 264 | } |
| 265 | } | 265 | } |
| @@ -276,7 +276,7 @@ bool should_disable(zend_execute_data* execute_data, const char* builtin_name, | |||
| 276 | } | 276 | } |
| 277 | } else if (config_node->r_filename) { | 277 | } else if (config_node->r_filename) { |
| 278 | if (false == | 278 | if (false == |
| 279 | is_regexp_matching(config_node->r_filename, current_filename)) { | 279 | sp_is_regexp_matching(config_node->r_filename, current_filename)) { |
| 280 | goto next; | 280 | goto next; |
| 281 | } | 281 | } |
| 282 | } | 282 | } |
| @@ -366,7 +366,7 @@ bool should_drop_on_ret(zval* return_value, | |||
| 366 | } | 366 | } |
| 367 | } else if (config_node->r_function) { | 367 | } else if (config_node->r_function) { |
| 368 | if (false == | 368 | if (false == |
| 369 | is_regexp_matching(config_node->r_function, complete_path_function)) { | 369 | sp_is_regexp_matching(config_node->r_function, complete_path_function)) { |
| 370 | goto next; | 370 | goto next; |
| 371 | } | 371 | } |
| 372 | } | 372 | } |
| @@ -377,7 +377,7 @@ bool should_drop_on_ret(zval* return_value, | |||
| 377 | } | 377 | } |
| 378 | } else if (config_node->r_filename) { | 378 | } else if (config_node->r_filename) { |
| 379 | if (false == | 379 | if (false == |
| 380 | is_regexp_matching(config_node->r_filename, current_filename)) { | 380 | sp_is_regexp_matching(config_node->r_filename, current_filename)) { |
| 381 | goto next; | 381 | goto next; |
| 382 | } | 382 | } |
| 383 | } | 383 | } |
| @@ -440,7 +440,7 @@ ZEND_FUNCTION(check_disabled_function) { | |||
| 440 | static int hook_functions(const sp_list_node* config) { | 440 | static int hook_functions(const sp_list_node* config) { |
| 441 | while (config && config->data) { | 441 | while (config && config->data) { |
| 442 | const char* function_name = ((sp_disabled_function*)config->data)->function; | 442 | const char* function_name = ((sp_disabled_function*)config->data)->function; |
| 443 | const pcre* function_name_regexp = | 443 | const sp_pcre* function_name_regexp = |
| 444 | ((sp_disabled_function*)config->data)->r_function; | 444 | ((sp_disabled_function*)config->data)->r_function; |
| 445 | 445 | ||
| 446 | if (NULL != function_name) { // hook function by name | 446 | if (NULL != function_name) { // hook function by name |
diff --git a/src/sp_pcre_compat.c b/src/sp_pcre_compat.c new file mode 100644 index 0000000..42a11cb --- /dev/null +++ b/src/sp_pcre_compat.c | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | #include "php_snuffleupagus.h" | ||
| 2 | |||
| 3 | #include "sp_pcre_compat.h" | ||
| 4 | |||
| 5 | sp_pcre* sp_pcre_compile(const char *const pattern) { | ||
| 6 | sp_pcre* ret = NULL; | ||
| 7 | const char *pcre_error = NULL; | ||
| 8 | #ifdef SP_HAS_PCRE2 | ||
| 9 | int errornumber; | ||
| 10 | PCRE2_SIZE erroroffset; | ||
| 11 | ret = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, PCRE2_CASELESS, &errornumber, &erroroffset, NULL); | ||
| 12 | #else | ||
| 13 | int erroroffset; | ||
| 14 | ret = pcre_compile(pattern, PCRE_CASELESS, &pcre_error, &erroroffset, NULL); | ||
| 15 | #endif | ||
| 16 | |||
| 17 | if (NULL == ret) { | ||
| 18 | sp_log_err("config", "Failed to compile '%s': %s on line %zu.", pattern, | ||
| 19 | pcre_error, sp_line_no); | ||
| 20 | } | ||
| 21 | return ret; | ||
| 22 | } | ||
| 23 | |||
| 24 | bool sp_is_regexp_matching_len(const sp_pcre* regexp, const char* str, size_t len) { | ||
| 25 | int ret = 0; | ||
| 26 | |||
| 27 | assert(NULL != regexp); | ||
| 28 | assert(NULL != str); | ||
| 29 | |||
| 30 | #ifdef SP_HAS_PCRE2 | ||
| 31 | pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(regexp, NULL); | ||
| 32 | ret = pcre2_match(regexp, (PCRE2_SPTR)str, len, 0, 0, match_data, NULL); | ||
| 33 | #else | ||
| 34 | int vec[30]; | ||
| 35 | ret = pcre_exec(regexp, NULL, str, len, 0, 0, vec, | ||
| 36 | sizeof(vec) / sizeof(int)); | ||
| 37 | #endif | ||
| 38 | |||
| 39 | if (ret < 0) { | ||
| 40 | #ifdef SP_HAS_PCRE2 | ||
| 41 | if (ret != PCRE2_ERROR_NOMATCH) { | ||
| 42 | #else | ||
| 43 | if (ret != PCRE_ERROR_NOMATCH) { | ||
| 44 | #endif | ||
| 45 | sp_log_err("regexp", "Something went wrong with a regexp (%d).", ret); | ||
| 46 | } | ||
| 47 | return false; | ||
| 48 | } | ||
| 49 | return true; | ||
| 50 | } | ||
diff --git a/src/sp_pcre_compat.h b/src/sp_pcre_compat.h new file mode 100644 index 0000000..a9eb253 --- /dev/null +++ b/src/sp_pcre_compat.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | #ifndef SP_PCRE_COMPAT_H | ||
| 2 | #define SP_PCRE_COMPAT_H | ||
| 3 | |||
| 4 | #include <stdlib.h> | ||
| 5 | #include <stdbool.h> | ||
| 6 | |||
| 7 | #undef pcre_exec | ||
| 8 | #undef pcre_compile | ||
| 9 | |||
| 10 | /* We're not supporting pcre2 when it's not bundled with php7, | ||
| 11 | * yet. Pull-requests are welcome. */ | ||
| 12 | #if HAVE_BUNDLED_PCRE | ||
| 13 | #if PHP_VERSION_ID >= 70300 | ||
| 14 | #define SP_HAS_PCRE2 | ||
| 15 | #include "ext/pcre/pcre2lib/pcre2.h" | ||
| 16 | #else | ||
| 17 | #include "ext/pcre/pcrelib/pcre.h" | ||
| 18 | #endif | ||
| 19 | #else | ||
| 20 | #include "pcre.h" | ||
| 21 | #endif | ||
| 22 | |||
| 23 | #ifdef SP_HAS_PCRE2 | ||
| 24 | #define sp_pcre pcre2_code | ||
| 25 | #else | ||
| 26 | #define sp_pcre pcre | ||
| 27 | #endif | ||
| 28 | |||
| 29 | sp_pcre* sp_pcre_compile(const char* str); | ||
| 30 | #define sp_is_regexp_matching(regexp, str) \ | ||
| 31 | 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); | ||
| 33 | |||
| 34 | #endif // SP_PCRE_COMPAT_H | ||
diff --git a/src/sp_utils.c b/src/sp_utils.c index 0625a2f..2979d98 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c | |||
| @@ -32,25 +32,6 @@ void sp_log_msg(char const* feature, char const* level, const char* fmt, ...) { | |||
| 32 | client_ip ? client_ip : "0.0.0.0", feature, level, msg); | 32 | client_ip ? client_ip : "0.0.0.0", feature, level, msg); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | zend_always_inline int is_regexp_matching(const pcre* regexp, const char* str) { | ||
| 36 | int vec[30]; | ||
| 37 | int ret = 0; | ||
| 38 | |||
| 39 | assert(NULL != regexp); | ||
| 40 | assert(NULL != str); | ||
| 41 | |||
| 42 | ret = sp_pcre_exec(regexp, NULL, str, strlen(str), 0, 0, vec, | ||
| 43 | sizeof(vec) / sizeof(int)); | ||
| 44 | |||
| 45 | if (ret < 0) { | ||
| 46 | if (ret != PCRE_ERROR_NOMATCH) { | ||
| 47 | sp_log_err("regexp", "Something went wrong with a regexp (%d).", ret); | ||
| 48 | } | ||
| 49 | return false; | ||
| 50 | } | ||
| 51 | return true; | ||
| 52 | } | ||
| 53 | |||
| 54 | int compute_hash(const char* const filename, char* file_hash) { | 35 | int compute_hash(const char* const filename, char* file_hash) { |
| 55 | unsigned char buf[1024]; | 36 | unsigned char buf[1024]; |
| 56 | unsigned char digest[SHA256_SIZE]; | 37 | unsigned char digest[SHA256_SIZE]; |
| @@ -192,13 +173,13 @@ char* sp_convert_to_string(zval* zv) { | |||
| 192 | return estrdup(""); | 173 | return estrdup(""); |
| 193 | } | 174 | } |
| 194 | 175 | ||
| 195 | bool sp_match_value(const char* value, const char* to_match, const pcre* rx) { | 176 | bool sp_match_value(const char* value, const char* to_match, const sp_pcre* rx) { |
| 196 | if (to_match) { | 177 | if (to_match) { |
| 197 | if (0 == strcmp(to_match, value)) { | 178 | if (0 == strcmp(to_match, value)) { |
| 198 | return true; | 179 | return true; |
| 199 | } | 180 | } |
| 200 | } else if (rx) { | 181 | } else if (rx) { |
| 201 | return is_regexp_matching(rx, value); | 182 | return sp_is_regexp_matching(rx, value); |
| 202 | } else { | 183 | } else { |
| 203 | return true; | 184 | return true; |
| 204 | } | 185 | } |
| @@ -274,7 +255,7 @@ void sp_log_disable_ret(const char* restrict path, | |||
| 274 | } | 255 | } |
| 275 | } | 256 | } |
| 276 | 257 | ||
| 277 | bool sp_match_array_key(const zval* zv, const char* to_match, const pcre* rx) { | 258 | bool sp_match_array_key(const zval* zv, const char* to_match, const sp_pcre* rx) { |
| 278 | zend_string* key; | 259 | zend_string* key; |
| 279 | zend_ulong idx; | 260 | zend_ulong idx; |
| 280 | 261 | ||
| @@ -298,7 +279,7 @@ bool sp_match_array_key(const zval* zv, const char* to_match, const pcre* rx) { | |||
| 298 | } | 279 | } |
| 299 | 280 | ||
| 300 | bool sp_match_array_value(const zval* arr, const char* to_match, | 281 | bool sp_match_array_value(const zval* arr, const char* to_match, |
| 301 | const pcre* rx) { | 282 | const sp_pcre* rx) { |
| 302 | zval* value; | 283 | zval* value; |
| 303 | 284 | ||
| 304 | ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), value) { | 285 | ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), value) { |
| @@ -368,7 +349,7 @@ int hook_function(const char* original_name, HashTable* hook_table, | |||
| 368 | return SUCCESS; | 349 | return SUCCESS; |
| 369 | } | 350 | } |
| 370 | 351 | ||
| 371 | int hook_regexp(const pcre* regexp, HashTable* hook_table, | 352 | int hook_regexp(const sp_pcre* regexp, HashTable* hook_table, |
| 372 | void (*new_function)(INTERNAL_FUNCTION_PARAMETERS), | 353 | void (*new_function)(INTERNAL_FUNCTION_PARAMETERS), |
| 373 | bool hook_execution_table) { | 354 | bool hook_execution_table) { |
| 374 | zend_string* key; | 355 | zend_string* key; |
| @@ -377,9 +358,7 @@ int hook_regexp(const pcre* regexp, HashTable* hook_table, | |||
| 377 | 358 | ||
| 378 | ZEND_HASH_FOREACH_STR_KEY(ht, key) { | 359 | ZEND_HASH_FOREACH_STR_KEY(ht, key) { |
| 379 | if (key) { | 360 | if (key) { |
| 380 | int vec[30]; | 361 | int ret = sp_is_regexp_matching_len(regexp, key->val, key->len); |
| 381 | int ret = sp_pcre_exec(regexp, NULL, key->val, key->len, 0, 0, vec, | ||
| 382 | sizeof(vec) / sizeof(int)); | ||
| 383 | if (ret < 0) { /* Error or no match*/ | 362 | if (ret < 0) { /* Error or no match*/ |
| 384 | if (PCRE_ERROR_NOMATCH != ret) { | 363 | if (PCRE_ERROR_NOMATCH != ret) { |
| 385 | sp_log_err("pcre", "Runtime error with pcre, error code: %d", ret); | 364 | sp_log_err("pcre", "Runtime error with pcre, error code: %d", ret); |
diff --git a/src/sp_utils.h b/src/sp_utils.h index ada7cf6..10a6daa 100644 --- a/src/sp_utils.h +++ b/src/sp_utils.h | |||
| @@ -46,17 +46,16 @@ | |||
| 46 | void sp_log_msg(char const *feature, char const *level, const char *fmt, ...); | 46 | void sp_log_msg(char const *feature, char const *level, const char *fmt, ...); |
| 47 | int compute_hash(const char *const filename, char *file_hash); | 47 | int compute_hash(const char *const filename, char *file_hash); |
| 48 | char *sp_convert_to_string(zval *); | 48 | char *sp_convert_to_string(zval *); |
| 49 | bool sp_match_value(const char *, const char *, const pcre *); | 49 | bool sp_match_value(const char *, const char *, const sp_pcre *); |
| 50 | bool sp_match_array_key(const zval *, const char *, const pcre *); | 50 | bool sp_match_array_key(const zval *, const char *, const sp_pcre *); |
| 51 | bool sp_match_array_value(const zval *, const char *, const pcre *); | 51 | bool sp_match_array_value(const zval *, const char *, const sp_pcre *); |
| 52 | void sp_log_disable(const char *restrict, const char *restrict, | 52 | void sp_log_disable(const char *restrict, const char *restrict, |
| 53 | const char *restrict, const sp_disabled_function *); | 53 | const char *restrict, const sp_disabled_function *); |
| 54 | void sp_log_disable_ret(const char *restrict, const char *restrict, | 54 | void sp_log_disable_ret(const char *restrict, const char *restrict, |
| 55 | const sp_disabled_function *); | 55 | const sp_disabled_function *); |
| 56 | int is_regexp_matching(const pcre *, const char *); | ||
| 57 | int hook_function(const char *, HashTable *, | 56 | int hook_function(const char *, HashTable *, |
| 58 | void (*)(INTERNAL_FUNCTION_PARAMETERS), bool); | 57 | void (*)(INTERNAL_FUNCTION_PARAMETERS), bool); |
| 59 | int hook_regexp(const pcre *, HashTable *, | 58 | int hook_regexp(const sp_pcre *, HashTable *, |
| 60 | void (*)(INTERNAL_FUNCTION_PARAMETERS), bool); | 59 | void (*)(INTERNAL_FUNCTION_PARAMETERS), bool); |
| 61 | bool check_is_in_eval_whitelist(const char * const function_name); | 60 | bool check_is_in_eval_whitelist(const char * const function_name); |
| 62 | 61 | ||
diff --git a/src/sp_var_parser.c b/src/sp_var_parser.c index d0ae67c..330fa54 100644 --- a/src/sp_var_parser.c +++ b/src/sp_var_parser.c | |||
| @@ -20,26 +20,22 @@ static sp_list_node *parse_str_tokens(const char *str, const sp_conf_token token | |||
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | static bool is_var_name_valid(const char *name) { | 22 | static bool is_var_name_valid(const char *name) { |
| 23 | static pcre *regexp_const = NULL; | 23 | static sp_pcre *regexp_const = NULL; |
| 24 | static pcre *regexp_var = NULL; | 24 | static sp_pcre *regexp_var = NULL; |
| 25 | const char *pcre_error; | ||
| 26 | int pcre_error_offset; | ||
| 27 | 25 | ||
| 28 | if (!name) { | 26 | if (!name) { |
| 29 | return false; | 27 | return false; |
| 30 | } | 28 | } |
| 31 | if (NULL == regexp_var || NULL == regexp_const) { | 29 | if (NULL == regexp_var || NULL == regexp_const) { |
| 32 | regexp_var = sp_pcre_compile(REGEXP_VAR, PCRE_CASELESS, &pcre_error, | 30 | regexp_var = sp_pcre_compile(REGEXP_VAR); |
| 33 | &pcre_error_offset, NULL); | 31 | regexp_const = sp_pcre_compile(REGEXP_CONST); |
| 34 | regexp_const = sp_pcre_compile(REGEXP_CONST, PCRE_CASELESS, &pcre_error, | ||
| 35 | &pcre_error_offset, NULL); | ||
| 36 | } | 32 | } |
| 37 | if (NULL == regexp_var || NULL == regexp_const) { | 33 | if (NULL == regexp_var || NULL == regexp_const) { |
| 38 | sp_log_err("config", "Could not compile regexp."); | 34 | sp_log_err("config", "Could not compile regexp."); |
| 39 | return false; | 35 | return false; |
| 40 | } | 36 | } |
| 41 | if (0 > sp_pcre_exec(regexp_var, NULL, name, strlen(name), 0, 0, NULL, 0) && | 37 | if ((false == sp_is_regexp_matching(regexp_var, name)) && |
| 42 | 0 > sp_pcre_exec(regexp_const, NULL, name, strlen(name), 0, 0, NULL, 0)) { | 38 | (false == sp_is_regexp_matching(regexp_const, name))) { |
| 43 | return false; | 39 | return false; |
| 44 | } | 40 | } |
| 45 | return true; | 41 | return true; |
diff --git a/src/tests/broken_conf_config_regexp.phpt b/src/tests/broken_conf_config_regexp.phpt index d2a379e..e49788c 100644 --- a/src/tests/broken_conf_config_regexp.phpt +++ b/src/tests/broken_conf_config_regexp.phpt | |||
| @@ -5,6 +5,6 @@ Broken configuration | |||
| 5 | --INI-- | 5 | --INI-- |
| 6 | sp.configuration_file={PWD}/config/broken_config_regexp.ini | 6 | sp.configuration_file={PWD}/config/broken_config_regexp.ini |
| 7 | --FILE-- | 7 | --FILE-- |
| 8 | --EXPECT-- | 8 | --EXPECTF-- |
| 9 | [snuffleupagus][0.0.0.0][config][error] Failed to compile '*.': nothing to repeat on line 1. | 9 | [snuffleupagus][0.0.0.0][config][error] Failed to compile '*.': %aon line 1. |
| 10 | [snuffleupagus][0.0.0.0][config][error] '.filename_r()' is expecting a valid regexp, and not '"*."' on line 1. | 10 | [snuffleupagus][0.0.0.0][config][error] '.filename_r()' is expecting a valid regexp, and not '"*."' on line 1. |
diff --git a/src/tests/broken_conf_shown_in_phpinfo.phpt b/src/tests/broken_conf_shown_in_phpinfo.phpt index 61e9512..5053ee0 100644 --- a/src/tests/broken_conf_shown_in_phpinfo.phpt +++ b/src/tests/broken_conf_shown_in_phpinfo.phpt | |||
| @@ -16,7 +16,7 @@ if (strstr($info, 'Valid config => no') !== FALSE) { | |||
| 16 | echo "lose"; | 16 | echo "lose"; |
| 17 | } | 17 | } |
| 18 | ?> | 18 | ?> |
| 19 | --EXPECT-- | 19 | --EXPECTF-- |
| 20 | [snuffleupagus][0.0.0.0][config][error] Failed to compile '*.': nothing to repeat on line 1. | 20 | [snuffleupagus][0.0.0.0][config][error] Failed to compile '*.': %aon line 1. |
| 21 | [snuffleupagus][0.0.0.0][config][error] '.filename_r()' is expecting a valid regexp, and not '"*."' on line 1. | 21 | [snuffleupagus][0.0.0.0][config][error] '.filename_r()' is expecting a valid regexp, and not '"*."' on line 1. |
| 22 | win | 22 | win |
diff --git a/src/tests/broken_regexp.phpt b/src/tests/broken_regexp.phpt index 3f027f1..7c7ac9c 100644 --- a/src/tests/broken_regexp.phpt +++ b/src/tests/broken_regexp.phpt | |||
| @@ -6,5 +6,5 @@ Broken regexp | |||
| 6 | sp.configuration_file={PWD}/config/broken_regexp.ini | 6 | sp.configuration_file={PWD}/config/broken_regexp.ini |
| 7 | --FILE-- | 7 | --FILE-- |
| 8 | --EXPECTF-- | 8 | --EXPECTF-- |
| 9 | [snuffleupagus][0.0.0.0][config][error] Failed to compile '^$[': missing terminating ] for character class on line 1. | 9 | [snuffleupagus][0.0.0.0][config][error] Failed to compile '^$[': %aon line 1. |
| 10 | [snuffleupagus][0.0.0.0][config][error] '.value_r()' is expecting a valid regexp, and not '"^$["' on line 1. | 10 | [snuffleupagus][0.0.0.0][config][error] '.value_r()' is expecting a valid regexp, and not '"^$["' on line 1. |
