From 369070880213de7f7117ca4fcaaffab1d757dd7b Mon Sep 17 00:00:00 2001 From: Robert Paprocki Date: Wed, 22 Feb 2017 13:54:49 -0800 Subject: [PATCH 1/2] Don't leak an fd on fuzzy hash initialization Since we're re-opening this file with every invocation, let's close our sanity check fd. --- apache2/re_operators.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 4f748d77da..597891f561 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -3828,6 +3828,7 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) { #ifdef WITH_SSDEEP struct fuzzy_hash_param_data *param_data; + FILE *fp; char *file; int param_len,threshold; @@ -3876,14 +3877,15 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) } file = resolve_relative_path(rule->ruleset->mp, rule->filename, file); - - if (!fopen(file, "r")) + + fp = fopen(file, "r"); + if (!fp) { *error_msg = apr_psprintf(rule->ruleset->mp, "Not able to open file:" \ " %s.", file); return -1; } - + fclose(fp); param_data->file = file; param_data->threshold = threshold; From 578ea98f29da31a0c7714a6d821755682b2f01fb Mon Sep 17 00:00:00 2001 From: Robert Paprocki Date: Thu, 2 Mar 2017 13:52:45 -0800 Subject: [PATCH 2/2] Read fuzzy hash databases on init Instead of reading the fuzzy db on every invocation, read and store the db contents during initialization and store the contents in memory. The only significant behavior change here is that a change in db contents now (obviously) requires a daemon restart, as no API is provided to flush the list of ssdeep chunks. --- apache2/re.h | 6 +++++ apache2/re_operators.c | 53 +++++++++++++++++++++++++++--------------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/apache2/re.h b/apache2/re.h index 836e2af2b8..c0c5433965 100644 --- a/apache2/re.h +++ b/apache2/re.h @@ -409,8 +409,14 @@ struct msre_cache_rec { apr_size_t val_len; }; +struct fuzzy_hash_chunk { + const char *data; + struct fuzzy_hash_chunk *next; +}; + struct fuzzy_hash_param_data { const char *file; + struct fuzzy_hash_chunk *head; int threshold; }; diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 597891f561..e54a540700 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -1279,7 +1279,7 @@ static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) { strncmp(fn, "http://", strlen("http://")) == 0) { *error_msg = apr_psprintf(rule->ruleset->mp, "HTTPS address or " \ - "file path are expected for operator pmFromFile \"%s\"", fn); + "file path are expected for operator pmFromFile \"%s\"", fn); return 0; } else if (strlen(fn) > strlen("https://") && @@ -1316,7 +1316,7 @@ static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) { msc_remote_clean_chunk(&chunk); #else *error_msg = apr_psprintf(rule->ruleset->mp, "ModSecurity was not " \ - "compiled with Curl support, it cannot load: \"%s\"", fn); + "compiled with Curl support, it cannot load: \"%s\"", fn); return 0; #endif } @@ -3828,9 +3828,11 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) { #ifdef WITH_SSDEEP struct fuzzy_hash_param_data *param_data; + struct fuzzy_hash_chunk *chunk, *t; FILE *fp; char *file; int param_len,threshold; + char line[1024]; char *data = NULL; char *threshold_str = NULL; @@ -3838,6 +3840,8 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) param_data = apr_palloc(rule->ruleset->mp, sizeof(struct fuzzy_hash_param_data)); + param_data->head = NULL; + data = apr_pstrdup(rule->ruleset->mp, rule->op_param); threshold_str = data; #endif @@ -3885,6 +3889,28 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) " %s.", file); return -1; } + + while (read_line(line, sizeof(line), fp)) + { + chunk = apr_palloc(rule->ruleset->mp, + sizeof(struct fuzzy_hash_chunk)); + + chunk->data = apr_pstrdup(rule->ruleset->mp, line); + chunk->next = NULL; + + if (param_data->head == NULL) { + param_data->head = chunk; + } else { + t = param_data->head; + + while (t->next) { + t = t->next; + } + + t->next = chunk; + } + } + fclose(fp); param_data->file = file; @@ -3911,8 +3937,7 @@ static int msre_op_fuzzy_hash_execute(modsec_rec *msr, msre_rule *rule, #ifdef WITH_SSDEEP char result[FUZZY_MAX_RESULT]; struct fuzzy_hash_param_data *param = rule->op_param_data; - FILE *fp; - char line[1024]; + struct fuzzy_hash_chunk *chunk = param->head; #endif if (error_msg == NULL) @@ -3931,29 +3956,19 @@ static int msre_op_fuzzy_hash_execute(modsec_rec *msr, msre_rule *rule, return -1; } - fp = fopen(param->file, "r"); - if (!fp) - { - *error_msg = apr_psprintf(rule->ruleset->mp, "Not able to open " \ - "fuzzy hash file: %s", param->file); - - return 1; - } - - while (read_line(line, sizeof(line), fp)) + while (chunk != NULL) { - int i = fuzzy_compare(line, result); + int i = fuzzy_compare(chunk->data, result); + msr_log(msr, 9, "%d (%s)", i, chunk->data); if (i >= param->threshold) { *error_msg = apr_psprintf(msr->mp, "Fuzzy hash of %s matched " \ - "with %s (from: %s). Score: %d.", var->name, line, + "with %s (from: %s). Score: %d.", var->name, chunk->data, param->file, i); - fclose(fp); return 1; } + chunk = chunk->next; } - - fclose(fp); #else *error_msg = apr_psprintf(rule->ruleset->mp, "ModSecurity was not " \ "compiled with ssdeep support.");