From 618e675b5d1cb2099464a198a568a129616164b0 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Fri, 6 May 2022 21:20:44 +0200 Subject: Silence a compiler warning --- src/sp_utils.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/sp_utils.c') diff --git a/src/sp_utils.c b/src/sp_utils.c index 6161859..df2f0d6 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c @@ -448,6 +448,7 @@ void unhook_functions(HashTable *ht) { if (func && func->type == ZEND_INTERNAL_FUNCTION && orig_handler) { func->internal_function.handler = orig_handler; } + (void)idx;//silence a -Wunused-but-set-variable ZEND_HASH_FOREACH_END_DEL(); } -- cgit v1.3 From a5f070cd7d982ae96ad72fb79420407574e7682a Mon Sep 17 00:00:00 2001 From: jvoisin Date: Mon, 27 Jun 2022 20:55:20 +0200 Subject: Dump the eval'ed code --- src/php_snuffleupagus.h | 7 +++++++ src/sp_execute.c | 2 ++ src/sp_utils.c | 9 +++++++++ src/tests/dump_request/dump_eval_blacklist.phpt | 2 ++ 4 files changed, 20 insertions(+) (limited to 'src/sp_utils.c') diff --git a/src/php_snuffleupagus.h b/src/php_snuffleupagus.h index 97fa0e4..a4a0ed4 100644 --- a/src/php_snuffleupagus.h +++ b/src/php_snuffleupagus.h @@ -148,6 +148,13 @@ u_long execution_depth; HashTable *disabled_functions_hook; HashTable *sp_internal_functions_hook; HashTable *sp_eval_blacklist_functions_hook; + +#if PHP_VERSION_ID >= 80000 +zend_string* eval_source_string; +#else +zval* eval_source_string; +#endif + ZEND_END_MODULE_GLOBALS(snuffleupagus) ZEND_EXTERN_MODULE_GLOBALS(snuffleupagus) diff --git a/src/sp_execute.c b/src/sp_execute.c index b81f408..a8798e4 100644 --- a/src/sp_execute.c +++ b/src/sp_execute.c @@ -302,6 +302,8 @@ ZEND_API zend_op_array* sp_compile_string(zend_string* source_string, #else ZEND_API zend_op_array* sp_compile_string(zval* source_string, char* filename) { #endif + // TODO(jvoisin) handle recursive calls to `eval` + SPG(eval_source_string) = source_string; zend_op_array* opline = orig_zend_compile_string(source_string, filename); sp_sloppy_modify_opcode(opline); return opline; diff --git a/src/sp_utils.c b/src/sp_utils.c index df2f0d6..d7200b1 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c @@ -177,6 +177,15 @@ int sp_log_request(const zend_string* restrict folder, const zend_string* restri ZEND_HASH_FOREACH_END(); fputs("\n", file); } + + if (UNEXPECTED(0 != SPG(in_eval))) { +#if PHP_VERSION_ID >= 80000 + fprintf(file, "EVAL_CODE: %s\n", ZSTR_VAL(SPG(eval_source_string))); +#else + fprintf(file, "EVAL_CODE: %s\n", ZSTR_VAL(zval_get_string(SPG(eval_source_string)))); +#endif + } + fclose(file); return 0; diff --git a/src/tests/dump_request/dump_eval_blacklist.phpt b/src/tests/dump_request/dump_eval_blacklist.phpt index c9f48e4..a8c1618 100644 --- a/src/tests/dump_request/dump_eval_blacklist.phpt +++ b/src/tests/dump_request/dump_eval_blacklist.phpt @@ -38,6 +38,8 @@ if ($res[3] != "GET:get_a='data_get_a' get_b='data_get_b' \n") { echo "Invalid POST"; } elseif ($res[5] != "COOKIE:cookie_a='data_cookie_a&cookie_b=data_cookie_b' \n") { echo "Invalid COOKIE"; +} elseif ($res[6] != "EVAL_CODE: \$a = strtoupper(\"1234\");\n") { + echo "Invalid EVAL_CODE"; } ?> --EXPECTF-- -- cgit v1.3 From 86407a7347963c4d6eb532a770d38df6223976e0 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Mon, 27 Jun 2022 22:47:20 +0200 Subject: Minor code simplification --- src/sp_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/sp_utils.c') diff --git a/src/sp_utils.c b/src/sp_utils.c index d7200b1..2ec1750 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c @@ -182,7 +182,7 @@ int sp_log_request(const zend_string* restrict folder, const zend_string* restri #if PHP_VERSION_ID >= 80000 fprintf(file, "EVAL_CODE: %s\n", ZSTR_VAL(SPG(eval_source_string))); #else - fprintf(file, "EVAL_CODE: %s\n", ZSTR_VAL(zval_get_string(SPG(eval_source_string)))); + fprintf(file, "EVAL_CODE: %s\n", Z_STRVAL_P(SPG(eval_source_string))); #endif } -- cgit v1.3 From 3dbb2f3feeec54c4ab6b2efc53b5c5635dbd9129 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Wed, 13 Jul 2022 01:11:44 +0200 Subject: Mix the stacktrace in the sha256 for the filename of .dump() This should make it easier to fuzz using Snuffleupagus. --- src/sp_utils.c | 60 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 24 deletions(-) (limited to 'src/sp_utils.c') diff --git a/src/sp_utils.c b/src/sp_utils.c index 2ec1750..fdcdc99 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c @@ -93,32 +93,12 @@ int compute_hash(const char* const restrict filename, static int construct_filename(char* filename, const zend_string* restrict folder, const zend_string* restrict textual) { - PHP_SHA256_CTX context; - unsigned char digest[SHA256_SIZE] = {0}; - char strhash[65] = {0}; - - if (-1 == mkdir(ZSTR_VAL(folder), 0700) && errno != EEXIST) { - sp_log_warn("request_logging", "Unable to create the folder '%s'", - ZSTR_VAL(folder)); - return -1; - } - - /* We're using the sha256 sum of the rule's textual representation - * as filename, in order to only have one dump per rule, to mitigate - * DoS attacks. */ - PHP_SHA256Init(&context); - PHP_SHA256Update(&context, (const unsigned char*)ZSTR_VAL(textual), - ZSTR_LEN(textual)); - PHP_SHA256Final(digest, &context); - make_digest_ex(strhash, digest, SHA256_SIZE); - snprintf(filename, PATH_MAX - 1, "%s/sp_dump.%s", ZSTR_VAL(folder), strhash); - return 0; } int sp_log_request(const zend_string* restrict folder, const zend_string* restrict text_repr) { FILE* file; - const char* current_filename = zend_get_executed_filename(TSRMLS_C); + char const* const current_filename = zend_get_executed_filename(TSRMLS_C); const int current_line = zend_get_executed_lineno(TSRMLS_C); char filename[PATH_MAX] = {0}; const struct { @@ -128,9 +108,41 @@ int sp_log_request(const zend_string* restrict folder, const zend_string* restri {"COOKIE", TRACK_VARS_COOKIE}, {"SERVER", TRACK_VARS_SERVER}, {"ENV", TRACK_VARS_ENV}, {NULL, 0}}; - if (0 != construct_filename(filename, folder, text_repr)) { + PHP_SHA256_CTX context; + unsigned char digest[SHA256_SIZE] = {0}; + char strhash[65] = {0}; + + if (-1 == mkdir(ZSTR_VAL(folder), 0700) && errno != EEXIST) { + sp_log_warn("request_logging", "Unable to create the folder '%s'", + ZSTR_VAL(folder)); return -1; } + + /* We're using the sha256 sum of the rule's textual representation, as well + * as the stacktrace as filename, in order to only have one dump per rule, to + * mitigate DoS attacks. We're doing the walk-the-execution-context dance + * twice because it's easier than to cache it in a linked-list. It doesn't + * really matter, since this is a super-cold path anyway. + */ + PHP_SHA256Init(&context); + PHP_SHA256Update(&context, (const unsigned char*)ZSTR_VAL(text_repr), ZSTR_LEN(text_repr)); + zend_execute_data* orig_execute_data = EG(current_execute_data); + zend_execute_data* current = EG(current_execute_data); + while (current) { + EG(current_execute_data) = current; + char* const complete_path_function = get_complete_function_path(current); + if (complete_path_function) { + const int current_line = zend_get_executed_lineno(TSRMLS_C); + PHP_SHA256Update(&context, (const unsigned char*)complete_path_function, strlen(complete_path_function)); + efree(complete_path_function); + } + current = current->prev_execute_data; + } + EG(current_execute_data) = orig_execute_data; + PHP_SHA256Final(digest, &context); + make_digest_ex(strhash, digest, SHA256_SIZE); + snprintf(filename, PATH_MAX - 1, "%s/sp_dump.%s", ZSTR_VAL(folder), strhash); + if (NULL == (file = fopen(filename, "w+"))) { sp_log_warn("request_logging", "Unable to open %s: %s", filename, strerror(errno)); @@ -141,8 +153,8 @@ int sp_log_request(const zend_string* restrict folder, const zend_string* restri fprintf(file, "FILE: %s:%d\n", current_filename, current_line); - zend_execute_data* orig_execute_data = EG(current_execute_data); - zend_execute_data* current = EG(current_execute_data); + orig_execute_data = EG(current_execute_data); + current = EG(current_execute_data); while (current) { EG(current_execute_data) = current; char* const complete_path_function = get_complete_function_path(current); -- cgit v1.3 From a205a17fc49dfb6701fdc68c1f2b05f11cd1e56f Mon Sep 17 00:00:00 2001 From: jvoisin Date: Wed, 13 Jul 2022 02:10:44 +0200 Subject: Remove some dead code --- src/sp_utils.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'src/sp_utils.c') diff --git a/src/sp_utils.c b/src/sp_utils.c index fdcdc99..a8c84f9 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c @@ -90,12 +90,6 @@ int compute_hash(const char* const restrict filename, return SUCCESS; } -static int construct_filename(char* filename, - const zend_string* restrict folder, - const zend_string* restrict textual) { - return 0; -} - int sp_log_request(const zend_string* restrict folder, const zend_string* restrict text_repr) { FILE* file; char const* const current_filename = zend_get_executed_filename(TSRMLS_C); @@ -132,7 +126,6 @@ int sp_log_request(const zend_string* restrict folder, const zend_string* restri EG(current_execute_data) = current; char* const complete_path_function = get_complete_function_path(current); if (complete_path_function) { - const int current_line = zend_get_executed_lineno(TSRMLS_C); PHP_SHA256Update(&context, (const unsigned char*)complete_path_function, strlen(complete_path_function)); efree(complete_path_function); } -- cgit v1.3 From 7deb974c164d4f7cfbe13c5403d8cd36a0cbc2eb Mon Sep 17 00:00:00 2001 From: jvoisin Date: Wed, 13 Jul 2022 02:10:49 +0200 Subject: Minor micro-optimization --- src/sp_utils.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/sp_utils.c') diff --git a/src/sp_utils.c b/src/sp_utils.c index a8c84f9..57ecf67 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c @@ -142,7 +142,9 @@ int sp_log_request(const zend_string* restrict folder, const zend_string* restri return -1; } - fprintf(file, "RULE: %s\n", ZSTR_VAL(text_repr)); + fputs("RULE: ", file); + fputs(ZSTR_VAL(text_repr), file); + fputc('\n', file); fprintf(file, "FILE: %s:%d\n", current_filename, current_line); -- cgit v1.3 From ce95c32c91c1d78cfb7603699b6b10e54e931f45 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Wed, 13 Jul 2022 02:26:56 +0200 Subject: More micro-optimizations --- src/sp_utils.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'src/sp_utils.c') diff --git a/src/sp_utils.c b/src/sp_utils.c index 57ecf67..3436328 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c @@ -95,7 +95,7 @@ int sp_log_request(const zend_string* restrict folder, const zend_string* restri char const* const current_filename = zend_get_executed_filename(TSRMLS_C); const int current_line = zend_get_executed_lineno(TSRMLS_C); char filename[PATH_MAX] = {0}; - const struct { + static const struct { char const* const str; const int key; } zones[] = {{"GET", TRACK_VARS_GET}, {"POST", TRACK_VARS_POST}, @@ -146,7 +146,9 @@ int sp_log_request(const zend_string* restrict folder, const zend_string* restri fputs(ZSTR_VAL(text_repr), file); fputc('\n', file); - fprintf(file, "FILE: %s:%d\n", current_filename, current_line); + fputs("FILE: ", file); + fputs(current_filename, file); + fprintf(file, ":%d\n", current_line); orig_execute_data = EG(current_execute_data); current = EG(current_execute_data); @@ -155,7 +157,9 @@ int sp_log_request(const zend_string* restrict folder, const zend_string* restri char* const complete_path_function = get_complete_function_path(current); if (complete_path_function) { const int current_line = zend_get_executed_lineno(TSRMLS_C); - fprintf(file, "STACKTRACE: %s:%d\n", complete_path_function, current_line); + fputs("STACKTRACE: ", file); + fputs(complete_path_function, file); + fprintf(file, ":%d\n", current_line); efree(complete_path_function); } current = current->prev_execute_data; @@ -171,26 +175,30 @@ int sp_log_request(const zend_string* restrict folder, const zend_string* restri } HashTable* ht = Z_ARRVAL(PG(http_globals)[zones[i].key]); - fprintf(file, "%s:", zones[i].str); + fputs(zones[i].str, file); + fputc(':', file); ZEND_HASH_FOREACH_STR_KEY_VAL(ht, variable_key, variable_value) { - smart_str a; - - memset(&a, 0, sizeof(a)); + smart_str a = {0}; php_var_export_ex(variable_value, 1, &a); ZSTR_VAL(a.s)[ZSTR_LEN(a.s)] = '\0'; - fprintf(file, "%s=%s ", ZSTR_VAL(variable_key), ZSTR_VAL(a.s)); + fputs(ZSTR_VAL(variable_key), file); + fputc('=', file); + fputs(ZSTR_VAL(a.s), file); + fputc(' ', file); zend_string_release(a.s); } ZEND_HASH_FOREACH_END(); - fputs("\n", file); + fputc('\n', file); } if (UNEXPECTED(0 != SPG(in_eval))) { + fputs("EVAL_CODE: ", file); #if PHP_VERSION_ID >= 80000 - fprintf(file, "EVAL_CODE: %s\n", ZSTR_VAL(SPG(eval_source_string))); + fputs(ZSTR_VAL(SPG(eval_source_string)), file); #else - fprintf(file, "EVAL_CODE: %s\n", Z_STRVAL_P(SPG(eval_source_string))); + fputs(Z_STRVAL_P(SPG(eval_source_string)), file); #endif + fputc('\n', file); } fclose(file); -- cgit v1.3 From ed87e551efd0160f1944a5e97158ab258db65eaf Mon Sep 17 00:00:00 2001 From: jvoisin Date: Wed, 13 Jul 2022 21:25:04 +0200 Subject: Even more const! --- src/sp_utils.c | 10 +++++----- src/sp_utils.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/sp_utils.c') diff --git a/src/sp_utils.c b/src/sp_utils.c index 3436328..42f7871 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c @@ -1,6 +1,6 @@ #include "php_snuffleupagus.h" -static const char* default_ipaddr = "0.0.0.0"; +static char const* const default_ipaddr = "0.0.0.0"; const char* get_ipaddr() { const char* client_ip = getenv("REMOTE_ADDR"); if (client_ip) { @@ -15,8 +15,8 @@ const char* get_ipaddr() { return default_ipaddr; } -void sp_log_msgf(char const* restrict feature, int level, int type, - const char* restrict fmt, ...) { +void sp_log_msgf(char const* const restrict feature, int level, int type, + char const* const restrict fmt, ...) { char* msg; va_list args; @@ -63,7 +63,7 @@ void sp_log_msgf(char const* restrict feature, int level, int type, } } -int compute_hash(const char* const restrict filename, +int compute_hash(char const* const restrict filename, char* restrict file_hash) { unsigned char buf[1024] = {0}; unsigned char digest[SHA256_SIZE] = {0}; @@ -90,7 +90,7 @@ int compute_hash(const char* const restrict filename, return SUCCESS; } -int sp_log_request(const zend_string* restrict folder, const zend_string* restrict text_repr) { +int sp_log_request(zend_string const* const restrict folder, zend_string const* const restrict text_repr) { FILE* file; char const* const current_filename = zend_get_executed_filename(TSRMLS_C); const int current_line = zend_get_executed_lineno(TSRMLS_C); diff --git a/src/sp_utils.h b/src/sp_utils.h index 0e595d8..7bab4ba 100644 --- a/src/sp_utils.h +++ b/src/sp_utils.h @@ -71,8 +71,8 @@ extern int sp_debug_stderr; #define GET_SUFFIX(x) (x == 1) ? "st" : ((x == 2) ? "nd" : "th") const char *get_ipaddr(void); -void sp_log_msgf(char const *restrict feature, int level, int type, const char *restrict fmt, ...); -int compute_hash(const char *const restrict filename, char *restrict file_hash); +void sp_log_msgf(char const* const restrict feature, int level, int type, char const* const restrict fmt, ...); +int compute_hash(char const* const restrict filename, char *restrict file_hash); const zend_string *sp_zval_to_zend_string(const zval *); bool sp_match_value(const zend_string* value, const zend_string* to_match, const sp_regexp* rx); bool sp_match_array_key(const zval *, const zend_string *, const sp_regexp *); @@ -83,7 +83,7 @@ bool hook_function(const char *, HashTable *, zif_handler); void unhook_functions(HashTable *ht); int hook_regexp(const sp_pcre *, HashTable *, zif_handler); bool check_is_in_eval_whitelist(const char* function_name); -int sp_log_request(const zend_string *restrict folder, const zend_string *restrict text_repr); +int sp_log_request(zend_string const* const restrict folder, zend_string const* const restrict text_repr); #define sp_zend_string_equals(s1, s2) zend_string_equals((zend_string*)s1, (zend_string*)s2) static inline bool sp_zend_string_equals_str(const zend_string* s1, const char *str, size_t len) { return (ZSTR_LEN(s1) == len && !memcmp(ZSTR_VAL(s1), str, len)); -- cgit v1.3