diff options
Diffstat (limited to 'src/sp_utils.c')
| -rw-r--r-- | src/sp_utils.c | 107 |
1 files changed, 66 insertions, 41 deletions
diff --git a/src/sp_utils.c b/src/sp_utils.c index 6161859..42f7871 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #include "php_snuffleupagus.h" | 1 | #include "php_snuffleupagus.h" |
| 2 | 2 | ||
| 3 | static const char* default_ipaddr = "0.0.0.0"; | 3 | static char const* const default_ipaddr = "0.0.0.0"; |
| 4 | const char* get_ipaddr() { | 4 | const char* get_ipaddr() { |
| 5 | const char* client_ip = getenv("REMOTE_ADDR"); | 5 | const char* client_ip = getenv("REMOTE_ADDR"); |
| 6 | if (client_ip) { | 6 | if (client_ip) { |
| @@ -15,8 +15,8 @@ const char* get_ipaddr() { | |||
| 15 | return default_ipaddr; | 15 | return default_ipaddr; |
| 16 | } | 16 | } |
| 17 | 17 | ||
| 18 | void sp_log_msgf(char const* restrict feature, int level, int type, | 18 | void sp_log_msgf(char const* const restrict feature, int level, int type, |
| 19 | const char* restrict fmt, ...) { | 19 | char const* const restrict fmt, ...) { |
| 20 | char* msg; | 20 | char* msg; |
| 21 | va_list args; | 21 | va_list args; |
| 22 | 22 | ||
| @@ -63,7 +63,7 @@ void sp_log_msgf(char const* restrict feature, int level, int type, | |||
| 63 | } | 63 | } |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | int compute_hash(const char* const restrict filename, | 66 | int compute_hash(char const* const restrict filename, |
| 67 | char* restrict file_hash) { | 67 | char* restrict file_hash) { |
| 68 | unsigned char buf[1024] = {0}; | 68 | unsigned char buf[1024] = {0}; |
| 69 | unsigned char digest[SHA256_SIZE] = {0}; | 69 | unsigned char digest[SHA256_SIZE] = {0}; |
| @@ -90,9 +90,18 @@ int compute_hash(const char* const restrict filename, | |||
| 90 | return SUCCESS; | 90 | return SUCCESS; |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | static int construct_filename(char* filename, | 93 | int sp_log_request(zend_string const* const restrict folder, zend_string const* const restrict text_repr) { |
| 94 | const zend_string* restrict folder, | 94 | FILE* file; |
| 95 | const zend_string* restrict textual) { | 95 | char const* const current_filename = zend_get_executed_filename(TSRMLS_C); |
| 96 | const int current_line = zend_get_executed_lineno(TSRMLS_C); | ||
| 97 | char filename[PATH_MAX] = {0}; | ||
| 98 | static const struct { | ||
| 99 | char const* const str; | ||
| 100 | const int key; | ||
| 101 | } zones[] = {{"GET", TRACK_VARS_GET}, {"POST", TRACK_VARS_POST}, | ||
| 102 | {"COOKIE", TRACK_VARS_COOKIE}, {"SERVER", TRACK_VARS_SERVER}, | ||
| 103 | {"ENV", TRACK_VARS_ENV}, {NULL, 0}}; | ||
| 104 | |||
| 96 | PHP_SHA256_CTX context; | 105 | PHP_SHA256_CTX context; |
| 97 | unsigned char digest[SHA256_SIZE] = {0}; | 106 | unsigned char digest[SHA256_SIZE] = {0}; |
| 98 | char strhash[65] = {0}; | 107 | char strhash[65] = {0}; |
| @@ -103,52 +112,54 @@ static int construct_filename(char* filename, | |||
| 103 | return -1; | 112 | return -1; |
| 104 | } | 113 | } |
| 105 | 114 | ||
| 106 | /* We're using the sha256 sum of the rule's textual representation | 115 | /* We're using the sha256 sum of the rule's textual representation, as well |
| 107 | * as filename, in order to only have one dump per rule, to mitigate | 116 | * as the stacktrace as filename, in order to only have one dump per rule, to |
| 108 | * DoS attacks. */ | 117 | * mitigate DoS attacks. We're doing the walk-the-execution-context dance |
| 118 | * twice because it's easier than to cache it in a linked-list. It doesn't | ||
| 119 | * really matter, since this is a super-cold path anyway. | ||
| 120 | */ | ||
| 109 | PHP_SHA256Init(&context); | 121 | PHP_SHA256Init(&context); |
| 110 | PHP_SHA256Update(&context, (const unsigned char*)ZSTR_VAL(textual), | 122 | PHP_SHA256Update(&context, (const unsigned char*)ZSTR_VAL(text_repr), ZSTR_LEN(text_repr)); |
| 111 | ZSTR_LEN(textual)); | 123 | zend_execute_data* orig_execute_data = EG(current_execute_data); |
| 124 | zend_execute_data* current = EG(current_execute_data); | ||
| 125 | while (current) { | ||
| 126 | EG(current_execute_data) = current; | ||
| 127 | char* const complete_path_function = get_complete_function_path(current); | ||
| 128 | if (complete_path_function) { | ||
| 129 | PHP_SHA256Update(&context, (const unsigned char*)complete_path_function, strlen(complete_path_function)); | ||
| 130 | efree(complete_path_function); | ||
| 131 | } | ||
| 132 | current = current->prev_execute_data; | ||
| 133 | } | ||
| 134 | EG(current_execute_data) = orig_execute_data; | ||
| 112 | PHP_SHA256Final(digest, &context); | 135 | PHP_SHA256Final(digest, &context); |
| 113 | make_digest_ex(strhash, digest, SHA256_SIZE); | 136 | make_digest_ex(strhash, digest, SHA256_SIZE); |
| 114 | snprintf(filename, PATH_MAX - 1, "%s/sp_dump.%s", ZSTR_VAL(folder), strhash); | 137 | snprintf(filename, PATH_MAX - 1, "%s/sp_dump.%s", ZSTR_VAL(folder), strhash); |
| 115 | 138 | ||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | int sp_log_request(const zend_string* restrict folder, const zend_string* restrict text_repr) { | ||
| 120 | FILE* file; | ||
| 121 | const char* current_filename = zend_get_executed_filename(TSRMLS_C); | ||
| 122 | const int current_line = zend_get_executed_lineno(TSRMLS_C); | ||
| 123 | char filename[PATH_MAX] = {0}; | ||
| 124 | const struct { | ||
| 125 | char const* const str; | ||
| 126 | const int key; | ||
| 127 | } zones[] = {{"GET", TRACK_VARS_GET}, {"POST", TRACK_VARS_POST}, | ||
| 128 | {"COOKIE", TRACK_VARS_COOKIE}, {"SERVER", TRACK_VARS_SERVER}, | ||
| 129 | {"ENV", TRACK_VARS_ENV}, {NULL, 0}}; | ||
| 130 | |||
| 131 | if (0 != construct_filename(filename, folder, text_repr)) { | ||
| 132 | return -1; | ||
| 133 | } | ||
| 134 | if (NULL == (file = fopen(filename, "w+"))) { | 139 | if (NULL == (file = fopen(filename, "w+"))) { |
| 135 | sp_log_warn("request_logging", "Unable to open %s: %s", filename, | 140 | sp_log_warn("request_logging", "Unable to open %s: %s", filename, |
| 136 | strerror(errno)); | 141 | strerror(errno)); |
| 137 | return -1; | 142 | return -1; |
| 138 | } | 143 | } |
| 139 | 144 | ||
| 140 | fprintf(file, "RULE: %s\n", ZSTR_VAL(text_repr)); | 145 | fputs("RULE: ", file); |
| 146 | fputs(ZSTR_VAL(text_repr), file); | ||
| 147 | fputc('\n', file); | ||
| 141 | 148 | ||
| 142 | fprintf(file, "FILE: %s:%d\n", current_filename, current_line); | 149 | fputs("FILE: ", file); |
| 150 | fputs(current_filename, file); | ||
| 151 | fprintf(file, ":%d\n", current_line); | ||
| 143 | 152 | ||
| 144 | zend_execute_data* orig_execute_data = EG(current_execute_data); | 153 | orig_execute_data = EG(current_execute_data); |
| 145 | zend_execute_data* current = EG(current_execute_data); | 154 | current = EG(current_execute_data); |
| 146 | while (current) { | 155 | while (current) { |
| 147 | EG(current_execute_data) = current; | 156 | EG(current_execute_data) = current; |
| 148 | char* const complete_path_function = get_complete_function_path(current); | 157 | char* const complete_path_function = get_complete_function_path(current); |
| 149 | if (complete_path_function) { | 158 | if (complete_path_function) { |
| 150 | const int current_line = zend_get_executed_lineno(TSRMLS_C); | 159 | const int current_line = zend_get_executed_lineno(TSRMLS_C); |
| 151 | fprintf(file, "STACKTRACE: %s:%d\n", complete_path_function, current_line); | 160 | fputs("STACKTRACE: ", file); |
| 161 | fputs(complete_path_function, file); | ||
| 162 | fprintf(file, ":%d\n", current_line); | ||
| 152 | efree(complete_path_function); | 163 | efree(complete_path_function); |
| 153 | } | 164 | } |
| 154 | current = current->prev_execute_data; | 165 | current = current->prev_execute_data; |
| @@ -164,19 +175,32 @@ int sp_log_request(const zend_string* restrict folder, const zend_string* restri | |||
| 164 | } | 175 | } |
| 165 | 176 | ||
| 166 | HashTable* ht = Z_ARRVAL(PG(http_globals)[zones[i].key]); | 177 | HashTable* ht = Z_ARRVAL(PG(http_globals)[zones[i].key]); |
| 167 | fprintf(file, "%s:", zones[i].str); | 178 | fputs(zones[i].str, file); |
| 179 | fputc(':', file); | ||
| 168 | ZEND_HASH_FOREACH_STR_KEY_VAL(ht, variable_key, variable_value) { | 180 | ZEND_HASH_FOREACH_STR_KEY_VAL(ht, variable_key, variable_value) { |
| 169 | smart_str a; | 181 | smart_str a = {0}; |
| 170 | |||
| 171 | memset(&a, 0, sizeof(a)); | ||
| 172 | php_var_export_ex(variable_value, 1, &a); | 182 | php_var_export_ex(variable_value, 1, &a); |
| 173 | ZSTR_VAL(a.s)[ZSTR_LEN(a.s)] = '\0'; | 183 | ZSTR_VAL(a.s)[ZSTR_LEN(a.s)] = '\0'; |
| 174 | fprintf(file, "%s=%s ", ZSTR_VAL(variable_key), ZSTR_VAL(a.s)); | 184 | fputs(ZSTR_VAL(variable_key), file); |
| 185 | fputc('=', file); | ||
| 186 | fputs(ZSTR_VAL(a.s), file); | ||
| 187 | fputc(' ', file); | ||
| 175 | zend_string_release(a.s); | 188 | zend_string_release(a.s); |
| 176 | } | 189 | } |
| 177 | ZEND_HASH_FOREACH_END(); | 190 | ZEND_HASH_FOREACH_END(); |
| 178 | fputs("\n", file); | 191 | fputc('\n', file); |
| 179 | } | 192 | } |
| 193 | |||
| 194 | if (UNEXPECTED(0 != SPG(in_eval))) { | ||
| 195 | fputs("EVAL_CODE: ", file); | ||
| 196 | #if PHP_VERSION_ID >= 80000 | ||
| 197 | fputs(ZSTR_VAL(SPG(eval_source_string)), file); | ||
| 198 | #else | ||
| 199 | fputs(Z_STRVAL_P(SPG(eval_source_string)), file); | ||
| 200 | #endif | ||
| 201 | fputc('\n', file); | ||
| 202 | } | ||
| 203 | |||
| 180 | fclose(file); | 204 | fclose(file); |
| 181 | 205 | ||
| 182 | return 0; | 206 | return 0; |
| @@ -448,6 +472,7 @@ void unhook_functions(HashTable *ht) { | |||
| 448 | if (func && func->type == ZEND_INTERNAL_FUNCTION && orig_handler) { | 472 | if (func && func->type == ZEND_INTERNAL_FUNCTION && orig_handler) { |
| 449 | func->internal_function.handler = orig_handler; | 473 | func->internal_function.handler = orig_handler; |
| 450 | } | 474 | } |
| 475 | (void)idx;//silence a -Wunused-but-set-variable | ||
| 451 | ZEND_HASH_FOREACH_END_DEL(); | 476 | ZEND_HASH_FOREACH_END_DEL(); |
| 452 | } | 477 | } |
| 453 | 478 | ||
