diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5ca97df84..d931133834 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: - name: autogen.sh run: ./autogen.sh - name: configure ${{ matrix.configure.label }} - run: ./configure ${{ matrix.configure.opt }} + run: ./configure --enable-assertions ${{ matrix.configure.opt }} - uses: ammaraskar/gcc-problem-matcher@master - name: make run: make -j `nproc` diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 74c76a5810..c0464f50eb 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -30,6 +30,15 @@ APLOG_USE_MODULE(security2); #endif +// Returns the rule id if existing, otherwise the file name & line number +const char* id_log(msre_rule* rule) { + assert(rule != NULL); + assert(rule->actionset != NULL); + const char* id = rule->actionset->id; + if (!id || !*id || id == NOT_SET_P) id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); + return id; +} + /* -- Directory context creation and initialisation -- */ /** @@ -239,19 +248,19 @@ static void copy_rules_phase(apr_pool_t *mp, if (copy > 0) { #ifdef DEBUG_CONF - ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy rule %pp [id \"%s\"]", rule, rule->actionset->id); + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy rule %pp [id \"%s\"]", rule, id_log(rule)); #endif /* Copy the rule. */ *(msre_rule **)apr_array_push(child_phase_arr) = rule; - if (rule->actionset && rule->actionset->is_chained) mode = 2; + if (rule->actionset->is_chained) mode = 2; } else { - if (rule->actionset && rule->actionset->is_chained) mode = 1; + if (rule->actionset->is_chained) mode = 1; } } else { if (mode == 2) { #ifdef DEBUG_CONF - ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy chain %pp for rule %pp [id \"%s\"]", rule, rule->chain_starter, rule->chain_starter->actionset->id); + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy chain %pp for rule %pp [id \"%s\"]", rule, rule->chain_starter, id_log(rule->chain_starter)); #endif /* Copy the rule (it belongs to the chain we want to include. */ @@ -906,16 +915,14 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, */ rule->actionset = msre_actionset_merge(modsecurity->msre, cmd->pool, dcfg->tmp_default_actionset, rule->actionset, 1); + if (rule->actionset == NULL) return apr_psprintf(cmd->pool, "ModSecurity: cannot merge actionset (memory full?)."); /* Keep track of the parent action for "block" */ - if (rule->actionset) { - rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec; - rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action; - } + rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec; + rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action; /* Must NOT specify a disruptive action in logging phase. */ - if ((rule->actionset != NULL) - && (rule->actionset->phase == PHASE_LOGGING) + if ( (rule->actionset->phase == PHASE_LOGGING) && (rule->actionset->intercept_action != ACTION_ALLOW) && (rule->actionset->intercept_action != ACTION_ALLOW_REQUEST) && (rule->actionset->intercept_action != ACTION_NONE) @@ -926,9 +933,7 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, if (dcfg->tmp_chain_starter != NULL) { rule->chain_starter = dcfg->tmp_chain_starter; - if (rule->actionset) { - rule->actionset->phase = rule->chain_starter->actionset->phase; - } + rule->actionset->phase = rule->chain_starter->actionset->phase; } if (rule->actionset->is_chained != 1) { @@ -967,8 +972,7 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, #ifdef DEBUG_CONF ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, - "Adding rule %pp phase=%d id=\"%s\".", rule, rule->actionset->phase, (rule->actionset->id == NOT_SET_P - ? "(none)" : rule->actionset->id)); + "Adding rule %pp phase=%d id=\"%s\".", rule, rule->actionset->phase, id_log(rule)); #endif /* Add rule to the recipe. */ @@ -1042,8 +1046,7 @@ static const char *add_marker(cmd_parms *cmd, directory_config *dcfg, for (p = PHASE_FIRST; p <= PHASE_LAST; p++) { #ifdef DEBUG_CONF ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, - "Adding marker %pp phase=%d id=\"%s\".", rule, p, (rule->actionset->id == NOT_SET_P - ? "(none)" : rule->actionset->id)); + "Adding marker %pp phase=%d id=\"%s\".", rule, p, id_log(rule)); #endif if (msre_ruleset_rule_add(dcfg->ruleset, rule, p) < 0) { @@ -1091,11 +1094,7 @@ static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg, return NULL; } - /* Check the rule actionset */ - /* ENH: Can this happen? */ - if (rule->actionset == NULL) { - return apr_psprintf(cmd->pool, "ModSecurity: Attempt to update action for rule \"%s\" failed: Rule does not have an actionset.", p1); - } + assert(rule->actionset != NULL); /* Create a new actionset */ new_actionset = msre_actionset_create(modsecurity->msre, cmd->pool, p2, &my_error_msg); @@ -1117,9 +1116,7 @@ static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg, char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset); ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Update rule %pp id=\"%s\" old action: \"%s\"", - rule, - (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id), - actions); + rule, id_log(rule), actions); } #endif @@ -1127,6 +1124,7 @@ static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg, /* ENH: Will this leak the old actionset? */ rule->actionset = msre_actionset_merge(modsecurity->msre, cmd->pool, rule->actionset, new_actionset, 1); + if (rule->actionset == NULL) return apr_psprintf(cmd->pool, "ModSecurity: cannot merge actionset (memory full?)."); msre_actionset_set_defaults(rule->actionset); /* Update the unparsed rule */ @@ -1137,9 +1135,7 @@ static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg, char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset); ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Update rule %pp id=\"%s\" new action: \"%s\"", - rule, - (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id), - actions); + rule, id_log(rule), actions); } #endif @@ -1746,6 +1742,9 @@ char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2, config_orig_path = apr_pstrndup(mp, filename, strlen(filename) - strlen(apr_filepath_name_get(filename))); + if (config_orig_path == NULL) { + return apr_psprintf(mp, "ModSecurity: failed to duplicate filename in parser_conn_limits_operator"); + } apr_filepath_merge(&file, config_orig_path, param, APR_FILEPATH_TRUENAME, mp); @@ -2452,8 +2451,12 @@ static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg, const char *p1) { directory_config *dcfg = (directory_config *)_dcfg; - rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); if (dcfg == NULL) return NULL; + rule_exception* re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); + if (re == NULL) { + ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, cmd->pool, "cmd_rule_remove_by_id: Cannot allocate memory"); + return NULL; + } re->type = RULE_EXCEPTION_REMOVE_ID; re->param = p1; diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 6490d61b5d..5d2ef85bd9 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -179,12 +179,13 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, * Reads request body from a client. */ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg!= NULL); request_rec *r = msr->r; unsigned int finished_reading; apr_bucket_brigade *bb_in; apr_bucket *bucket; - if (error_msg == NULL) return -1; *error_msg = NULL; if (msr->reqbody_should_exist != 1) { @@ -368,6 +369,8 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { * run or not. */ static int output_filter_should_run(modsec_rec *msr, request_rec *r) { + assert(msr != NULL); + assert(r != NULL); char *content_type = NULL; /* Check configuration. */ @@ -429,10 +432,13 @@ static int output_filter_should_run(modsec_rec *msr, request_rec *r) { static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f, apr_bucket_brigade *bb_in) { + assert(msr != NULL); + assert(f != NULL); request_rec *r = f->r; const char *s_content_length = NULL; apr_status_t rc; + assert(msr != NULL); msr->of_brigade = apr_brigade_create(msr->mp, f->c->bucket_alloc); if (msr->of_brigade == NULL) { msr_log(msr, 1, "Output filter: Failed to create brigade."); @@ -496,6 +502,8 @@ static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f, * and to the client. */ static apr_status_t send_of_brigade(modsec_rec *msr, ap_filter_t *f) { + assert(msr != NULL); + assert(f != NULL); apr_status_t rc; rc = ap_pass_brigade(f->next, msr->of_brigade); @@ -537,6 +545,8 @@ static apr_status_t send_of_brigade(modsec_rec *msr, ap_filter_t *f) { * */ static void inject_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) { + assert(msr != NULL); + assert(f != NULL); apr_bucket *b; if (msr->txcfg->content_injection_enabled && msr->stream_output_data != NULL) { @@ -563,6 +573,8 @@ static void inject_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) { * */ static void prepend_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) { + assert(msr != NULL); + assert(f != NULL); if ((msr->txcfg->content_injection_enabled) && (msr->content_prepend) && (!msr->of_skipping)) { apr_bucket *bucket_ci = NULL; @@ -1008,6 +1020,12 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) { /* Now send data down the filter stream * (full-buffering only). */ + if (!eos_bucket) { + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server, + "ModSecurity: Internal Error: eos_bucket is NULL."); + return APR_EGENERAL; + } + if ((msr->of_skipping == 0)&&(!msr->of_partial)) { if(msr->of_stream_changed == 1) { inject_content_to_of_brigade(msr,f); diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c index d76da7558d..20ea940ee5 100644 --- a/apache2/apache2_util.c +++ b/apache2/apache2_util.c @@ -25,6 +25,8 @@ * Sends a brigade with an error bucket down the filter chain. */ apr_status_t send_error_bucket(modsec_rec *msr, ap_filter_t *f, int status) { + assert(msr != NULL); + assert(f != NULL); apr_bucket_brigade *brigade = NULL; apr_bucket *bucket = NULL; @@ -61,6 +63,9 @@ apr_status_t send_error_bucket(modsec_rec *msr, ap_filter_t *f, int status) { * the "output" parameter. */ int apache2_exec(modsec_rec *msr, const char *command, const char **argv, char **output) { + assert(msr != NULL); + assert(command != NULL); + apr_procattr_t *procattr = NULL; apr_proc_t *procnew = NULL; apr_status_t rc = APR_SUCCESS; @@ -204,6 +209,9 @@ char *get_env_var(request_rec *r, char *name) { static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *msr, int level, int fixup, const char *text, va_list ap) { + assert(r != NULL); + assert(msr != NULL); + assert(text != NULL); apr_size_t nbytes, nbytes_written; apr_file_t *debuglog_fd = NULL; int filter_debug_level = 0; @@ -303,6 +311,8 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec * * Apache error log if the message is important enough. */ void msr_log(modsec_rec *msr, int level, const char *text, ...) { + assert(msr != NULL); + assert(text != NULL); va_list ap; va_start(ap, text); @@ -316,6 +326,8 @@ void msr_log(modsec_rec *msr, int level, const char *text, ...) { * Apache error log. This is intended for error callbacks. */ void msr_log_error(modsec_rec *msr, const char *text, ...) { + assert(msr != NULL); + assert(text != NULL); va_list ap; va_start(ap, text); @@ -330,6 +342,8 @@ void msr_log_error(modsec_rec *msr, const char *text, ...) { * The 'text' will first be escaped. */ void msr_log_warn(modsec_rec *msr, const char *text, ...) { + assert(msr != NULL); + assert(text != NULL); va_list ap; va_start(ap, text); diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 7786543a12..0ee72865fc 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -475,6 +475,8 @@ static modsec_rec *retrieve_tx_context(request_rec *r) { * phases, redirections, or subrequests. */ static void store_tx_context(modsec_rec *msr, request_rec *r) { + assert(msr != NULL); + assert(r != NULL); apr_table_setn(r->notes, NOTE_MSR, (void *)msr); } @@ -491,7 +493,10 @@ static modsec_rec *create_tx_context(request_rec *r) { apr_allocator_create(&allocator); apr_allocator_max_free_set(allocator, 1024); apr_pool_create_ex(&msr->mp, r->pool, NULL, allocator); - if (msr->mp == NULL) return NULL; + if (msr->mp == NULL) { + apr_allocator_destroy(allocator); + return NULL; + } apr_allocator_owner_set(allocator, msr->mp); msr->modsecurity = modsecurity; @@ -863,6 +868,9 @@ static int hook_request_early(request_rec *r) { */ msr = create_tx_context(r); if (msr == NULL) return DECLINED; + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Context created after request failure."); + } #ifdef REQUEST_EARLY @@ -1150,17 +1158,12 @@ static void hook_error_log(const char *file, int line, int level, apr_status_t s #endif if (msr_ap_server) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 - msr = create_tx_context((request_rec *)info->r); + msr = create_tx_context((request_rec*)info->r); #else - msr = create_tx_context((request_rec *)r); + msr = create_tx_context((request_rec*)r); #endif - if (msr != NULL && msr->txcfg->debuglog_level >= 9) { - if (msr == NULL) { - msr_log(msr, 9, "Failed to create context after request failure."); - } - else { - msr_log(msr, 9, "Context created after request failure."); - } + if (msr && msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Context created after request failure."); } } if (msr == NULL) return; diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index af5294668b..d6f2034990 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -41,6 +41,8 @@ int DSOLOCAL *unicode_map_table = NULL; const char * msc_alert_message(modsec_rec *msr, msre_actionset *actionset, const char *action_message, const char *rule_message) { + assert(msr != NULL); + assert(actionset != NULL); const char *message = NULL; if (rule_message == NULL) rule_message = "Unknown error."; @@ -63,6 +65,8 @@ const char * msc_alert_message(modsec_rec *msr, msre_actionset *actionset, const void msc_alert(modsec_rec *msr, int level, msre_actionset *actionset, const char *action_message, const char *rule_message) { + assert(msr != NULL); + assert(actionset != NULL); const char *message = msc_alert_message(msr, actionset, action_message, rule_message); msr_log(msr, level, "%s", message); @@ -126,6 +130,11 @@ msc_engine *modsecurity_create(apr_pool_t *mp, int processing_mode) { int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { apr_status_t rc; + msce->auditlog_lock = msce->geo_lock = NULL; +#ifdef GLOBAL_COLLECTION_LOCK + msce->geo_lock = NULL; +#endif + /** * Notice that curl is initialized here but never cleaned up. First version * of this implementation curl was initialized and cleaned for every @@ -547,6 +556,7 @@ apr_status_t modsecurity_tx_init(modsec_rec *msr) { * */ static int is_response_status_relevant(modsec_rec *msr, int status) { + assert(msr != NULL); char *my_error_msg = NULL; apr_status_t rc; char buf[32]; @@ -780,6 +790,7 @@ static apr_status_t modsecurity_process_phase_logging(modsec_rec *msr) { * in the modsec_rec structure. */ apr_status_t modsecurity_process_phase(modsec_rec *msr, unsigned int phase) { + assert(msr != NULL); /* Check if we should run. */ if ((msr->was_intercepted)&&(phase != PHASE_LOGGING)) { if (msr->txcfg->debuglog_level >= 4) { diff --git a/apache2/msc_crypt.c b/apache2/msc_crypt.c index 3fe18c78b4..3287eeff2e 100644 --- a/apache2/msc_crypt.c +++ b/apache2/msc_crypt.c @@ -32,14 +32,12 @@ * \retval NULL on fail */ char *normalize_path(modsec_rec *msr, char *input) { + assert(msr != NULL); + assert(input != NULL); xmlURI *uri = NULL; char *parsed_content = NULL; char *content = NULL; - if(msr == NULL) return NULL; - - if(input == NULL) return NULL; - uri = xmlParseURI(input); if(uri != NULL && uri->path) { @@ -195,6 +193,8 @@ char *mschmac(modsec_rec *msr, const char *key, int key_len, char *hmac(modsec_rec *msr, const char *key, int key_len, unsigned char *msg, int msglen) { #endif + assert(msr != NULL); + assert(msg != NULL); apr_sha1_ctx_t ctx; unsigned char digest[APR_SHA1_DIGESTSIZE]; unsigned char hmac_ipad[HMAC_PAD_SIZE], hmac_opad[HMAC_PAD_SIZE]; @@ -346,6 +346,8 @@ int init_response_body_html_parser(modsec_rec *msr) { * \retval -1 on fail */ int do_hash_method(modsec_rec *msr, char *link, int type) { + assert(msr != NULL); + assert(link != NULL); hash_method **em = NULL; int i = 0; char *error_msg = NULL; @@ -1051,6 +1053,7 @@ int hash_response_body_links(modsec_rec *msr) { * \retval -1 On fail */ int inject_hashed_response_body(modsec_rec *msr, int elts) { + assert(msr != NULL); xmlOutputBufferPtr output_buf = NULL; xmlCharEncodingHandlerPtr handler = NULL; char *p = NULL; @@ -1290,13 +1293,13 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { * \retval NULL on fail */ char *do_hash_link(modsec_rec *msr, char *link, int type) { + assert(msr != NULL); + assert(link != NULL); char *mac_link = NULL; char *path_chunk = NULL; char *hash_value = NULL; char *qm = NULL; - if(msr == NULL) return NULL; - if(strlen(link) > 7 && strncmp("http:",(char*)link,5)==0){ path_chunk = strchr(link+7,'/'); if(path_chunk != NULL) { diff --git a/apache2/msc_geo.c b/apache2/msc_geo.c index a849b4f9e2..e77e4f5056 100644 --- a/apache2/msc_geo.c +++ b/apache2/msc_geo.c @@ -263,6 +263,10 @@ int geo_init(directory_config *dcfg, const char *dbfn, char **error_msg) */ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **error_msg) { + assert(msr != NULL); + assert(georec != NULL); + assert(target != NULL); + assert(error_msg != NULL); apr_sockaddr_t *addr; long ipnum = 0; char *targetip = NULL; diff --git a/apache2/msc_json.c b/apache2/msc_json.c index 17f938b64e..4cbeebf59c 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -20,6 +20,7 @@ const char *base_offset=NULL; int json_add_argument(modsec_rec *msr, const char *value, unsigned length) { + assert(msr != NULL); msc_arg *arg = (msc_arg *) NULL; /** @@ -86,6 +87,7 @@ int json_add_argument(modsec_rec *msr, const char *value, unsigned length) static int yajl_map_key(void *ctx, const unsigned char *key, size_t length) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); unsigned char *safe_key = (unsigned char *) NULL; /** @@ -117,6 +119,7 @@ static int yajl_map_key(void *ctx, const unsigned char *key, size_t length) static int yajl_null(void *ctx) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); return json_add_argument(msr, "", 0); } @@ -127,6 +130,7 @@ static int yajl_null(void *ctx) static int yajl_boolean(void *ctx, int value) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); if (value) { return json_add_argument(msr, "true", strlen("true")); @@ -142,6 +146,7 @@ static int yajl_boolean(void *ctx, int value) static int yajl_string(void *ctx, const unsigned char *value, size_t length) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); return json_add_argument(msr, value, length); } @@ -154,12 +159,14 @@ static int yajl_string(void *ctx, const unsigned char *value, size_t length) static int yajl_number(void *ctx, const char *value, size_t length) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); return json_add_argument(msr, value, length); } static int yajl_start_array(void *ctx) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); if (!msr->json->current_key && !msr->json->prefix) { msr->json->prefix = apr_pstrdup(msr->mp, "array"); @@ -189,6 +196,7 @@ static int yajl_start_array(void *ctx) { static int yajl_end_array(void *ctx) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); unsigned char *separator = (unsigned char *) NULL; /** @@ -225,6 +233,7 @@ static int yajl_end_array(void *ctx) { static int yajl_start_map(void *ctx) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); /** * If we do not have a current_key, this is a top-level hash, so we do not @@ -263,6 +272,7 @@ static int yajl_start_map(void *ctx) static int yajl_end_map(void *ctx) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); unsigned char *separator = (unsigned char *) NULL; /** @@ -298,6 +308,8 @@ static int yajl_end_map(void *ctx) * Initialise JSON parser. */ int json_init(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); /** * yajl configuration and callbacks */ @@ -315,7 +327,6 @@ int json_init(modsec_rec *msr, char **error_msg) { yajl_end_array }; - if (error_msg == NULL) return -1; *error_msg = NULL; msr_log(msr, 4, "JSON parser initialization"); @@ -352,7 +363,8 @@ int json_init(modsec_rec *msr, char **error_msg) { * Feed one chunk of data to the JSON parser. */ int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char **error_msg) { - if (error_msg == NULL) return -1; + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; base_offset=buf; @@ -376,9 +388,10 @@ int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char * Finalise JSON parsing. */ int json_complete(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); char *json_data = (char *) NULL; - if (error_msg == NULL) return -1; *error_msg = NULL; /* Wrap up the parsing process */ diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 7f286500f9..92160adc60 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -35,6 +35,7 @@ * the size counters, update the hash context. */ static int sec_auditlog_write(modsec_rec *msr, const char *data, unsigned int len) { + assert(msr != NULL); apr_size_t nbytes_written, nbytes = len; apr_status_t rc; @@ -86,6 +87,8 @@ static int sec_auditlog_write(modsec_rec *msr, const char *data, unsigned int le * some of the fields to make the log line shorter than _limit bytes. */ char *construct_log_vcombinedus_limited(modsec_rec *msr, int _limit, int *was_limited) { + assert(msr != NULL); + assert(was_limited != NULL); char *hostname; char *local_user, *remote_user; char *referer, *user_agent, *uniqueid; @@ -405,6 +408,7 @@ static void sec_auditlog_write_producer_header(modsec_rec *msr) { * Ouput the Producer header into a JSON generator */ static void sec_auditlog_write_producer_header_json(modsec_rec *msr, yajl_gen g) { + assert(msr != NULL); char **signatures = NULL; int i; @@ -520,6 +524,7 @@ static msre_rule *return_chained_rule(const msre_rule *current, modsec_rec *msr) * \retval 1 On Success */ static int chained_is_matched(modsec_rec *msr, const msre_rule *next_rule) { + assert(msr != NULL); int i = 0; const msre_rule *rule = NULL; @@ -538,6 +543,7 @@ static int chained_is_matched(modsec_rec *msr, const msre_rule *next_rule) { * Write detailed information about performance metrics into a JSON generator */ static void format_performance_variables_json(modsec_rec *msr, yajl_gen g) { + assert(msr != NULL); yajl_string(g, "stopwatch"); yajl_gen_map_open(g); @@ -558,6 +564,8 @@ static void format_performance_variables_json(modsec_rec *msr, yajl_gen g) { * Write detailed information about a rule and its actionset into a JSON generator */ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) { + assert(msr != NULL); + assert(rule != NULL); const apr_array_header_t *tarr; const apr_table_entry_t *telts; int been_opened = 0; @@ -748,10 +756,13 @@ void sec_audit_logger_json(modsec_rec *msr) { /* Lock the mutex, but only if we are using serial format. */ if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { - rc = apr_global_mutex_lock(msr->modsecurity->auditlog_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s", - get_apr_error(msr->mp, rc)); + if (!msr->modsecurity->auditlog_lock) msr_log(msr, 1, "Audit log: Global mutex was not created"); + else { + rc = apr_global_mutex_lock(msr->modsecurity->auditlog_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s", + get_apr_error(msr->mp, rc)); + } } } diff --git a/apache2/msc_lua.c b/apache2/msc_lua.c index 2f05df651d..e1715c03b5 100644 --- a/apache2/msc_lua.c +++ b/apache2/msc_lua.c @@ -154,6 +154,8 @@ static int l_log(lua_State *L) { * */ static apr_array_header_t *resolve_tfns(lua_State *L, int idx, modsec_rec *msr, apr_pool_t *mp) { + assert(msr != NULL); + assert(mp != NULL); apr_array_header_t *tfn_arr = NULL; msre_tfn_metadata *tfn = NULL; char *name = NULL; @@ -406,11 +408,13 @@ static const struct luaL_Reg mylib[] = { * */ int lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rule, char **error_msg) { + assert(script != NULL); + assert(msr != NULL); + assert(error_msg != NULL); apr_time_t time_before; lua_State *L = NULL; int rc = 0; - if (error_msg == NULL) return -1; *error_msg = NULL; if (msr->txcfg->debuglog_level >= 8) { diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index 9309d4df29..7d56dd64e0 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -21,11 +21,9 @@ #include "msc_parsers.h" void validate_quotes(modsec_rec *msr, char *data, char quote) { + assert(msr != NULL); int i, len; - if(msr == NULL) - return; - if(msr->mpd == NULL) return; @@ -84,6 +82,8 @@ static char *multipart_construct_filename(modsec_rec *msr) { * */ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value) { + assert(msr != NULL); + assert(c_d_value != NULL); char *p = NULL, *t = NULL; /* accept only what we understand */ @@ -255,9 +255,10 @@ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value) * */ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); int i, len, rc; - if (error_msg == NULL) return -1; *error_msg = NULL; /* Check for nul bytes. */ @@ -454,11 +455,12 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) { * */ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); char *p = msr->mpd->buf + (MULTIPART_BUF_SIZE - msr->mpd->bufleft); char localreserve[2] = { '\0', '\0' }; /* initialized to quiet warning */ int bytes_reserved = 0; - if (error_msg == NULL) return -1; *error_msg = NULL; msr->mpd->mpp_substate_part_data_read = 1; @@ -628,6 +630,8 @@ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) { * */ static char *multipart_combine_value_parts(modsec_rec *msr, apr_array_header_t *value_parts) { + assert(msr != NULL); + assert(value_parts != NULL); value_part_t **parts = NULL; char *rval = apr_palloc(msr->mp, msr->mpd->mpp->length + 1); unsigned long int offset; @@ -652,6 +656,7 @@ static char *multipart_combine_value_parts(modsec_rec *msr, apr_array_header_t * * */ static int multipart_process_boundary(modsec_rec *msr, int last_part, char **error_log) { + assert(msr != NULL); /* if there was a part being built finish it */ if (msr->mpd->mpp != NULL) { /* close the temp file */ @@ -788,7 +793,8 @@ static int multipart_count_boundary_params(apr_pool_t *mp, const char *header_va * */ int multipart_init(modsec_rec *msr, char **error_msg) { - if (error_msg == NULL) return -1; + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; msr->mpd = (multipart_data *)apr_pcalloc(msr->mp, sizeof(multipart_data)); @@ -952,6 +958,8 @@ int multipart_init(modsec_rec *msr, char **error_msg) { * is clear that there is no more data to be processed. */ int multipart_complete(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); if (msr->mpd == NULL) return 1; if (msr->txcfg->debuglog_level >= 4) { @@ -1055,10 +1063,12 @@ int multipart_complete(modsec_rec *msr, char **error_msg) { int multipart_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char **error_msg) { + assert(msr != NULL); + assert(buf != NULL); + assert(error_msg != NULL); char *inptr = (char *)buf; unsigned int inleft = size; - if (error_msg == NULL) return -1; *error_msg = NULL; if (size == 0) return 1; @@ -1433,6 +1443,7 @@ apr_status_t multipart_cleanup(modsec_rec *msr) { * */ int multipart_get_arguments(modsec_rec *msr, char *origin, apr_table_t *arguments) { + assert(msr != NULL); multipart_part **parts; int i; diff --git a/apache2/msc_parsers.c b/apache2/msc_parsers.c index 8bbf972689..894c84b9de 100644 --- a/apache2/msc_parsers.c +++ b/apache2/msc_parsers.c @@ -21,6 +21,9 @@ int parse_cookies_v0(modsec_rec *msr, char *_cookie_header, apr_table_t *cookies, const char *delim) { + assert(msr != NULL); + assert(cookies != NULL); + assert(delim != NULL); char *attr_name = NULL, *attr_value = NULL; char *cookie_header; char *saveptr = NULL; @@ -95,6 +98,8 @@ int parse_cookies_v0(modsec_rec *msr, char *_cookie_header, int parse_cookies_v1(modsec_rec *msr, char *_cookie_header, apr_table_t *cookies) { + assert(msr != NULL); + assert(cookies != NULL); char *attr_name = NULL, *attr_value = NULL, *p = NULL; char *prev_attr_name = NULL; char *cookie_header = NULL; @@ -239,6 +244,7 @@ int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength, int argument_separator, const char *origin, apr_table_t *arguments, int *invalid_count) { + assert(msr != NULL); msc_arg *arg; apr_size_t i, j; char *value = NULL; @@ -340,6 +346,9 @@ int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength, */ void add_argument(modsec_rec *msr, apr_table_t *arguments, msc_arg *arg) { + assert(msr != NULL); + assert(arguments != NULL); + assert(arg != NULL); if (msr->txcfg->debuglog_level >= 5) { msr_log(msr, 5, "Adding request argument (%s): name \"%s\", value \"%s\"", arg->origin, log_escape_ex(msr->mp, arg->name, arg->name_len), diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index e84c33a391..ba8bdfd416 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -41,6 +41,8 @@ void msre_engine_reqbody_processor_register(msre_engine *engine, * Prepare to accept the request body (part 2). */ static apr_status_t modsecurity_request_body_start_init(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; if(msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) { @@ -80,6 +82,8 @@ static apr_status_t modsecurity_request_body_start_init(modsec_rec *msr, char ** * Prepare to accept the request body (part 1). */ apr_status_t modsecurity_request_body_start(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; msr->msc_reqbody_length = 0; msr->stream_input_length = 0; @@ -161,6 +165,8 @@ apr_status_t modsecurity_request_body_start(modsec_rec *msr, char **error_msg) { static apr_status_t modsecurity_request_body_store_disk(modsec_rec *msr, const char *data, apr_size_t length, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); apr_size_t i; *error_msg = NULL; @@ -181,6 +187,8 @@ static apr_status_t modsecurity_request_body_store_disk(modsec_rec *msr, static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr, const char *data, apr_size_t length, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; /* Would storing this chunk mean going over the limit? */ @@ -309,6 +317,8 @@ static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr, apr_status_t modsecurity_request_body_store(modsec_rec *msr, const char *data, apr_size_t length, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; /* If we have a processor for this request body send @@ -428,6 +438,8 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr, } apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buffer, int buflen, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); #ifndef MSC_LARGE_STREAM_INPUT char *stream_input_body = NULL; char *data = NULL; @@ -541,6 +553,8 @@ apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buf * Replace a bunch of chunks holding a request body with a single large chunk. */ static apr_status_t modsecurity_request_body_end_raw(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); msc_data_chunk **chunks, *one_chunk; char *d; int i, sofar; @@ -614,6 +628,8 @@ static apr_status_t modsecurity_request_body_end_raw(modsec_rec *msr, char **err * */ static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); int invalid_count = 0; *error_msg = NULL; @@ -643,6 +659,8 @@ static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr, cha * Stops receiving the request body. */ apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; /* Close open file descriptors, if any. */ @@ -753,6 +771,8 @@ apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) { * Prepares to forward the request body. */ apr_status_t modsecurity_request_body_retrieve_start(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) { @@ -821,6 +841,8 @@ apr_status_t modsecurity_request_body_retrieve_end(modsec_rec *msr) { apr_status_t modsecurity_request_body_retrieve(modsec_rec *msr, msc_data_chunk **chunk, long int nbytes, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); msc_data_chunk **chunks; *error_msg = NULL; @@ -922,6 +944,8 @@ apr_status_t modsecurity_request_body_retrieve(modsec_rec *msr, * */ apr_status_t modsecurity_request_body_clear(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; /* Release memory we used to store request body data. */ diff --git a/apache2/msc_tree.c b/apache2/msc_tree.c index 232a363e2c..f8610b39e3 100644 --- a/apache2/msc_tree.c +++ b/apache2/msc_tree.c @@ -535,6 +535,8 @@ int TreeCheckData(TreePrefix *prefix, CPTData *prefix_data, unsigned int netmask } int TreePrefixNetmask(modsec_rec *msr, TreePrefix *prefix, unsigned int netmask, int flag) { + // msr can be NULL; + assert(!msr || msr->txcfg != NULL); CPTData *prefix_data = NULL; int ret = 0; @@ -574,6 +576,8 @@ int TreePrefixNetmask(modsec_rec *msr, TreePrefix *prefix, unsigned int netmask, } TreeNode *CPTRetriveNode(modsec_rec *msr, unsigned char *buffer, unsigned int ip_bitmask, TreeNode *node) { + // msr can be NULL; + assert(!msr || msr->txcfg != NULL); unsigned int x, y; if(node == NULL) { @@ -620,6 +624,8 @@ TreeNode *CPTRetriveParentNode(TreeNode *node) { } TreeNode *CPTFindElementIPNetblock(modsec_rec *msr, unsigned char *ipdata, unsigned char ip_bitmask, TreeNode *node) { + // msr can be NULL; + assert(!msr || msr->txcfg != NULL); TreeNode *netmask_node = NULL; int mask = 0, bytes = 0; int i = 0, j = 0; @@ -656,15 +662,22 @@ TreeNode *CPTFindElementIPNetblock(modsec_rec *msr, unsigned char *ipdata, unsig } node = CPTRetriveNode(msr, ipdata, ip_bitmask, node); + if (!node) { + if (msr && msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "CPTFindElementIPNetblock: No tree node found."); + } + return NULL; + } + - if (node && node->bit != ip_bitmask) { + if (node->bit != ip_bitmask) { if (msr && msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "CPTFindElementIPNetblock: Found a tree node but netmask is different."); } return NULL; } - if (node && node->prefix == NULL) { + if (node->prefix == NULL) { if (msr && msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "CPTFindElementIPNetblock: Found a tree node but prefix is NULL."); } @@ -700,6 +713,8 @@ TreeNode *CPTFindElementIPNetblock(modsec_rec *msr, unsigned char *ipdata, unsig } TreeNode *CPTFindElement(modsec_rec *msr, unsigned char *ipdata, unsigned int ip_bitmask, CPTTree *tree) { + // msr can be NULL; + assert(!msr || msr->txcfg != NULL); TreeNode *node = NULL; int mask = 0, bytes = 0; unsigned char temp_data[NETMASK_256-1]; @@ -781,6 +796,8 @@ TreeNode *CPTFindElement(modsec_rec *msr, unsigned char *ipdata, unsigned int ip } TreeNode *CPTIpMatch(modsec_rec *msr, unsigned char *ipdata, CPTTree *tree, int type) { + // msr can be NULL; + assert(!msr || msr->txcfg != NULL); if(tree == NULL) { if (msr && msr->txcfg->debuglog_level >= 9) { @@ -839,6 +856,7 @@ TreeNode *TreeAddIP(const char *buffer, CPTTree *tree, int type) { *(ip_strv4 + (sizeof(ip_strv4) - 1)) = '\0'; ptr = strdup(ip_strv4); + if (ptr == NULL) return NULL; // No way to return a clean error message netmask_v4 = is_netmask_v4(ptr); if (netmask_v4 > NETMASK_32) { @@ -875,6 +893,7 @@ TreeNode *TreeAddIP(const char *buffer, CPTTree *tree, int type) { *(ip_strv6 + sizeof(ip_strv6) - 1) = '\0'; ptr = strdup(ip_strv6); + if (ptr == NULL) return NULL; // No way to return a clean error message netmask_v6 = is_netmask_v6(ptr); if (netmask_v6 > NETMASK_128) { @@ -911,4 +930,3 @@ TreeNode *TreeAddIP(const char *buffer, CPTTree *tree, int type) { return NULL; } - diff --git a/apache2/msc_util.c b/apache2/msc_util.c index cf9a393517..fd318a087a 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -667,6 +667,7 @@ int convert_to_int(const char c) * \retval 0 On Sucess|Fail */ int set_match_to_tx(modsec_rec *msr, int capture, const char *match, int tx_n) { + assert(msr != NULL); if (capture) { msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); @@ -2378,6 +2379,7 @@ apr_fileperms_t mode2fileperms(int mode) { * Generate a single variable. */ char *construct_single_var(modsec_rec *msr, char *name) { + assert(msr != NULL); char *varname = NULL; char *param = NULL; msre_var *var = NULL; @@ -2386,6 +2388,7 @@ char *construct_single_var(modsec_rec *msr, char *name) { /* Extract variable name and its parameter from the script. */ varname = apr_pstrdup(msr->mp, name); + if (varname == NULL) return NULL; param = strchr(varname, '.'); if (param != NULL) { *param = '\0'; @@ -2703,6 +2706,10 @@ int ip_tree_from_uri(TreeRoot **rtree, char *uri, int tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree, const char *value, modsec_rec *msr, char **error_msg) { + assert(mp != NULL); + assert(value != NULL); + // msr can be NULL; + assert(error_msg != NULL); struct in_addr in; #if APR_HAVE_IPV6 struct in6_addr in6; @@ -2843,3 +2850,14 @@ char* strtok_r( } #endif +// we cannot log an error message as this happens much too often +char* get_username(apr_pool_t* mp) { + char* username; + apr_uid_t uid; + apr_gid_t gid; + int rc = apr_uid_current(&uid, &gid, mp); + if (rc != APR_SUCCESS) return "apache"; + rc = apr_uid_name_get(&username, uid, mp); + if (rc != APR_SUCCESS) return "apache"; + return username; +} diff --git a/apache2/msc_util.h b/apache2/msc_util.h index f7e1280f21..afff3e7f64 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -15,6 +15,7 @@ #ifndef _UTIL_H_ #define _UTIL_H_ +#include #include #include @@ -164,6 +165,9 @@ int ip_tree_from_uri(TreeRoot **rtree, char *uri, apr_pool_t *mp, char **error_msg); #endif +char DSOLOCAL *get_username(apr_pool_t* mp); +const char* id_log(msre_rule* rule); + int read_line(char *buff, int size, FILE *fp); size_t msc_curl_write_memory_cb(void *contents, size_t size, diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 5b5bbb1a25..808f7e9097 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -24,9 +24,10 @@ xml_unload_external_entity(const char *URI, xmlCharEncoding enc) { * Initialise XML parser. */ int xml_init(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); xmlParserInputBufferCreateFilenameFunc entity; - if (error_msg == NULL) return -1; *error_msg = NULL; msr->xml = apr_pcalloc(msr->mp, sizeof(xml_data)); @@ -59,7 +60,8 @@ static void xml_receive_sax_error(void *data, const char *msg, ...) { * Feed one chunk of data to the XML parser. */ int xml_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char **error_msg) { - if (error_msg == NULL) return -1; + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; /* We want to initialise our parsing context here, to @@ -107,7 +109,8 @@ int xml_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char * Finalise XML parsing. */ int xml_complete(modsec_rec *msr, char **error_msg) { - if (error_msg == NULL) return -1; + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; /* Only if we have a context, meaning we've done some work. */ diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index 79f99dcc44..6634151ca4 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -1,841 +1,816 @@ -/* -* ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) -* -* You may not use this file except in compliance with -* the License.  You may obtain a copy of the License at -* -*     http://www.apache.org/licenses/LICENSE-2.0 -* -* If any of the files related to licensing are missing or if you have any -* other questions related to licensing please contact Trustwave Holdings, Inc. -* directly using the email address security@modsecurity.org. -*/ - -#include "persist_dbm.h" -#include "apr_sdbm.h" - -/** - * - */ -static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob, unsigned int blob_size, - int log_vars) -{ - apr_table_t *col = NULL; - unsigned int blob_offset; - - col = apr_table_make(msr->mp, 32); - if (col == NULL) return NULL; - - /* ENH verify the first 3 bytes (header) */ - - blob_offset = 3; - while (blob_offset + 1 < blob_size) { - msc_string *var = apr_pcalloc(msr->mp, sizeof(msc_string)); - - var->name_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; - if (var->name_len == 0) { - /* Is the length a name length, or just the end of the blob? */ - if (blob_offset < blob_size - 2) { - /* This should never happen as the name length - * includes the terminating NUL and should be 1 for "" - */ - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); - } - msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length = 0 at blob offset %u-%u.", blob_offset, blob_offset + 1); - } - break; - } - else if (var->name_len > 65536) { - /* This should never happen as the length is restricted on store - * to 65536. - */ - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); - } - msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length > 65536 (0x%04x) at blob offset %u-%u.", var->name_len, blob_offset, blob_offset + 1); - break; - } - - blob_offset += 2; - if (var->name_len < 1 || blob_offset + var->name_len > blob_size) return NULL; - var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1); - blob_offset += var->name_len; - var->name_len--; - - var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; - blob_offset += 2; - - if (var->value_len < 1 || blob_offset + var->value_len > blob_size) return NULL; - var->value = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->value_len - 1); - blob_offset += var->value_len; - var->value_len--; - - if (log_vars && (msr->txcfg->debuglog_level >= 9)) { - msr_log(msr, 9, "collection_unpack: Read variable: name \"%s\", value \"%s\".", - log_escape_ex(msr->mp, var->name, var->name_len), - log_escape_ex(msr->mp, var->value, var->value_len)); - } - - apr_table_addn(col, var->name, (void *)var); - } - - return col; -} - -/** - * - */ -static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name, - const char *col_key, int col_key_len) -{ - char *dbm_filename = NULL; - apr_status_t rc; - apr_sdbm_datum_t key; - apr_sdbm_datum_t *value = NULL; - apr_sdbm_t *dbm = NULL; - apr_table_t *col = NULL; - const apr_array_header_t *arr; - apr_table_entry_t *te; - int expired = 0; - int i; - - /** - * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations - */ - char *userinfo; - apr_uid_t uid; - apr_gid_t gid; - apr_uid_current(&uid, &gid, msr->mp); - rc = apr_uid_name_get(&userinfo, uid, msr->mp); - if (rc != APR_SUCCESS) { - userinfo = apr_psprintf(msr->mp, "%u", uid); - } - - if (msr->txcfg->data_dir == NULL) { - msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use " - "SecDataDir to define data directory first.", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, col_key, col_key_len)); - goto cleanup; - } - - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), - log_escape(msr->mp, dbm_filename)); - } - - key.dptr = (char *)col_key; - key.dsize = col_key_len + 1; - - if (existing_dbm == NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto cleanup; - } -#endif - rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { - dbm = NULL; -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - goto cleanup; - } - } - else { - dbm = existing_dbm; - } - - value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t)); - rc = apr_sdbm_fetch(dbm, value, key); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to read from DBM file \"%s\": %s", log_escape(msr->mp, - dbm_filename), get_apr_error(msr->mp, rc)); - goto cleanup; - } - - if (value->dptr == NULL) { /* Key not found in DBM file. */ - goto cleanup; - } - - /* ENH Need expiration (and perhaps other metadata) accessible in blob - * form to determine if converting to a table is needed. This will - * save some cycles. - */ - - /* Transform raw data into a table. */ - col = collection_unpack(msr, (const unsigned char *)value->dptr, value->dsize, 1); - if (col == NULL) { - goto cleanup; - } - - /* Close after "value" used from fetch or memory may be overwritten. */ - if (existing_dbm == NULL) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - dbm = NULL; - } - - /* Remove expired variables. */ - do { - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - if (strncmp(te[i].key, "__expire_", 9) == 0) { - msc_string *var = (msc_string *)te[i].val; - int expiry_time = atoi(var->value); - - if (expiry_time <= apr_time_sec(msr->request_time)) { - char *key_to_expire = te[i].key; - - /* Done early if the col expired */ - if (strcmp(key_to_expire, "__expire_KEY") == 0) { - expired = 1; - } - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire + 9); - msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire); - } - - apr_table_unset(col, key_to_expire + 9); - apr_table_unset(col, key_to_expire); - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Removed expired variable \"%s\".", key_to_expire + 9); - } - - break; - } - } - } - } while(!expired && (i != arr->nelts)); - - /* Delete the collection if the variable "KEY" does not exist. - * - * ENH It would probably be more efficient to hold the DBM - * open until determined if it needs deleted than to open a second - * time. - */ - if (apr_table_get(col, "KEY") == NULL) { - if (existing_dbm == NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto cleanup; - } -#endif - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to access DBM file \"%s\": %s", - log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); - dbm = NULL; -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - goto cleanup; - } - } - else { - dbm = existing_dbm; - } - - rc = apr_sdbm_delete(dbm, key); - if (rc != APR_SUCCESS) { -#ifdef LOG_NO_COLL_DELET_PB - if (msr->txcfg->debuglog_level >= 9) -#endif - msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", " - "key \"%s\"): %s", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc)); - msr->msc_sdbm_delete_error = 1; - goto cleanup; - } - - - if (existing_dbm == NULL) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - dbm = NULL; - } - - if (expired && (msr->txcfg->debuglog_level >= 9)) { - msr_log(msr, 9, "collection_retrieve_ex: Collection expired (name \"%s\", key \"%s\").", col_name, - log_escape_ex(msr->mp, col_key, col_key_len)); - } - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Deleted collection (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - } - goto cleanup; - } - - /* Update UPDATE_RATE */ - { - msc_string *var; - int create_time, counter; - - var = (msc_string *)apr_table_get(col, "CREATE_TIME"); - if (var == NULL) { - /* Error. */ - } else { - create_time = atoi(var->value); - var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); - if (var == NULL) { - /* Error. */ - } else { - apr_time_t td; - counter = atoi(var->value); - - /* UPDATE_RATE is removed on store, so add it back here */ - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "UPDATE_RATE"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - - /* NOTE: No rate if there has been no time elapsed */ - td = (apr_time_sec(apr_time_now()) - create_time); - if (td == 0) { - var->value = apr_psprintf(msr->mp, "%d", 0); - } - else { - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, - (apr_time_t)((60 * counter)/td)); - } - var->value_len = strlen(var->value); - } - } - } - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Retrieved collection (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - } - - if ((existing_dbm == NULL) && dbm) { - /* Should not ever get here */ - msr_log(msr, 1, "collection_retrieve_ex: Internal Error: Collection remained open (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - } - - return col; - -cleanup: - - if ((existing_dbm == NULL) && dbm) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - } - - return NULL; -} - -/** - * - */ -apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name, - const char *col_key, int col_key_len) -{ - apr_time_t time_before = apr_time_now(); - apr_table_t *rtable = NULL; - - rtable = collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len); - - msr->time_storage_read += apr_time_now() - time_before; - - return rtable; -} - -/** - * - */ -int collection_store(modsec_rec *msr, apr_table_t *col) { - char *dbm_filename = NULL; - msc_string *var_name = NULL, *var_key = NULL; - unsigned char *blob = NULL; - unsigned int blob_size, blob_offset; - apr_status_t rc; - apr_sdbm_datum_t key; - apr_sdbm_datum_t value; - apr_sdbm_t *dbm = NULL; - const apr_array_header_t *arr; - apr_table_entry_t *te; - int i; - const apr_table_t *stored_col = NULL; - const apr_table_t *orig_col = NULL; - - /** - * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations - */ - char *userinfo; - apr_uid_t uid; - apr_gid_t gid; - apr_uid_current(&uid, &gid, msr->mp); - rc = apr_uid_name_get(&userinfo, uid, msr->mp); - if (rc != APR_SUCCESS) { - userinfo = apr_psprintf(msr->mp, "%u", uid); - } - - var_name = (msc_string *)apr_table_get(col, "__name"); - if (var_name == NULL) { - goto error; - } - - var_key = (msc_string *)apr_table_get(col, "__key"); - if (var_key == NULL) { - goto error; - } - - if (msr->txcfg->data_dir == NULL) { - msr_log(msr, 1, "collection_store: Unable to store collection (name \"%s\", key \"%s\"). Use " - "SecDataDir to define data directory first.", log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var_key->value, var_key->value_len)); - goto error; - } - - // ENH: lowercase the var name in the filename - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", var_name->value, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value), - log_escape(msr->mp, dbm_filename)); - } - -#ifdef GLOBAL_COLLECTION_LOCK - /* Need to lock to pull in the stored data again and apply deltas. */ - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* Delete IS_NEW on store. */ - apr_table_unset(col, "IS_NEW"); - - /* Delete UPDATE_RATE on store to save space as it is calculated */ - apr_table_unset(col, "UPDATE_RATE"); - - /* Update the timeout value. */ - { - msc_string *var = (msc_string *)apr_table_get(col, "TIMEOUT"); - if (var != NULL) { - int timeout = atoi(var->value); - var = (msc_string *)apr_table_get(col, "__expire_KEY"); - if (var != NULL) { - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()) + timeout)); - var->value_len = strlen(var->value); - } - } - } - - /* LAST_UPDATE_TIME */ - { - msc_string *var = (msc_string *)apr_table_get(col, "LAST_UPDATE_TIME"); - if (var == NULL) { - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "LAST_UPDATE_TIME"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - } - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()))); - var->value_len = strlen(var->value); - } - - /* UPDATE_COUNTER */ - { - msc_string *var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); - int counter = 0; - if (var == NULL) { - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "UPDATE_COUNTER"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - } else { - counter = atoi(var->value); - } - var->value = apr_psprintf(msr->mp, "%d", counter + 1); - var->value_len = strlen(var->value); - } - - /* ENH Make the expiration timestamp accessible in blob form so that - * it is easier/faster to determine expiration without having to - * convert back to table form - */ - - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - msr_log(msr, 1, "collection_store: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - dbm = NULL; - goto error; - } - -#ifndef GLOBAL_COLLECTION_LOCK - /* Need to lock to pull in the stored data again and apply deltas. */ - rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* If there is an original value, then create a delta and - * apply the delta to the current value */ - orig_col = (const apr_table_t *)apr_table_get(msr->collections_original, var_name->value); - if (orig_col != NULL) { - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Re-retrieving collection prior to store: %s", - apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value)); - } - - stored_col = (const apr_table_t *)collection_retrieve_ex(dbm, msr, var_name->value, var_key->value, var_key->value_len); - } - - /* Merge deltas and calculate the size first. */ - blob_size = 3 + 2; - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - msc_string *var = (msc_string *)te[i].val; - int len; - - /* If there is an original value, then apply the delta - * to the latest stored value */ - if (stored_col != NULL) { - const msc_string *orig_var = (const msc_string *)apr_table_get(orig_col, var->name); - if (orig_var != NULL) { - const msc_string *stored_var = (const msc_string *)apr_table_get(stored_col, var->name); - if (stored_var != NULL) { - int origval = atoi(orig_var->value); - int ourval = atoi(var->value); - int storedval = atoi(stored_var->value); - int delta = ourval - origval; - int newval = storedval + delta; - - if (newval < 0) newval = 0; /* Counters never go below zero. */ - - var->value = apr_psprintf(msr->mp, "%d", newval); - var->value_len = strlen(var->value); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Delta applied for %s.%s %d->%d (%d): %d + (%d) = %d [%s,%d]", - log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var->name, var->name_len), - origval, ourval, delta, storedval, delta, newval, var->value, var->value_len); - } - } - } - } - - // Allocate blob_size for keys - len = var->name_len + 1; - if (len >= 65536) len = 65536; - blob_size += len + 2; - - // Allocate blob_size for values - len = var->value_len + 1; - if (len >= 65536) len = 65536; - blob_size += len + 2; - } - - /* Now generate the binary object. */ - blob = apr_pcalloc(msr->mp, blob_size); - if (blob == NULL) { - if (dbm != NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - } - - return -1; - } - - blob[0] = 0x49; - blob[1] = 0x52; - blob[2] = 0x01; - - blob_offset = 3; - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - msc_string *var = (msc_string *)te[i].val; - int len; - - len = var->name_len + 1; - if (len >= 65536) len = 65536; - - blob[blob_offset + 0] = (len & 0xff00) >> 8; - blob[blob_offset + 1] = len & 0x00ff; - memcpy(blob + blob_offset + 2, var->name, len - 1); - blob[blob_offset + 2 + len - 1] = '\0'; - blob_offset += 2 + len; - - len = var->value_len + 1; - if (len >= 65536) len = 65536; - - blob[blob_offset + 0] = (len & 0xff00) >> 8; - blob[blob_offset + 1] = len & 0x00ff; - memcpy(blob + blob_offset + 2, var->value, len - 1); - blob[blob_offset + 2 + len - 1] = '\0'; - blob_offset += 2 + len; - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Wrote variable: name \"%s\", value \"%s\".", - log_escape_ex(msr->mp, var->name, var->name_len), - log_escape_ex(msr->mp, var->value, var->value_len)); - } - } - - blob[blob_offset] = 0; - blob[blob_offset + 1] = 0; - - /* And, finally, store it. */ - key.dptr = var_key->value; - key.dsize = var_key->value_len + 1; - - value.dptr = (char *)blob; - value.dsize = blob_size; - - rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename, - get_apr_error(msr->mp, rc)); - if (dbm != NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - } - - return -1; - } - -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\").", - log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var_key->value, var_key->value_len)); - } - - return 0; - -error: - return -1; -} - -/** - * - */ -int collections_remove_stale(modsec_rec *msr, const char *col_name) { - char *dbm_filename = NULL; - apr_sdbm_datum_t key, value; - apr_sdbm_t *dbm = NULL; - apr_status_t rc; - apr_array_header_t *keys_arr; - char **keys; - apr_time_t now = apr_time_sec(msr->request_time); - int i; - - /** - * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations - */ - char *userinfo; - apr_uid_t uid; - apr_gid_t gid; - apr_uid_current(&uid, &gid, msr->mp); - rc = apr_uid_name_get(&userinfo, uid, msr->mp); - if (rc != APR_SUCCESS) { - userinfo = apr_psprintf(msr->mp, "%u", uid); - } - - if (msr->txcfg->data_dir == NULL) { - /* The user has been warned about this problem enough times already by now. - * msr_log(msr, 1, "Unable to access collection file (name \"%s\"). Use SecDataDir to " - * "define data directory first.", log_escape(msr->mp, col_name)); - */ - goto error; - } - - if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE")) - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", msr->txcfg->webappid, "_", col_name, NULL); - else - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), - log_escape(msr->mp, dbm_filename)); - } - -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - msr_log(msr, 1, "collections_remove_stale: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - dbm = NULL; - goto error; - } - - /* First get a list of all keys. */ - keys_arr = apr_array_make(msr->mp, 256, sizeof(char *)); - -#ifndef GLOBAL_COLLECTION_LOCK - rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* No one can write to the file while doing this so - * do it as fast as possible. - */ - rc = apr_sdbm_firstkey(dbm, &key); - while(rc == APR_SUCCESS) { - if (key.dsize) { - char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1); - *(char **)apr_array_push(keys_arr) = s; - } - rc = apr_sdbm_nextkey(dbm, &key); - } -#ifndef GLOBAL_COLLECTION_LOCK - apr_sdbm_unlock(dbm); -#endif - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Found %d record(s) in file \"%s\".", keys_arr->nelts, - log_escape(msr->mp, dbm_filename)); - } - - /* Now retrieve the entires one by one. */ - keys = (char **)keys_arr->elts; - for (i = 0; i < keys_arr->nelts; i++) { - key.dptr = keys[i]; - key.dsize = strlen(key.dptr) + 1; - - rc = apr_sdbm_fetch(dbm, &value, key); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed reading DBM file \"%s\": %s", - log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); - goto error; - } - - if (value.dptr != NULL) { - apr_table_t *col = NULL; - msc_string *var = NULL; - - col = collection_unpack(msr, (const unsigned char *)value.dptr, value.dsize, 0); - if (col == NULL) { - goto error; - } - - var = (msc_string *)apr_table_get(col, "__expire_KEY"); - if (var == NULL) { - msr_log(msr, 1, "collections_remove_stale: Collection cleanup discovered entry with no " - "__expire_KEY (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); - } else { - unsigned int expiry_time = atoi(var->value); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Record (name \"%s\", key \"%s\") set to expire in %" APR_TIME_T_FMT " seconds.", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), - expiry_time - now); - } - - if (expiry_time <= now) { - rc = apr_sdbm_delete(dbm, key); - if (rc != APR_SUCCESS) { -#ifdef LOG_NO_COLL_DELET_PB - if (msr->txcfg->debuglog_level >= 9) -#endif - msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", " - "key \"%s\"): %s", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc)); - msr->msc_sdbm_delete_error = 1; - goto error; - } - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collections_remove_stale: Removed stale collection (name \"%s\", " - "key \"%s\").", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); - } - } - } - } else { - /* Ignore entry not found - it may have been removed in the meantime. */ - } - } - - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - return 1; - -error: - - if (dbm) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - } - - return -1; -} +/* +* ModSecurity for Apache 2.x, http://www.modsecurity.org/ +* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* +* You may not use this file except in compliance with +* the License.  You may obtain a copy of the License at +* +*     http://www.apache.org/licenses/LICENSE-2.0 +* +* If any of the files related to licensing are missing or if you have any +* other questions related to licensing please contact Trustwave Holdings, Inc. +* directly using the email address security@modsecurity.org. +*/ + +#include "persist_dbm.h" +#include "apr_sdbm.h" + +/** + * + */ +static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob, unsigned int blob_size, + int log_vars) +{ + assert(msr != NULL); + assert(blob != NULL); + apr_table_t *col = NULL; + unsigned int blob_offset; + + col = apr_table_make(msr->mp, 32); + if (col == NULL) return NULL; + + /* ENH verify the first 3 bytes (header) */ + + blob_offset = 3; + while (blob_offset + 1 < blob_size) { + msc_string *var = apr_pcalloc(msr->mp, sizeof(msc_string)); + + var->name_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; + if (var->name_len == 0) { + /* Is the length a name length, or just the end of the blob? */ + if (blob_offset < blob_size - 2) { + /* This should never happen as the name length + * includes the terminating NUL and should be 1 for "" + */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); + } + msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length = 0 at blob offset %u-%u.", blob_offset, blob_offset + 1); + } + break; + } + else if (var->name_len > 65536) { + /* This should never happen as the length is restricted on store + * to 65536. + */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); + } + msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length > 65536 (0x%04x) at blob offset %u-%u.", var->name_len, blob_offset, blob_offset + 1); + break; + } + + blob_offset += 2; + if (blob_offset + var->name_len > blob_size) return NULL; + var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1); + blob_offset += var->name_len; + var->name_len--; + + var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; + blob_offset += 2; + + if (blob_offset + var->value_len > blob_size) return NULL; + var->value = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->value_len - 1); + blob_offset += var->value_len; + var->value_len--; + + if (log_vars && (msr->txcfg->debuglog_level >= 9)) { + msr_log(msr, 9, "collection_unpack: Read variable: name \"%s\", value \"%s\".", + log_escape_ex(msr->mp, var->name, var->name_len), + log_escape_ex(msr->mp, var->value, var->value_len)); + } + + apr_table_addn(col, var->name, (void *)var); + } + + return col; +} + +/** + * + */ +static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name, + const char *col_key, int col_key_len) +{ + assert(msr != NULL); + assert(col_name != NULL); + char *dbm_filename = NULL; + apr_status_t rc; + apr_sdbm_datum_t key; + apr_sdbm_datum_t *value = NULL; + apr_sdbm_t *dbm = NULL; + apr_table_t *col = NULL; + const apr_array_header_t *arr; + apr_table_entry_t *te; + int expired = 0; + int i; + char *userinfo = get_username(msr->mp); + + if (msr->txcfg->data_dir == NULL) { + msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use " + "SecDataDir to define data directory first.", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, col_key, col_key_len)); + goto cleanup; + } + + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), + log_escape(msr->mp, dbm_filename)); + } + + key.dptr = (char *)col_key; + key.dsize = col_key_len + 1; + + if (existing_dbm == NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto cleanup; + } +#endif + rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { + dbm = NULL; +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + goto cleanup; + } + } + else { + dbm = existing_dbm; + } + + value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t)); + rc = apr_sdbm_fetch(dbm, value, key); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to read from DBM file \"%s\": %s", log_escape(msr->mp, + dbm_filename), get_apr_error(msr->mp, rc)); + goto cleanup; + } + + if (value->dptr == NULL) { /* Key not found in DBM file. */ + goto cleanup; + } + + /* ENH Need expiration (and perhaps other metadata) accessible in blob + * form to determine if converting to a table is needed. This will + * save some cycles. + */ + + /* Transform raw data into a table. */ + col = collection_unpack(msr, (const unsigned char *)value->dptr, value->dsize, 1); + if (col == NULL) { + goto cleanup; + } + + /* Close after "value" used from fetch or memory may be overwritten. */ + if (existing_dbm == NULL) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + dbm = NULL; + } + + /* Remove expired variables. */ + do { + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + if (strncmp(te[i].key, "__expire_", 9) == 0) { + msc_string *var = (msc_string *)te[i].val; + int expiry_time = atoi(var->value); + + if (expiry_time <= apr_time_sec(msr->request_time)) { + char *key_to_expire = te[i].key; + + /* Done early if the col expired */ + if (strcmp(key_to_expire, "__expire_KEY") == 0) { + expired = 1; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire + 9); + msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire); + } + + apr_table_unset(col, key_to_expire + 9); + apr_table_unset(col, key_to_expire); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Removed expired variable \"%s\".", key_to_expire + 9); + } + + break; + } + } + } + } while(!expired && (i != arr->nelts)); + + /* Delete the collection if the variable "KEY" does not exist. + * + * ENH It would probably be more efficient to hold the DBM + * open until determined if it needs deleted than to open a second + * time. + */ + if (apr_table_get(col, "KEY") == NULL) { + if (existing_dbm == NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto cleanup; + } +#endif + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to access DBM file \"%s\": %s", + log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); + dbm = NULL; +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + goto cleanup; + } + } + else { + dbm = existing_dbm; + } + + rc = apr_sdbm_delete(dbm, key); + if (rc != APR_SUCCESS) { +#ifdef LOG_NO_COLL_DELET_PB + if (msr->txcfg->debuglog_level >= 9) +#endif + msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", " + "key \"%s\"): %s", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc)); + msr->msc_sdbm_delete_error = 1; + goto cleanup; + } + + + if (existing_dbm == NULL) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + dbm = NULL; + } + + if (expired && (msr->txcfg->debuglog_level >= 9)) { + msr_log(msr, 9, "collection_retrieve_ex: Collection expired (name \"%s\", key \"%s\").", col_name, + log_escape_ex(msr->mp, col_key, col_key_len)); + } + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Deleted collection (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + } + goto cleanup; + } + + /* Update UPDATE_RATE */ + { + msc_string *var; + int create_time, counter; + + var = (msc_string *)apr_table_get(col, "CREATE_TIME"); + if (var == NULL) { + /* Error. */ + } else { + create_time = atoi(var->value); + var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); + if (var == NULL) { + /* Error. */ + } else { + apr_time_t td; + counter = atoi(var->value); + + /* UPDATE_RATE is removed on store, so add it back here */ + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "UPDATE_RATE"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + + /* NOTE: No rate if there has been no time elapsed */ + td = (apr_time_sec(apr_time_now()) - create_time); + if (td == 0) { + var->value = apr_psprintf(msr->mp, "%d", 0); + } + else { + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, + (apr_time_t)((60 * counter)/td)); + } + var->value_len = strlen(var->value); + } + } + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Retrieved collection (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + } + + if ((existing_dbm == NULL) && dbm) { + /* Should not ever get here */ + msr_log(msr, 1, "collection_retrieve_ex: Internal Error: Collection remained open (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + } + + return col; + +cleanup: + + if ((existing_dbm == NULL) && dbm) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + } + + return NULL; +} + +/** + * + */ +apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name, + const char *col_key, int col_key_len) +{ + assert(msr != NULL); + apr_time_t time_before = apr_time_now(); + apr_table_t *rtable = NULL; + + rtable = collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len); + + msr->time_storage_read += apr_time_now() - time_before; + + return rtable; +} + +/** + * + */ +int collection_store(modsec_rec *msr, apr_table_t *col) { + assert(msr != NULL); + char *dbm_filename = NULL; + msc_string *var_name = NULL, *var_key = NULL; + unsigned char *blob = NULL; + unsigned int blob_size, blob_offset; + apr_status_t rc; + apr_sdbm_datum_t key; + apr_sdbm_datum_t value; + apr_sdbm_t *dbm = NULL; + const apr_array_header_t *arr; + apr_table_entry_t *te; + int i; + const apr_table_t *stored_col = NULL; + const apr_table_t *orig_col = NULL; + char *userinfo = get_username(msr->mp); + + var_name = (msc_string *)apr_table_get(col, "__name"); + if (var_name == NULL) { + goto error; + } + + var_key = (msc_string *)apr_table_get(col, "__key"); + if (var_key == NULL) { + goto error; + } + + if (msr->txcfg->data_dir == NULL) { + msr_log(msr, 1, "collection_store: Unable to store collection (name \"%s\", key \"%s\"). Use " + "SecDataDir to define data directory first.", log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var_key->value, var_key->value_len)); + goto error; + } + + // ENH: lowercase the var name in the filename + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", var_name->value, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value), + log_escape(msr->mp, dbm_filename)); + } + +#ifdef GLOBAL_COLLECTION_LOCK + /* Need to lock to pull in the stored data again and apply deltas. */ + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* Delete IS_NEW on store. */ + apr_table_unset(col, "IS_NEW"); + + /* Delete UPDATE_RATE on store to save space as it is calculated */ + apr_table_unset(col, "UPDATE_RATE"); + + /* Update the timeout value. */ + { + msc_string *var = (msc_string *)apr_table_get(col, "TIMEOUT"); + if (var != NULL) { + int timeout = atoi(var->value); + var = (msc_string *)apr_table_get(col, "__expire_KEY"); + if (var != NULL) { + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()) + timeout)); + var->value_len = strlen(var->value); + } + } + } + + /* LAST_UPDATE_TIME */ + { + msc_string *var = (msc_string *)apr_table_get(col, "LAST_UPDATE_TIME"); + if (var == NULL) { + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "LAST_UPDATE_TIME"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + } + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()))); + var->value_len = strlen(var->value); + } + + /* UPDATE_COUNTER */ + { + msc_string *var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); + int counter = 0; + if (var == NULL) { + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "UPDATE_COUNTER"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + } else { + counter = atoi(var->value); + } + var->value = apr_psprintf(msr->mp, "%d", counter + 1); + var->value_len = strlen(var->value); + } + + /* ENH Make the expiration timestamp accessible in blob form so that + * it is easier/faster to determine expiration without having to + * convert back to table form + */ + + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + msr_log(msr, 1, "collection_store: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + dbm = NULL; + goto error; + } + +#ifndef GLOBAL_COLLECTION_LOCK + /* Need to lock to pull in the stored data again and apply deltas. */ + rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* If there is an original value, then create a delta and + * apply the delta to the current value */ + orig_col = (const apr_table_t *)apr_table_get(msr->collections_original, var_name->value); + if (orig_col != NULL) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Re-retrieving collection prior to store: %s", + apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value)); + } + + stored_col = (const apr_table_t *)collection_retrieve_ex(dbm, msr, var_name->value, var_key->value, var_key->value_len); + } + + /* Merge deltas and calculate the size first. */ + blob_size = 3 + 2; + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *var = (msc_string *)te[i].val; + int len; + + /* If there is an original value, then apply the delta + * to the latest stored value */ + if (stored_col != NULL) { + const msc_string *orig_var = (const msc_string *)apr_table_get(orig_col, var->name); + if (orig_var != NULL) { + const msc_string *stored_var = (const msc_string *)apr_table_get(stored_col, var->name); + if (stored_var != NULL) { + int origval = atoi(orig_var->value); + int ourval = atoi(var->value); + int storedval = atoi(stored_var->value); + int delta = ourval - origval; + int newval = storedval + delta; + + if (newval < 0) newval = 0; /* Counters never go below zero. */ + + var->value = apr_psprintf(msr->mp, "%d", newval); + var->value_len = strlen(var->value); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Delta applied for %s.%s %d->%d (%d): %d + (%d) = %d [%s,%d]", + log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var->name, var->name_len), + origval, ourval, delta, storedval, delta, newval, var->value, var->value_len); + } + } + } + } + + // Allocate blob_size for keys + len = var->name_len + 1; + if (len >= 65536) len = 65536; + blob_size += len + 2; + + // Allocate blob_size for values + len = var->value_len + 1; + if (len >= 65536) len = 65536; + blob_size += len + 2; + } + + /* Now generate the binary object. */ + blob = apr_pcalloc(msr->mp, blob_size); + if (blob == NULL) { + if (dbm != NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + } + + return -1; + } + + blob[0] = 0x49; + blob[1] = 0x52; + blob[2] = 0x01; + + blob_offset = 3; + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *var = (msc_string *)te[i].val; + int len; + + len = var->name_len + 1; + if (len >= 65536) len = 65536; + + blob[blob_offset + 0] = (len & 0xff00) >> 8; + blob[blob_offset + 1] = len & 0x00ff; + memcpy(blob + blob_offset + 2, var->name, len - 1); + blob[blob_offset + 2 + len - 1] = '\0'; + blob_offset += 2 + len; + + len = var->value_len + 1; + if (len >= 65536) len = 65536; + + blob[blob_offset + 0] = (len & 0xff00) >> 8; + blob[blob_offset + 1] = len & 0x00ff; + memcpy(blob + blob_offset + 2, var->value, len - 1); + blob[blob_offset + 2 + len - 1] = '\0'; + blob_offset += 2 + len; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Wrote variable: name \"%s\", value \"%s\".", + log_escape_ex(msr->mp, var->name, var->name_len), + log_escape_ex(msr->mp, var->value, var->value_len)); + } + } + + blob[blob_offset] = 0; + blob[blob_offset + 1] = 0; + + /* And, finally, store it. */ + key.dptr = var_key->value; + key.dsize = var_key->value_len + 1; + + value.dptr = (char *)blob; + value.dsize = blob_size; + + rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename, + get_apr_error(msr->mp, rc)); + if (dbm != NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + } + + return -1; + } + +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\").", + log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var_key->value, var_key->value_len)); + } + + return 0; + +error: + return -1; +} + +/** + * + */ +int collections_remove_stale(modsec_rec *msr, const char *col_name) { + assert(msr != NULL); + assert(col_name != NULL); + char *dbm_filename = NULL; + apr_sdbm_datum_t key, value; + apr_sdbm_t *dbm = NULL; + apr_status_t rc; + apr_array_header_t *keys_arr; + char **keys; + apr_time_t now = apr_time_sec(msr->request_time); + int i; + char *userinfo = get_username(msr->mp); + + if (msr->txcfg->data_dir == NULL) { + /* The user has been warned about this problem enough times already by now. + * msr_log(msr, 1, "Unable to access collection file (name \"%s\"). Use SecDataDir to " + * "define data directory first.", log_escape(msr->mp, col_name)); + */ + goto error; + } + + if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE")) + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", msr->txcfg->webappid, "_", col_name, NULL); + else + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), + log_escape(msr->mp, dbm_filename)); + } + +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + msr_log(msr, 1, "collections_remove_stale: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + dbm = NULL; + goto error; + } + + /* First get a list of all keys. */ + keys_arr = apr_array_make(msr->mp, 256, sizeof(char *)); + +#ifndef GLOBAL_COLLECTION_LOCK + rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* No one can write to the file while doing this so + * do it as fast as possible. + */ + rc = apr_sdbm_firstkey(dbm, &key); + while(rc == APR_SUCCESS) { + if (key.dsize) { + char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1); + *(char **)apr_array_push(keys_arr) = s; + } + rc = apr_sdbm_nextkey(dbm, &key); + } +#ifndef GLOBAL_COLLECTION_LOCK + apr_sdbm_unlock(dbm); +#endif + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Found %d record(s) in file \"%s\".", keys_arr->nelts, + log_escape(msr->mp, dbm_filename)); + } + + /* Now retrieve the entires one by one. */ + keys = (char **)keys_arr->elts; + for (i = 0; i < keys_arr->nelts; i++) { + key.dptr = keys[i]; + key.dsize = strlen(key.dptr) + 1; + + rc = apr_sdbm_fetch(dbm, &value, key); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed reading DBM file \"%s\": %s", + log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); + goto error; + } + + if (value.dptr != NULL) { + apr_table_t *col = NULL; + msc_string *var = NULL; + + col = collection_unpack(msr, (const unsigned char *)value.dptr, value.dsize, 0); + if (col == NULL) { + goto error; + } + + var = (msc_string *)apr_table_get(col, "__expire_KEY"); + if (var == NULL) { + msr_log(msr, 1, "collections_remove_stale: Collection cleanup discovered entry with no " + "__expire_KEY (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); + } else { + unsigned int expiry_time = atoi(var->value); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Record (name \"%s\", key \"%s\") set to expire in %" APR_TIME_T_FMT " seconds.", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), + expiry_time - now); + } + + if (expiry_time <= now) { + rc = apr_sdbm_delete(dbm, key); + if (rc != APR_SUCCESS) { +#ifdef LOG_NO_COLL_DELET_PB + if (msr->txcfg->debuglog_level >= 9) +#endif + msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", " + "key \"%s\"): %s", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc)); + msr->msc_sdbm_delete_error = 1; + goto error; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collections_remove_stale: Removed stale collection (name \"%s\", " + "key \"%s\").", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); + } + } + } + } else { + /* Ignore entry not found - it may have been removed in the meantime. */ + } + } + + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + return 1; + +error: + + if (dbm) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + } + + return -1; +} \ No newline at end of file diff --git a/apache2/re.c b/apache2/re.c index 9ded3be796..8e69f5bafa 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -57,6 +57,7 @@ static apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr); * \param targets Exception list. */ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *var, const char *exceptions) { + assert(msr != NULL); const char *targets = NULL; char *savedptr = NULL, *target = NULL; char *c = NULL, *name = NULL, *value = NULL; @@ -64,9 +65,6 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va char *myvalue = NULL, *myname = NULL; int match = 0; - if(msr == NULL) - return 0; - if(var == NULL) return 0; @@ -76,8 +74,9 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va if(rule->actionset == NULL) return 0; - if(rule->actionset->id !=NULL) { + assert(exceptions != NULL); + { myvar = apr_pstrdup(msr->mp, var->name); c = strchr(myvar,':'); @@ -94,7 +93,7 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va if(targets != NULL) { if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "fetch_target_exception: Found exception target list [%s] for rule id %s", targets, rule->actionset->id); + msr_log(msr, 9, "fetch_target_exception: Found exception target list [%s] for rule id %s", targets, id_log(rule)); } target = apr_strtok((char *)targets, ",", &savedptr); @@ -139,7 +138,7 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va } } else { if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "fetch_target_exception: No exception target found for rule id %s.", rule->actionset->id); + msr_log(msr, 9, "fetch_target_exception: No exception target found for rule id %s.", id_log(rule)); } } @@ -203,6 +202,7 @@ char *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, apr_array_header_t *phase_arr, const char *p2, const char *p3) { + assert(ruleset != NULL); msre_rule **rules; int i, j, mode; char *err; @@ -212,11 +212,9 @@ char *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, rules = (msre_rule **)phase_arr->elts; for (i = 0; i < phase_arr->nelts; i++) { msre_rule *rule = (msre_rule *)rules[i]; - if (mode == 0) { /* Looking for next rule. */ if (msre_ruleset_rule_matches_exception(rule, re)) { - - err = update_rule_target_ex(NULL, ruleset, rule, p2, p3); + err = update_rule_target_ex(msr, ruleset, rule, p2, p3); if (err) return err; if (rule->actionset->is_chained) mode = 2; /* Match all rules in this chain. */ } else { @@ -238,6 +236,7 @@ char *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *rule, const char *p2, const char *p3) { + assert(ruleset != NULL); msre_var **targets = NULL; const char *current_targets = NULL; @@ -637,7 +636,10 @@ static char *msre_generate_target_string(apr_pool_t *pool, msre_rule *rule) { /** * Generate an action string from an actionset. */ -static char *msre_actionset_generate_action_string(apr_pool_t *pool, const msre_actionset *actionset) { +#ifndef DEBUG_CONF +static +#endif +char *msre_actionset_generate_action_string(apr_pool_t *pool, const msre_actionset *actionset) { const apr_array_header_t *tarr = NULL; const apr_table_entry_t *telts = NULL; char *actions = NULL; @@ -864,6 +866,7 @@ static msre_action_metadata *msre_resolve_action(msre_engine *engine, const char msre_var *msre_create_var_ex(apr_pool_t *pool, msre_engine *engine, const char *name, const char *param, modsec_rec *msr, char **error_msg) { + // msr can be NULL const char *varparam = param; msre_var *var = apr_pcalloc(pool, sizeof(msre_var)); if (var == NULL) return NULL; @@ -944,6 +947,9 @@ msre_var *msre_create_var_ex(apr_pool_t *pool, msre_engine *engine, const char * static msre_var *msre_create_var(msre_ruleset *ruleset, const char *name, const char *param, modsec_rec *msr, char **error_msg) { + // msr can be NULL + assert(ruleset != NULL); + assert(error_msg != NULL); msre_var *var = msre_create_var_ex(ruleset->mp, ruleset->engine, name, param, msr, error_msg); if (var == NULL) return NULL; @@ -1539,6 +1545,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re #if defined(PERFORMANCE_MEASUREMENT) apr_time_t time1 = 0; #endif + assert(rule->actionset != NULL); /* Reset the rule interception flag */ msr->rule_was_intercepted = 0; @@ -1566,7 +1573,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re saw_starter = 0; if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "Current rule is id=\"%s\" [chained %d] is trying to find the SecMarker=\"%s\" [stater %d]",rule->actionset->id,last_rule->actionset->is_chained,skip_after,saw_starter); + msr_log(msr, 9, "Current rule is id=\"%s\" [chained %d] is trying to find the SecMarker=\"%s\" [stater %d]", id_log(rule),last_rule->actionset->is_chained,skip_after,saw_starter); } } @@ -1723,7 +1730,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re msr_log(msr, 5, "Not processing %srule id=\"%s\": " "removed by ctl action", rule->actionset->is_chained ? "chained " : "", - rule->actionset->id); + id_log(rule)); } /* Skip the whole chain, if this is a chained rule */ @@ -1757,11 +1764,11 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re fn = apr_psprintf(p, " [file \"%s\"] [line \"%d\"]", rule->filename, rule->line_num); } - if (rule->actionset != NULL && rule->actionset->id != NULL) { + if (rule->actionset->id != NULL) { id = apr_psprintf(p, " [id \"%s\"]", rule->actionset->id); } - if (rule->actionset != NULL && rule->actionset->rev != NULL) { + if (rule->actionset->rev != NULL) { rev = apr_psprintf(p, " [rev \"%s\"]", rule->actionset->rev); } @@ -1893,23 +1900,17 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } } else if (rc < 0) { - const char *id = ""; const char *msg = ""; - if (rule->actionset) { - if (rule->actionset->id) { - id = rule->actionset->id; - } - if (rule->actionset->msg) { - msg = rule->actionset->msg; - } + if (rule->actionset->msg) { + msg = rule->actionset->msg; } - msr_log(msr, 1, "Rule processing failed (id=%s, msg=%s).", id, msg); + msr_log(msr, 1, "Rule processing failed (id=%s, msg=%s).", id_log(rule), msg); if (msr->txcfg->reqintercept_oe == 1) { apr_table_clear(msr->matched_vars); return -1; } else { - if (rule->actionset && rule->actionset->is_chained) { + if (rule->actionset->is_chained) { /* If the current rule is part of a chain then * we need to skip over all the rules in the chain. */ @@ -1933,17 +1934,11 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } } else { - const char *id = ""; const char *msg = ""; - if (rule->actionset) { - if (rule->actionset->id) { - id = rule->actionset->id; - } - if (rule->actionset->msg) { - msg = rule->actionset->msg; - } + if (rule->actionset->msg) { + msg = rule->actionset->msg; } - msr_log(msr, 1, "Rule processing failed with unknown return code: %d (id=%s, msg=%s).", rc, id, msg); + msr_log(msr, 1, "Rule processing failed with unknown return code: %d (id=%s, msg=%s).", rc, id_log(rule), msg); apr_table_clear(msr->matched_vars); return -1; } @@ -2081,6 +2076,8 @@ static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, rules = (msre_rule **)phase_arr->elts; for (i = 0; i < phase_arr->nelts; i++) { msre_rule *rule = (msre_rule *)rules[i]; + assert(rule != NULL); + assert(rule->actionset != NULL); if (mode == 0) { /* Looking for next rule. */ int remove_rule = 0; @@ -2089,7 +2086,7 @@ static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, if (rule->placeholder == RULE_PH_NONE) { switch(re->type) { case RULE_EXCEPTION_REMOVE_ID : - if ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) { + if (rule->actionset->id != NULL) { int ruleid = atoi(rule->actionset->id); if (rule_id_in_range(ruleid, re->param)) { @@ -2142,9 +2139,9 @@ static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, if (remove_rule) { /* Do not increment j. */ removed_count++; - if (rule->actionset && rule->actionset->is_chained) mode = 2; /* Remove rules in this chain. */ + if (rule->actionset->is_chained) mode = 2; /* Remove rules in this chain. */ } else { - if (rule->actionset && rule->actionset->is_chained) mode = 1; /* Keep rules in this chain. */ + if (rule->actionset->is_chained) mode = 1; /* Keep rules in this chain. */ rules[j++] = rules[i]; } } else { /* Handling rule that is part of a chain. */ @@ -2201,6 +2198,7 @@ static const char *msre_format_severity(int severity) { * Creates a string containing the metadata of the supplied rule. */ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) { + assert(msr != NULL); const apr_array_header_t *tarr; const apr_table_entry_t *telts; char *id = ""; @@ -2497,6 +2495,8 @@ msre_rule *msre_rule_lua_create(msre_ruleset *ruleset, static void msre_perform_nondisruptive_actions(modsec_rec *msr, msre_rule *rule, msre_actionset *actionset, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(actionset != NULL); const apr_array_header_t *tarr; const apr_table_entry_t *telts; int i; @@ -2519,6 +2519,8 @@ static void msre_perform_nondisruptive_actions(modsec_rec *msr, msre_rule *rule, static void msre_perform_disruptive_actions(modsec_rec *msr, msre_rule *rule, msre_actionset *actionset, apr_pool_t *mptmp, const char *message) { + assert(msr != NULL); + assert(actionset != NULL); const apr_array_header_t *tarr; const apr_table_entry_t *telts; int i; @@ -2603,6 +2605,14 @@ static void msre_perform_disruptive_actions(modsec_rec *msr, msre_rule *rule, static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr, msre_actionset *acting_actionset, apr_pool_t *mptmp) { + assert(var != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(rule->op_metadata != NULL); + assert(rule->op_metadata->execute != NULL); + assert(msr != NULL); + assert(acting_actionset != NULL); + assert(mptmp != NULL); apr_time_t time_before_op = 0; char *my_error_msg = NULL; const char *full_varname = NULL; @@ -3111,6 +3121,8 @@ static apr_status_t msre_rule_process_normal(msre_rule *rule, modsec_rec *msr) { /* Perform transformations. */ tarr = apr_table_elts(normtab); + /* if no transformation, multi_match makes no sense and breaks the logic */ + if (tarr->nelts == 0) multi_match = 0; /* Execute transformations in a loop. */ diff --git a/apache2/re.h b/apache2/re.h index c0c5433965..db6c190455 100644 --- a/apache2/re.h +++ b/apache2/re.h @@ -75,6 +75,10 @@ int DSOLOCAL rule_id_in_range(int ruleid, const char *range); msre_var DSOLOCAL *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, msre_rule *rule, apr_pool_t *mptmp); +#ifdef DEBUG_CONF +char DSOLOCAL* msre_actionset_generate_action_string(apr_pool_t* pool, const msre_actionset* actionset); +#endif + #if defined(WITH_LUA) apr_table_t DSOLOCAL *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, msre_rule *rule, apr_pool_t *mptmp); diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 02ec07d222..36f898dd23 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -51,6 +51,7 @@ static void msre_engine_action_register(msre_engine *engine, const char *name, msre_var *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, msre_rule *rule, apr_pool_t *mptmp) { + assert(msr != NULL); apr_table_t *vartab = NULL; const apr_table_entry_t *te = NULL; const apr_array_header_t *arr = NULL; @@ -108,6 +109,7 @@ msre_var *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t apr_table_t *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, msre_rule *rule, apr_pool_t *mptmp) { + assert(msr != NULL); const apr_array_header_t *tarr; const apr_table_entry_t *telts; apr_table_t *vartab = NULL, *tvartab = NULL; @@ -169,6 +171,8 @@ apr_table_t *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header * in the given variable. */ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); char *data = NULL; apr_array_header_t *arr = NULL; char *p = NULL, *q = NULL, *t = NULL; @@ -316,6 +320,7 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t * value that is set. */ apr_status_t collection_original_setvar(modsec_rec *msr, const char *col_name, const msc_string *orig_var) { + assert(msr != NULL); apr_table_t *table = NULL; msc_string *var = NULL; const char *var_name = NULL; @@ -628,6 +633,8 @@ static apr_status_t msre_action_redirect_init(msre_engine *engine, apr_pool_t *m static apr_status_t msre_action_redirect_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); msc_string *var = NULL; var = apr_pcalloc(mptmp, sizeof(msc_string)); @@ -660,6 +667,8 @@ static apr_status_t msre_action_proxy_init(msre_engine *engine, apr_pool_t *mp, static apr_status_t msre_action_proxy_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); msc_string *var = NULL; var = apr_pcalloc(mptmp, sizeof(msc_string)); @@ -968,6 +977,8 @@ static apr_status_t msre_action_ctl_init(msre_engine *engine, apr_pool_t *mp, ms static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); char *name = NULL; char *value = NULL; @@ -1236,13 +1247,21 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, msr_log(msr, 4, "Ctl: ruleRemoveTargetById id=%s targets=%s", p1, p2); } if (p2 == NULL) { - msr_log(msr, 1, "ModSecurity: Missing target for id \"%s\"", p1); + msr_log(msr, 1, "Ctl: ruleRemoveTargetById: Missing target for id \"%s\"", p1); return -1; } re = apr_pcalloc(msr->mp, sizeof(rule_exception)); + if (re == NULL) { + msr_log(msr, 1, "Ctl: Memory allocation error"); + return -1; + } re->type = RULE_EXCEPTION_REMOVE_ID; re->param = (const char *)apr_pstrdup(msr->mp, p1); + if (re->param == NULL) { + msr_log(msr, 1, "Ctl: Memory allocation error"); + return -1; + } apr_table_addn(msr->removed_targets, apr_pstrdup(msr->mp, p2), (void *)re); return 1; } else @@ -1336,6 +1355,8 @@ static char *msre_action_xmlns_validate(msre_engine *engine, apr_pool_t *mp, msr static apr_status_t msre_action_sanitizeArg_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); const char *sargname = NULL; const apr_array_header_t *tarr; const apr_table_entry_t *telts; @@ -1364,6 +1385,8 @@ static apr_status_t msre_action_sanitizeArg_execute(modsec_rec *msr, apr_pool_t static apr_status_t msre_action_sanitizeMatched_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); const char *sargname = NULL; const apr_array_header_t *tarr; const apr_table_entry_t *telts; @@ -1439,6 +1462,8 @@ static apr_status_t msre_action_sanitizeMatched_execute(modsec_rec *msr, apr_poo static apr_status_t msre_action_sanitizeRequestHeader_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); apr_table_set(msr->request_headers_to_sanitize, action->param, "1"); return 1; } @@ -1447,6 +1472,8 @@ static apr_status_t msre_action_sanitizeRequestHeader_execute(modsec_rec *msr, a static apr_status_t msre_action_sanitizeResponseHeader_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); apr_table_set(msr->response_headers_to_sanitize, action->param, "1"); return 1; } @@ -1455,6 +1482,8 @@ static apr_status_t msre_action_sanitizeResponseHeader_execute(modsec_rec *msr, static apr_status_t msre_action_setenv_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); char *data = apr_pstrdup(mptmp, action->param); char *env_name = NULL, *env_value = NULL; char *s = NULL; @@ -1528,6 +1557,9 @@ static apr_status_t msre_action_setenv_execute(modsec_rec *msr, apr_pool_t *mptm apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, char *var_name, char *var_value) { + assert(msr != NULL); + assert(var_name != NULL); + assert(var_value != NULL); char *col_name = NULL; char *s = NULL; apr_table_t *target_col = NULL; @@ -1549,9 +1581,13 @@ apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp, var->value_len = strlen(var->value); expand_macros(msr, var, rule, mptmp); var_name = log_escape_nq_ex(msr->mp, var->value, var->value_len); + if (var_name == NULL) { + msr_log(msr, 1, "Failed to allocate space to expand name macros"); + return -1; + } /* Handle the exclamation mark. */ - if (var_name != NULL && var_name[0] == '!') { + if (var_name[0] == '!') { var_name = var_name + 1; is_negated = 1; } @@ -1711,6 +1747,8 @@ apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp, static apr_status_t msre_action_setvar_parse(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); char *data = apr_pstrdup(mptmp, action->param); char *var_name = NULL, *var_value = NULL; char *s = NULL; @@ -1736,6 +1774,8 @@ static apr_status_t msre_action_setvar_parse(modsec_rec *msr, apr_pool_t *mptmp, static apr_status_t msre_action_expirevar_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); char *data = apr_pstrdup(mptmp, action->param); char *col_name = NULL, *var_name = NULL, *var_value = NULL; char *s = NULL; @@ -1833,6 +1873,8 @@ static apr_status_t msre_action_expirevar_execute(modsec_rec *msr, apr_pool_t *m static apr_status_t msre_action_deprecatevar_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); char *data = apr_pstrdup(mptmp, action->param); char *col_name = NULL, *var_name = NULL, *var_value = NULL; char *s = NULL; @@ -1967,6 +2009,8 @@ static apr_status_t msre_action_deprecatevar_execute(modsec_rec *msr, apr_pool_t static apr_status_t init_collection(modsec_rec *msr, const char *real_col_name, const char *col_name, const char *col_key, unsigned int col_key_len) { + assert(msr != NULL); + assert(real_col_name != NULL); apr_table_t *table = NULL; msc_string *var = NULL; @@ -1980,7 +2024,6 @@ static apr_status_t init_collection(modsec_rec *msr, const char *real_col_name, /* Init collection from storage. */ table = collection_retrieve(msr, real_col_name, col_key, col_key_len); - if (table == NULL) { /* Does not exist yet - create new. */ @@ -2101,6 +2144,8 @@ static apr_status_t init_collection(modsec_rec *msr, const char *real_col_name, static apr_status_t msre_action_initcol_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); char *data = apr_pstrdup(msr->mp, action->param); char *col_name = NULL, *col_key = NULL; unsigned int col_key_len; @@ -2132,6 +2177,8 @@ static apr_status_t msre_action_initcol_execute(modsec_rec *msr, apr_pool_t *mpt static apr_status_t msre_action_setsid_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); msc_string *var = NULL; char *real_col_name = NULL, *col_key = NULL; unsigned int col_key_len; @@ -2156,6 +2203,8 @@ static apr_status_t msre_action_setsid_execute(modsec_rec *msr, apr_pool_t *mptm static apr_status_t msre_action_setuid_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); msc_string *var = NULL; char *real_col_name = NULL, *col_key = NULL; unsigned int col_key_len; @@ -2180,6 +2229,8 @@ static apr_status_t msre_action_setuid_execute(modsec_rec *msr, apr_pool_t *mptm static apr_status_t msre_action_setrsc_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); msc_string *var = NULL; char *real_col_name = NULL, *col_key = NULL; unsigned int col_key_len; @@ -2228,7 +2279,9 @@ static char *msre_action_exec_validate(msre_engine *engine, apr_pool_t *mp, msre static apr_status_t msre_action_exec_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { - #if defined(WITH_LUA) + assert(msr != NULL); + assert(action != NULL); +#if defined(WITH_LUA) if (action->param_data != NULL) { /* Lua */ msc_script *script = (msc_script *)action->param_data; char *my_error_msg = NULL; @@ -2256,6 +2309,8 @@ static apr_status_t msre_action_exec_execute(modsec_rec *msr, apr_pool_t *mptmp, static apr_status_t msre_action_prepend_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); msc_string *var = NULL; /* Expand any macros in the text */ @@ -2276,6 +2331,8 @@ static apr_status_t msre_action_prepend_execute(modsec_rec *msr, apr_pool_t *mpt static apr_status_t msre_action_append_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); msc_string *var = NULL; /* Expand any macros in the text */ diff --git a/apache2/re_operators.c b/apache2/re_operators.c index cfd8952539..178c7b7bb0 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -70,6 +70,7 @@ msre_op_metadata *msre_engine_op_resolve(msre_engine *engine, const char *name) static int msre_op_unconditionalmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(error_msg != NULL); *error_msg = "Unconditional match in SecAction."; /* Always match. */ @@ -81,6 +82,7 @@ static int msre_op_unconditionalmatch_execute(modsec_rec *msr, msre_rule *rule, static int msre_op_nomatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(error_msg != NULL); *error_msg = "No match."; /* Never match. */ @@ -131,13 +133,13 @@ static int msre_op_ipmatch_param_init(msre_rule *rule, char **error_msg) { * \retval 0 On No Match */ static int msre_op_ipmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(var != NULL); + assert(error_msg != NULL); TreeRoot *rtree = NULL; int res = 0; - if (error_msg == NULL) - return -1; - else - *error_msg = NULL; + *error_msg = NULL; if (rule == NULL || rule->ip_op == NULL) { msr_log(msr, 1, "ipMatch Internal Error: ipmatch value is null."); @@ -258,14 +260,14 @@ static int msre_op_ipmatchFromFile_param_init(msre_rule *rule, char **error_msg) */ static int msre_op_ipmatchFromFile_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); TreeRoot *rtree = (TreeRoot *)rule->op_param_data; int res = 0; - if (error_msg == NULL) - return -1; - else - *error_msg = NULL; + *error_msg = NULL; if (rtree == NULL) { @@ -469,8 +471,20 @@ static int msre_op_rsub_param_init(msre_rule *rule, char **error_msg) { * \retval 0 On No Match */ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (!str) { + msr_log(msr, 1, "rsub: Memory allocation error"); + return -1; + } msc_string *re_pattern = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (!re_pattern) { + msr_log(msr, 1, "rsub: Memory allocation error"); + return -1; + } char *offset = NULL; char *data = NULL, *pattern = NULL; char *data_out = NULL; @@ -483,7 +497,6 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, regmatch_t pmatch[AP_MAX_REG_MATCH]; #endif - if (error_msg == NULL) return -1; *error_msg = NULL; if(strcmp(var->name,"STREAM_OUTPUT_BODY") == 0 ) { @@ -751,8 +764,16 @@ static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) { * \retval 0 On fail */ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; msc_string *re_pattern = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (!re_pattern) { + msr_log(msr, 1, "validateHash: Memory allocation error"); + return -1; + } const char *target; const char *errptr = NULL; int erroffset; @@ -761,15 +782,12 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v char *my_error_msg = NULL; int ovector[33]; int rc; - const char *pattern = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT int jit; #endif #endif - - if (error_msg == NULL) return -1; *error_msg = NULL; if (msr->txcfg->hash_enforcement == HASH_DISABLED || msr->txcfg->hash_is_enabled == HASH_DISABLED) @@ -791,7 +809,7 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v expand_macros(msr, re_pattern, rule, msr->mp); - pattern = log_escape_re(msr->mp, re_pattern->value); + const char *pattern = log_escape_re(msr->mp, re_pattern->value); if (msr->txcfg->debuglog_level >= 6) { msr_log(msr, 6, "Escaping pattern [%s]",pattern); } @@ -1010,8 +1028,21 @@ static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) { } static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; + if (!regex) { + msr_log(msr, 1, "rx: Memory allocation error"); + return -1; + } msc_string *re_pattern = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (!re_pattern) { + msr_log(msr, 1, "rx: Memory allocation error"); + return -1; + } const char *target; const char *errptr = NULL; int erroffset; @@ -1032,8 +1063,6 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c #endif #endif - - if (error_msg == NULL) return -1; *error_msg = NULL; if (regex == NULL) { @@ -1108,15 +1137,18 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c target_length = var->value_len; } - /* Are we supposed to capture subexpressions? */ - capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; - matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; - if(!matched_bytes) - matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; + if (rule->actionset->actions) { + /* Are we supposed to capture subexpressions? */ + capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; + matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; + if (!matched_bytes) + matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; - matched = apr_table_get(rule->actionset->actions, "sanitizeMatched") ? 1 : 0; - if(!matched) - matched = apr_table_get(rule->actionset->actions, "sanitiseMatched") ? 1 : 0; + matched = apr_table_get(rule->actionset->actions, "sanitizeMatched") ? 1 : 0; + if (!matched) + matched = apr_table_get(rule->actionset->actions, "sanitiseMatched") ? 1 : 0; + } + else capture = 0; /* Show when the regex captures but "capture" is not set */ if (msr->txcfg->debuglog_level >= 6) { @@ -1456,6 +1488,11 @@ static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) { } static int msre_op_pm_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(var != NULL); + assert(error_msg != NULL); const char *match = NULL; apr_status_t rc = 0; int capture; @@ -1465,7 +1502,9 @@ static int msre_op_pm_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c if ((var->value == NULL) || (var->value_len == 0)) return 0; /* Are we supposed to capture subexpressions? */ - capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; + if (rule->actionset->actions) + capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; + else capture = 0; if (rule->op_param_data == NULL) { @@ -1642,6 +1681,9 @@ static const char *gsb_reduce_char(apr_pool_t *pool, const char *domain) { * \retval 0 On No Match */ static int verify_gsb(gsb_db *gsb, modsec_rec *msr, const char *match, unsigned int match_length) { + assert(gsb != NULL); + assert(msr != NULL); + assert(match != NULL); apr_md5_ctx_t ctx; apr_status_t rc; unsigned char digest[APR_MD5_DIGESTSIZE]; @@ -1719,6 +1761,10 @@ static int msre_op_gsbLookup_param_init(msre_rule *rule, char **error_msg) { * \retval 0 On No Match */ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; char *my_error_msg = NULL; int ovector[33]; @@ -2065,7 +2111,6 @@ static int msre_op_within_execute(modsec_rec *msr, msre_rule *rule, msre_var *va unsigned int target_length = 0; unsigned int i, i_max; - if (error_msg == NULL) return -1; *error_msg = NULL; str->value = (char *)rule->op_param; @@ -2128,15 +2173,22 @@ static int msre_op_within_execute(modsec_rec *msr, msre_rule *rule, msre_var *va /* contains */ static int msre_op_contains_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); const char *match = NULL; const char *target; unsigned int match_length; unsigned int target_length = 0; unsigned int i, i_max; + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (str == NULL) { + *error_msg = "Internal Error: cannot allocate memory."; + return -1; + } str->value = (char *)rule->op_param; - if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2207,7 +2259,13 @@ static int msre_op_contains_execute(modsec_rec *msr, msre_rule *rule, msre_var * */ static int msre_op_detectSQLi_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - + assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(rule->actionset->actions != NULL); + assert(var != NULL); + assert(var != NULL); + assert(error_msg != NULL); char fingerprint[8]; int issqli; int capture; @@ -2239,6 +2297,11 @@ static int msre_op_detectSQLi_execute(modsec_rec *msr, msre_rule *rule, msre_var */ static int msre_op_detectXSS_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(rule->actionset->actions != NULL); + assert(error_msg != NULL); int capture; int is_xss; @@ -2265,16 +2328,23 @@ static int msre_op_detectXSS_execute(modsec_rec *msr, msre_rule *rule, msre_var /* containsWord */ static int msre_op_containsWord_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); const char *match = NULL; const char *target; unsigned int match_length; unsigned int target_length = 0; unsigned int i, i_max; int rc = 0; + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (str == NULL) { + *error_msg = "Internal Error: cannot allocate memory."; + return -1; + } str->value = (char *)rule->op_param; - if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2282,7 +2352,6 @@ static int msre_op_containsWord_execute(modsec_rec *msr, msre_rule *rule, msre_v str->value_len = strlen(str->value); - if (error_msg == NULL) return -1; *error_msg = NULL; expand_macros(msr, str, rule, msr->mp); @@ -2360,14 +2429,21 @@ static int msre_op_containsWord_execute(modsec_rec *msr, msre_rule *rule, msre_v /* streq */ static int msre_op_streq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (!str) { + msr_log(msr, 1, "streq: Memory allocation error"); + return -1; + } const char *match = NULL; const char *target; unsigned int match_length; unsigned int target_length; str->value = (char *)rule->op_param; - if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2375,7 +2451,6 @@ static int msre_op_streq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var str->value_len = strlen(str->value); - if (error_msg == NULL) return -1; *error_msg = NULL; expand_macros(msr, str, rule, msr->mp); @@ -2416,14 +2491,21 @@ static int msre_op_streq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var /* beginsWith */ static int msre_op_beginsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); const char *match = NULL; const char *target; unsigned int match_length; unsigned int target_length; + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (str == NULL) { + *error_msg = "Internal Error: cannot allocate memory."; + return -1; + } str->value = (char *)rule->op_param; - if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2479,14 +2561,19 @@ static int msre_op_beginsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var /* endsWith */ static int msre_op_endsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + assert(msr != NULL); + assert(rule != NULL); const char *match = NULL; const char *target; unsigned int match_length; unsigned int target_length; + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (str == NULL) { + *error_msg = "Internal Error: cannot allocate memory."; + return -1; + } str->value = (char *)rule->op_param; - if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2494,7 +2581,6 @@ static int msre_op_endsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var * str->value_len = strlen(str->value); - if (error_msg == NULL) return -1; *error_msg = NULL; expand_macros(msr, str, rule, msr->mp); @@ -2571,12 +2657,15 @@ static int msre_op_strmatch_param_init(msre_rule *rule, char **error_msg) { } static int msre_op_strmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); apr_strmatch_pattern *compiled_pattern = (apr_strmatch_pattern *)rule->op_param_data; const char *target; unsigned int target_length; const char *rc; - if (error_msg == NULL) return -1; *error_msg = NULL; if (compiled_pattern == NULL) { @@ -2619,6 +2708,10 @@ static int msre_op_validateDTD_init(msre_rule *rule, char **error_msg) { static int msre_op_validateDTD_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); xmlValidCtxtPtr cvp; xmlDtdPtr dtd; @@ -2689,6 +2782,10 @@ static int msre_op_validateSchema_init(msre_rule *rule, char **error_msg) { static int msre_op_validateSchema_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); xmlSchemaParserCtxtPtr parserCtx; xmlSchemaValidCtxtPtr validCtx; xmlSchemaPtr schema; @@ -2826,6 +2923,10 @@ static int msre_op_verifyCC_init(msre_rule *rule, char **error_msg) { } static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; const char *target; unsigned int target_length; @@ -2845,7 +2946,6 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * #endif #endif - if (error_msg == NULL) return -1; *error_msg = NULL; if (regex == NULL) { @@ -2853,6 +2953,8 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * return -1; } + assert(rule->actionset != NULL); + memset(ovector, 0, sizeof(ovector)); #ifdef WITH_PCRE_STUDY @@ -2943,13 +3045,10 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * * and we are done. */ - if (rule->actionset) { - matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; - } + matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; if(!matched_bytes) matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; - if (apr_table_get(rule->actionset->actions, "capture")) { for(; i < rc; i++) { msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); @@ -3156,6 +3255,11 @@ static int msre_op_verifyCPF_init(msre_rule *rule, char **error_msg) { * \retval 0 On No Match */ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; const char *target; unsigned int target_length; @@ -3175,8 +3279,6 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var #endif #endif - - if (error_msg == NULL) return -1; *error_msg = NULL; if (regex == NULL) { @@ -3184,6 +3286,8 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var return -1; } + assert(rule->actionset != NULL); + memset(ovector, 0, sizeof(ovector)); #ifdef WITH_PCRE_STUDY @@ -3251,11 +3355,11 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var /* Verify a match. */ if (rc > 0) { - const char *match = target + ovector[0]; + const char* match = target + ovector[0]; int length = ovector[1] - ovector[0]; int i = 0; - offset = ovector[2*i]; + offset = ovector[2 * i]; /* Check CPF using the match string */ is_cpf = cpf_verify(match, length); @@ -3273,15 +3377,13 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var * and we are done. */ - if (rule->actionset) { - matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; - } - if(!matched_bytes) + matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; + if (!matched_bytes) matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; if (apr_table_get(rule->actionset->actions, "capture")) { - for(; i < rc; i++) { - msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + for (; i < rc; i++) { + msc_string* s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; s->name = apr_psprintf(msr->mp, "%d", i); if (s->name == NULL) return -1; @@ -3290,33 +3392,34 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var if (s->value == NULL) return -1; s->value_len = length; - apr_table_setn(msr->tx_vars, s->name, (void *)s); + apr_table_setn(msr->tx_vars, s->name, (void*)s); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, log_escape_nq_ex(msr->mp, s->value, s->value_len)); } - if((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { + if ((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { qspos = apr_psprintf(msr->mp, "%s", var->name); parm = strstr(qspos, ":"); - if (parm != NULL) { + if (parm != NULL) { parm++; mparm = apr_palloc(msr->mp, sizeof(msc_parm)); if (mparm == NULL) continue; - mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); + mparm->value = apr_pstrmemdup(msr->mp, s->value, s->value_len); mparm->pad_1 = rule->actionset->arg_min; mparm->pad_2 = rule->actionset->arg_max; - apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); - } else { + apr_table_addn(msr->pattern_to_sanitize, parm, (void*)mparm); + } + else { mparm = apr_palloc(msr->mp, sizeof(msc_parm)); if (mparm == NULL) continue; - mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); - apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); + mparm->value = apr_pstrmemdup(msr->mp, s->value, s->value_len); + apr_table_addn(msr->pattern_to_sanitize, qspos, (void*)mparm); } } @@ -3324,7 +3427,7 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var } /* Unset the remaining TX vars (from previous invocations). */ - for(; i <= 9; i++) { + for (; i <= 9; i++) { char buf[24]; apr_snprintf(buf, sizeof(buf), "%i", i); apr_table_unset(msr->tx_vars, buf); @@ -3359,6 +3462,8 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var * \retval 1 On Valid SSN */ static int ssn_verify(modsec_rec *msr, const char *ssnumber, int len) { + assert(msr != NULL); + assert(ssnumber != NULL); int i; int num[9]; int digits = 0; @@ -3470,6 +3575,11 @@ static int msre_op_verifySSN_init(msre_rule *rule, char **error_msg) { * \retval 0 On No Match */ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; const char *target; unsigned int target_length; @@ -3498,6 +3608,8 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var return -1; } + assert(rule->actionset != NULL); + memset(ovector, 0, sizeof(ovector)); #ifdef WITH_PCRE_STUDY @@ -3587,9 +3699,7 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var * and we are done. */ - if (rule->actionset) { - matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; - } + matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; if(!matched_bytes) matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; @@ -3668,6 +3778,9 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var static int msre_op_geoLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(var != NULL); + assert(error_msg != NULL); geo_rec rec; geo_db *geo = msr->txcfg->geo; const char *geo_host = var->value; @@ -3794,6 +3907,11 @@ static int msre_op_geoLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var /* rbl */ static int msre_op_rbl_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(var != NULL); + assert(error_msg != NULL); unsigned int h0, h1, h2, h3; unsigned int high8bits = 0; char *name_to_check = NULL; @@ -3802,10 +3920,11 @@ static int msre_op_rbl_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, apr_status_t rc; int capture = 0; - if (error_msg == NULL) return -1; *error_msg = NULL; - capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; + if (rule->actionset->actions) + capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; + else capture = 0; /* ENH Add IPv6 support. */ @@ -4082,18 +4201,16 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) static int msre_op_fuzzy_hash_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); #ifdef WITH_SSDEEP char result[FUZZY_MAX_RESULT]; struct fuzzy_hash_param_data *param = rule->op_param_data; struct fuzzy_hash_chunk *chunk = param->head; #endif - if (error_msg == NULL) - { - return -1; - } - *error_msg = NULL; #ifdef WITH_SSDEEP @@ -4174,7 +4291,10 @@ static int msre_op_inspectFile_init(msre_rule *rule, char **error_msg) { static int msre_op_inspectFile_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - if (error_msg == NULL) return -1; + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); *error_msg = NULL; if (rule->op_param_data == NULL) { @@ -4298,10 +4418,13 @@ static int msre_op_validateByteRange_init(msre_rule *rule, char **error_msg) { static int msre_op_validateByteRange_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); char *table = rule->op_param_data; unsigned int i, count; - if (error_msg == NULL) return -1; *error_msg = NULL; if (table == NULL) { @@ -4372,6 +4495,9 @@ static int validate_url_encoding(const char *input, long int input_length) { static int msre_op_validateUrlEncoding_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(var != NULL); + assert(error_msg != NULL); int rc = validate_url_encoding(var->value, var->value_len); switch(rc) { case 1 : @@ -4492,6 +4618,9 @@ static int detect_utf8_character(const unsigned char *p_read, unsigned int lengt static int msre_op_validateUtf8Encoding_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(var != NULL); + assert(error_msg != NULL); unsigned int i, bytes_left; bytes_left = var->value_len; @@ -4549,6 +4678,9 @@ static int msre_op_validateUtf8Encoding_execute(modsec_rec *msr, msre_rule *rule static int msre_op_eq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(error_msg != NULL); msc_string str; int left, right; char *target = NULL; @@ -4587,6 +4719,10 @@ static int msre_op_eq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, static int msre_op_gt_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_string str; int left, right; char *target = NULL; @@ -4630,16 +4766,14 @@ static int msre_op_gt_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, static int msre_op_lt_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_string str; int left, right; char *target = NULL; - if ((var->value == NULL)||(rule->op_param == NULL)) { - /* NULL values do not match anything. */ - return 0; - } - - if (error_msg == NULL) return -1; *error_msg = NULL; if ((var->value == NULL)||(rule->op_param == NULL)) { @@ -4673,6 +4807,10 @@ static int msre_op_lt_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, static int msre_op_ge_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_string str; int left, right; char *target = NULL; @@ -4716,6 +4854,10 @@ static int msre_op_ge_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, static int msre_op_le_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_string str; int left, right; char *target = NULL; @@ -4725,7 +4867,6 @@ static int msre_op_le_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, return 0; } - if (error_msg == NULL) return -1; *error_msg = NULL; if ((var->value == NULL)||(rule->op_param == NULL)) { diff --git a/apache2/re_variables.c b/apache2/re_variables.c index a53140b2c1..5aa7589a2b 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -99,6 +99,10 @@ static char *var_generic_list_validate(msre_ruleset *ruleset, msre_var *var) { static int var_args_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -144,6 +148,10 @@ static int var_args_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_args_combined_size_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; unsigned int combined_size = 0; @@ -171,6 +179,10 @@ static int var_args_combined_size_generate(modsec_rec *msr, msre_var *var, msre_ static int var_args_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -214,6 +226,10 @@ static int var_args_names_generate(modsec_rec *msr, msre_var *var, msre_rule *ru static int var_args_get_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -262,6 +278,10 @@ static int var_args_get_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_args_get_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -308,6 +328,10 @@ static int var_args_get_names_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_args_post_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -356,6 +380,10 @@ static int var_args_post_generate(modsec_rec *msr, msre_var *var, msre_rule *rul static int var_args_post_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -402,10 +430,14 @@ static int var_args_post_names_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_rule_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_actionset *actionset = NULL; - if (rule == NULL) return 0; - actionset = rule->actionset; if (rule->chain_starter != NULL) actionset = rule->chain_starter->actionset; @@ -437,13 +469,13 @@ static int var_rule_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, return var_simple_generate(var, vartab, mptmp, value); } - return 0; } /* ENV */ static char *var_env_validate(msre_ruleset *ruleset, msre_var *var) { + assert(ruleset != NULL); if (var->param == NULL) { return apr_psprintf(ruleset->mp, "Parameter required for ENV."); } @@ -458,6 +490,8 @@ static char *var_env_validate(msre_ruleset *ruleset, msre_var *var) { static int var_env_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); char *value = get_env_var(msr->r, (char *)var->param); if (value != NULL) { return var_simple_generate(var, vartab, mptmp, value); @@ -470,6 +504,7 @@ static int var_env_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_request_uri_raw_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->r->unparsed_uri); } @@ -478,6 +513,8 @@ static int var_request_uri_raw_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_uniqueid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); char *value = get_env_var(msr->r, "UNIQUE_ID"); if (value != NULL) { return var_simple_generate(var, vartab, mptmp, value); @@ -492,10 +529,18 @@ static int var_uniqueid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_request_uri_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) /* dynamic */ { + assert(msr != NULL); + assert(msr->r != NULL); char *value = NULL; if (msr->r->parsed_uri.query == NULL) value = msr->r->parsed_uri.path; - else value = apr_pstrcat(mptmp, msr->r->parsed_uri.path, "?", msr->r->parsed_uri.query, NULL); + else { + value = apr_pstrcat(mptmp, msr->r->parsed_uri.path, "?", msr->r->parsed_uri.query, NULL); + if (!value) { + msr_log(msr, 1, "REQUEST_URI: Memory allocation error"); + return -1; + } + } return var_simple_generate(var, vartab, mptmp, value); } @@ -505,7 +550,12 @@ static int var_request_uri_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_reqbody_processor_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "REQBODY_PROCESSOR: Memory allocation error"); + return -1; + } if (msr->msc_reqbody_processor == NULL) { rvar->value = apr_pstrdup(mptmp, ""); @@ -524,9 +574,22 @@ static int var_reqbody_processor_generate(modsec_rec *msr, msre_var *var, msre_r static int var_sdbm_delete_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "SDBM_DELETE_ERROR: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%d", msr->msc_sdbm_delete_error); + if (!rvar->value) { + msr_log(msr, 1, "SDBM_DELETE_ERROR: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -538,7 +601,12 @@ static int var_sdbm_delete_error_generate(modsec_rec *msr, msre_var *var, msre_r static int var_reqbody_processor_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "REQBODY_ERROR: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%d", msr->msc_reqbody_error); rvar->value_len = strlen(rvar->value); @@ -552,7 +620,16 @@ static int var_reqbody_processor_error_generate(modsec_rec *msr, msre_var *var, static int var_reqbody_processor_error_msg_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(rule != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "REQBODY_ERROR_MSG: Memory allocation error"); + return -1; + } if (msr->msc_reqbody_error_msg == NULL) { rvar->value = apr_pstrdup(mptmp, ""); @@ -581,6 +658,13 @@ static char *var_xml_validate(msre_ruleset *ruleset, msre_var *var) { static int var_xml_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(var->name != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *tarr; const apr_table_entry_t *telts; xmlXPathContextPtr xpathCtx; @@ -667,9 +751,19 @@ static int var_xml_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, content = (char *)xmlNodeGetContent(nodes->nodeTab[i]); if (content != NULL) { + xmlFree(content); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "XML: Memory allocation error"); + count = -1; + goto var_xml_generate_Error; + } rvar->value = apr_pstrdup(mptmp, content); - xmlFree(content); + if (!rvar->value) { + msr_log(msr, 1, "XML: Memory allocation error"); + count = -1; + goto var_xml_generate_Error; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -677,6 +771,7 @@ static int var_xml_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, } } +var_xml_generate_Error: xmlXPathFreeObject(xpathObj); xmlXPathFreeContext(xpathCtx); @@ -688,6 +783,11 @@ static int var_xml_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_webserver_error_log_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(var->name != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; int i, count = 0; @@ -698,7 +798,15 @@ static int var_webserver_error_log_generate(modsec_rec *msr, msre_var *var, msre fem = format_error_log_message(mptmp, em); if (fem != NULL) { rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "WEBSERVER_ERROR_LOG: Memory allocation error"); + return -1; + } rvar->value = apr_pstrdup(mptmp, fem); + if (!rvar->value) { + msr_log(msr, 1, "WEBSERVER_ERROR_LOG: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -713,6 +821,7 @@ static int var_webserver_error_log_generate(modsec_rec *msr, msre_var *var, msre static int var_useragent_ip_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->useragent_ip ? msr->useragent_ip : "0.0.0.0"); } #endif @@ -722,6 +831,7 @@ static int var_useragent_ip_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_remote_addr_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); #if !defined(MSC_TEST) #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 3 if (ap_find_linked_module("mod_remoteip.c") != NULL) { @@ -739,6 +849,7 @@ static int var_remote_addr_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_remote_host_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); const char *value1 = ap_get_remote_host(msr->r->connection, msr->r->per_dir_config, REMOTE_NAME, NULL); return var_simple_generate(var, vartab, mptmp, value1); @@ -749,6 +860,7 @@ static int var_remote_host_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_remote_port_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); char *value = apr_psprintf(mptmp, "%u", msr->remote_port); return var_simple_generate(var, vartab, mptmp, value); } @@ -758,6 +870,7 @@ static int var_remote_port_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_remote_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->remote_user); } @@ -766,6 +879,10 @@ static int var_remote_user_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_tx_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -792,10 +909,18 @@ static int var_tx_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TX: Memory allocation error"); + return -1; + } rvar->value = str->value; rvar->value_len = str->value_len; rvar->name = apr_psprintf(mptmp, "TX:%s", log_escape_nq_ex(mptmp, str->name, str->name_len)); + if (!rvar->name) { + msr_log(msr, 1, "TX: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -810,6 +935,10 @@ static int var_tx_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_geo_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -863,6 +992,10 @@ static int var_highest_severity_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_ip_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -911,6 +1044,8 @@ static int var_ip_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_matched_var_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->matched_var != NULL); return var_simple_generate_ex(var, vartab, mptmp, apr_pmemdup(mptmp, msr->matched_var->value, @@ -923,6 +1058,8 @@ static int var_matched_var_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_matched_var_name_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->matched_var != NULL); return var_simple_generate_ex(var, vartab, mptmp, apr_pmemdup(mptmp, msr->matched_var->name, @@ -935,6 +1072,10 @@ static int var_matched_var_name_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_session_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -965,6 +1106,10 @@ static int var_session_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "SESSION: Memory allocation error"); + return -1; + } rvar->value = str->value; rvar->value_len = str->value_len; @@ -983,6 +1128,10 @@ static int var_session_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -1013,10 +1162,18 @@ static int var_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "USER: Memory allocation error"); + return -1; + } rvar->value = str->value; rvar->value_len = str->value_len; rvar->name = apr_psprintf(mptmp, "USER:%s", log_escape_nq_ex(mptmp, str->name, str->name_len)); + if (!rvar->name) { + msr_log(msr, 1, "USER: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -1031,6 +1188,10 @@ static int var_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_global_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -1079,6 +1240,10 @@ static int var_global_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_resource_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -1109,6 +1274,10 @@ static int var_resource_generate(modsec_rec *msr, msre_var *var, msre_rule *rule /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "RESOURCE: Memory allocation error"); + return -1; + } rvar->value = str->value; rvar->value_len = str->value_len; @@ -1127,6 +1296,10 @@ static int var_resource_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_files_tmp_contents_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); multipart_part **parts = NULL; int i, count = 0; @@ -1224,6 +1397,10 @@ static int var_files_tmp_contents_generate(modsec_rec *msr, msre_var *var, static int var_files_tmpnames_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); multipart_part **parts = NULL; int i, count = 0; @@ -1269,6 +1446,10 @@ static int var_files_tmpnames_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_files_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); multipart_part **parts = NULL; int i, count = 0; @@ -1314,6 +1495,10 @@ static int var_files_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_files_sizes_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); multipart_part **parts = NULL; int i, count = 0; @@ -1359,6 +1544,10 @@ static int var_files_sizes_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_files_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); multipart_part **parts = NULL; int i, count = 0; @@ -1368,6 +1557,10 @@ static int var_files_names_generate(modsec_rec *msr, msre_var *var, msre_rule *r for(i = 0; i < msr->mpd->parts->nelts; i++) { if (parts[i]->type == MULTIPART_FILE) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "FILES_NAMES: Memory allocation error"); + return count; + } rvar->value = parts[i]->name; rvar->value_len = strlen(rvar->value); @@ -1387,6 +1580,9 @@ static int var_files_names_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_files_combined_size_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); multipart_part **parts = NULL; msre_var *rvar = NULL; unsigned int combined_size = 0; @@ -1402,6 +1598,10 @@ static int var_files_combined_size_generate(modsec_rec *msr, msre_var *var, msre } rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "FILES_NAMES: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%u", combined_size); rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -1414,6 +1614,10 @@ static int var_files_combined_size_generate(modsec_rec *msr, msre_var *var, msre static int var_multipart_part_headers_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); multipart_part **parts = NULL; int i, j, count = 0; @@ -1470,6 +1674,7 @@ static int var_modsec_build_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_multipart_filename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->multipart_filename); } @@ -1478,6 +1683,7 @@ static int var_multipart_filename_generate(modsec_rec *msr, msre_var *var, msre_ static int var_multipart_name_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->multipart_name); } @@ -1486,6 +1692,7 @@ static int var_multipart_name_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_multipart_boundary_quoted_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_boundary_quoted != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1498,6 +1705,7 @@ static int var_multipart_boundary_quoted_generate(modsec_rec *msr, msre_var *var static int var_multipart_boundary_whitespace_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_boundary_whitespace != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1510,6 +1718,7 @@ static int var_multipart_boundary_whitespace_generate(modsec_rec *msr, msre_var static int var_multipart_data_after_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_data_after != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1522,6 +1731,7 @@ static int var_multipart_data_after_generate(modsec_rec *msr, msre_var *var, msr static int var_multipart_data_before_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_data_before != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1534,6 +1744,7 @@ static int var_multipart_data_before_generate(modsec_rec *msr, msre_var *var, ms static int var_multipart_header_folding_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_header_folding != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1546,6 +1757,7 @@ static int var_multipart_header_folding_generate(modsec_rec *msr, msre_var *var, static int var_multipart_crlf_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_crlf_line != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1558,6 +1770,7 @@ static int var_multipart_crlf_line_generate(modsec_rec *msr, msre_var *var, msre static int var_multipart_crlf_lf_lines_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_lf_line != 0)&&(msr->mpd->flag_crlf_line != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1570,6 +1783,7 @@ static int var_multipart_crlf_lf_lines_generate(modsec_rec *msr, msre_var *var, static int var_multipart_lf_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_lf_line != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1582,6 +1796,7 @@ static int var_multipart_lf_line_generate(modsec_rec *msr, msre_var *var, msre_r static int var_multipart_missing_semicolon_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_missing_semicolon != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1594,6 +1809,7 @@ static int var_multipart_missing_semicolon_generate(modsec_rec *msr, msre_var *v static int var_multipart_invalid_part_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_invalid_part != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1606,6 +1822,7 @@ static int var_multipart_invalid_part_generate(modsec_rec *msr, msre_var *var, m static int var_multipart_invalid_quoting_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_invalid_quoting != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1618,6 +1835,7 @@ static int var_multipart_invalid_quoting_generate(modsec_rec *msr, msre_var *var static int var_multipart_invalid_header_folding_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_invalid_header_folding != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1630,6 +1848,7 @@ static int var_multipart_invalid_header_folding_generate(modsec_rec *msr, msre_v static int var_multipart_file_limit_exceeded_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_file_limit_exceeded != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1642,6 +1861,7 @@ static int var_multipart_file_limit_exceeded_generate(modsec_rec *msr, msre_var static int var_multipart_strict_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->mpd != NULL) { /* Respond positive if at least one of the multipart flags is raised. */ if ( (msr->mpd->flag_error) @@ -1669,6 +1889,7 @@ static int var_multipart_strict_error_generate(modsec_rec *msr, msre_var *var, m static int var_multipart_unmatched_boundary_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_unmatched_boundary != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1681,6 +1902,7 @@ static int var_multipart_unmatched_boundary_generate(modsec_rec *msr, msre_var * static int var_urlencoded_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->urlencoded_error) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1693,6 +1915,7 @@ static int var_urlencoded_error_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_inbound_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->inbound_error) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1705,6 +1928,7 @@ static int var_inbound_error_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_outbound_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->outbound_error) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1719,6 +1943,8 @@ static apr_time_t calculate_perf_combined(modsec_rec *msr) { } char *format_all_performance_variables(modsec_rec *msr, apr_pool_t *mp) { + assert(msr != NULL); + assert(mp != NULL); return apr_psprintf(mp, "combined=%" APR_TIME_T_FMT ", p1=%" APR_TIME_T_FMT ", p2=%" APR_TIME_T_FMT ", p3=%" APR_TIME_T_FMT ", p4=%" APR_TIME_T_FMT ", p5=%" APR_TIME_T_FMT ", sr=%" APR_TIME_T_FMT ", sw=%" APR_TIME_T_FMT @@ -1731,6 +1957,10 @@ char *format_all_performance_variables(modsec_rec *msr, apr_pool_t *mp) { static int generate_performance_variable(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp, apr_time_t value) { + assert(msr != NULL); + assert(var != NULL); + assert( vartab!= NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); @@ -1747,6 +1977,10 @@ static int generate_performance_variable(modsec_rec *msr, msre_var *var, msre_ru static int var_perf_all_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); @@ -1771,6 +2005,7 @@ static int var_perf_combined_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_perf_gc_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_gc); } @@ -1779,6 +2014,7 @@ static int var_perf_gc_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_perf_phase1_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_phase1); } @@ -1787,6 +2023,7 @@ static int var_perf_phase1_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_perf_phase2_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_phase2); } @@ -1795,6 +2032,7 @@ static int var_perf_phase2_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_perf_phase3_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_phase3); } @@ -1803,6 +2041,7 @@ static int var_perf_phase3_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_perf_phase4_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_phase4); } @@ -1811,6 +2050,7 @@ static int var_perf_phase4_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_perf_phase5_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_phase5); } @@ -1819,6 +2059,7 @@ static int var_perf_phase5_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_perf_sread_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_storage_read); } @@ -1827,6 +2068,7 @@ static int var_perf_sread_generate(modsec_rec *msr, msre_var *var, msre_rule *ru static int var_perf_swrite_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_storage_write); } @@ -1835,6 +2077,7 @@ static int var_perf_swrite_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_perf_logging_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_logging); } @@ -1844,6 +2087,10 @@ static int var_perf_logging_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_perf_rules_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -1887,9 +2134,16 @@ static int var_perf_rules_generate(modsec_rec *msr, msre_var *var, msre_rule *ru static int var_duration_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { - msre_var *rvar = NULL; + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "DURATION: Memory allocation error"); + return -1; + } - rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); rvar->value = apr_psprintf(mptmp, "%" APR_TIME_T_FMT, (apr_time_now() - msr->r->request_time)); rvar->value_len = strlen(rvar->value); @@ -1903,6 +2157,10 @@ static int var_duration_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_time_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -1910,10 +2168,18 @@ static int var_time_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%02d%02d%02d%02d%02d%02d%02d", (tm->tm_year / 100) + 19, (tm->tm_year % 100), tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + if (!rvar->value) { + msr_log(msr, 1, "TIME: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -1925,6 +2191,10 @@ static int var_time_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_time_year_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -1932,9 +2202,17 @@ static int var_time_year_generate(modsec_rec *msr, msre_var *var, msre_rule *rul tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME_YEAR: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%02d%02d", (tm->tm_year / 100) + 19, tm->tm_year % 100); + if (!rvar->value) { + msr_log(msr, 1, "TIME_YEAR: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -1946,6 +2224,10 @@ static int var_time_year_generate(modsec_rec *msr, msre_var *var, msre_rule *rul static int var_time_wday_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -1953,7 +2235,15 @@ static int var_time_wday_generate(modsec_rec *msr, msre_var *var, msre_rule *rul tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME_WDAY: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%d", tm->tm_wday); + if (!rvar->value) { + msr_log(msr, 1, "TIME_WDAY: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -1965,6 +2255,10 @@ static int var_time_wday_generate(modsec_rec *msr, msre_var *var, msre_rule *rul static int var_time_sec_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -1972,7 +2266,15 @@ static int var_time_sec_generate(modsec_rec *msr, msre_var *var, msre_rule *rule tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME_SEC: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_sec); + if (!rvar->value) { + msr_log(msr, 1, "TIME_SEC: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -1984,6 +2286,10 @@ static int var_time_sec_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_time_min_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -1991,7 +2297,15 @@ static int var_time_min_generate(modsec_rec *msr, msre_var *var, msre_rule *rule tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME_MIN: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_min); + if (!rvar->value) { + msr_log(msr, 1, "TIME_MIN: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -2002,6 +2316,10 @@ static int var_time_min_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_time_hour_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -2009,7 +2327,15 @@ static int var_time_hour_generate(modsec_rec *msr, msre_var *var, msre_rule *rul tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME_HOUR: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_hour); + if (!rvar->value) { + msr_log(msr, 1, "TIME_HOUR: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -2021,6 +2347,10 @@ static int var_time_hour_generate(modsec_rec *msr, msre_var *var, msre_rule *rul static int var_time_mon_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -2028,7 +2358,21 @@ static int var_time_mon_generate(modsec_rec *msr, msre_var *var, msre_rule *rule tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + assert(msr != NULL); + assert(msr->r != NULL); + assert(var != NULL); + assert(rule != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); + if (!rvar) { + msr_log(msr, 1, "TIME_MON: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_mon + 1); + if (!rvar->value) { + msr_log(msr, 1, "TIME_MON: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -2040,6 +2384,11 @@ static int var_time_mon_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_time_day_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -2047,7 +2396,15 @@ static int var_time_day_generate(modsec_rec *msr, msre_var *var, msre_rule *rule tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME_DAY: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_mday); + if (!rvar->value) { + msr_log(msr, 1, "TIME_DAY: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -2059,12 +2416,24 @@ static int var_time_day_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_time_epoch_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; time_t tc; tc = time(NULL); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME_EPOCH: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%ld", (long)tc); + if (!rvar->value) { + msr_log(msr, 1, "TIME_EPOCH: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -2076,6 +2445,7 @@ static int var_time_epoch_generate(modsec_rec *msr, msre_var *var, msre_rule *ru static int var_query_string_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->query_string); } @@ -2084,6 +2454,8 @@ static int var_query_string_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_request_basename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); char *value = file_basename(mptmp, msr->r->parsed_uri.path); return var_simple_generate(var, vartab, mptmp, value); } @@ -2155,6 +2527,10 @@ static int var_full_request_generate(modsec_rec *msr, msre_var *var, static int var_full_request_length_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; char *value = NULL; int headers_length = 0; @@ -2173,6 +2549,7 @@ static int var_full_request_length_generate(modsec_rec *msr, msre_var *var, msre static int var_request_body_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->msc_reqbody_buffer != NULL) { return var_simple_generate_ex(var, vartab, mptmp, msr->msc_reqbody_buffer, msr->msc_reqbody_length); @@ -2185,6 +2562,7 @@ static int var_request_body_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_request_body_length_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); char *value = apr_psprintf(mptmp, "%d", msr->msc_reqbody_length); return var_simple_generate(var, vartab, mptmp, value); } @@ -2194,6 +2572,10 @@ static int var_request_body_length_generate(modsec_rec *msr, msre_var *var, msre static int var_matched_vars_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2259,6 +2641,10 @@ static int var_matched_vars_names_generate(modsec_rec *msr, msre_var *var, msre_ static int var_matched_vars_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2324,6 +2710,10 @@ static int var_matched_vars_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_request_cookies_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2348,11 +2738,19 @@ static int var_request_cookies_generate(modsec_rec *msr, msre_var *var, msre_rul /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "REQUEST_COOKIES: Memory allocation error"); + return -1; + } rvar->value = te[i].val; rvar->value_len = strlen(rvar->value); rvar->name = apr_psprintf(mptmp, "REQUEST_COOKIES:%s", log_escape_nq(mptmp, te[i].key)); + if (!rvar->name) { + msr_log(msr, 1, "REQUEST_COOKIES: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -2367,6 +2765,10 @@ static int var_request_cookies_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_request_cookies_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2391,11 +2793,19 @@ static int var_request_cookies_names_generate(modsec_rec *msr, msre_var *var, ms /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "REQUEST_COOKIES_NAMES: Memory allocation error"); + return -1; + } rvar->value = te[i].key; rvar->value_len = strlen(rvar->value); rvar->name = apr_psprintf(mptmp, "REQUEST_COOKIES_NAMES:%s", log_escape_nq(mptmp, te[i].key)); + if (!rvar->name) { + msr_log(msr, 1, "REQUEST_COOKIES_NAMES: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -2410,6 +2820,10 @@ static int var_request_cookies_names_generate(modsec_rec *msr, msre_var *var, ms static int var_request_headers_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2434,11 +2848,19 @@ static int var_request_headers_generate(modsec_rec *msr, msre_var *var, msre_rul /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "REQUEST_HEADERS: Memory allocation error"); + return -1; + } rvar->value = te[i].val; rvar->value_len = strlen(rvar->value); rvar->name = apr_psprintf(mptmp, "REQUEST_HEADERS:%s", log_escape_nq(mptmp, te[i].key)); + if (!rvar->name) { + msr_log(msr, 1, "REQUEST_HEADERS: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -2453,6 +2875,10 @@ static int var_request_headers_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_request_headers_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2477,11 +2903,19 @@ static int var_request_headers_names_generate(modsec_rec *msr, msre_var *var, ms /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "REQUEST_HEADERS_NAMES: Memory allocation error"); + return -1; + } rvar->value = te[i].key; rvar->value_len = strlen(rvar->value); rvar->name = apr_psprintf(mptmp, "REQUEST_HEADERS_NAMES:%s", log_escape_nq(mptmp, te[i].key)); + if (!rvar->name) { + msr_log(msr, 1, "REQUEST_HEADERS_NAMES: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -2496,6 +2930,7 @@ static int var_request_headers_names_generate(modsec_rec *msr, msre_var *var, ms static int var_request_filename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->r->parsed_uri.path); } @@ -2504,6 +2939,7 @@ static int var_request_filename_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_request_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->request_line); } @@ -2512,6 +2948,7 @@ static int var_request_line_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_request_method_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->request_method); } @@ -2520,6 +2957,7 @@ static int var_request_method_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_request_protocol_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->request_protocol); } @@ -2528,6 +2966,7 @@ static int var_request_protocol_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_server_addr_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->local_addr); } @@ -2536,6 +2975,7 @@ static int var_server_addr_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_server_name_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->hostname); } @@ -2544,7 +2984,12 @@ static int var_server_name_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_server_port_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); char *value = apr_psprintf(mptmp, "%u", msr->local_port); + if (!value) { + msr_log(msr, 1, "SERVER_PORT: Memory allocation error"); + return -1; + } return var_simple_generate(var, vartab, mptmp, value); } @@ -2553,6 +2998,8 @@ static int var_server_port_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_script_basename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); char *value = file_basename(mptmp, msr->r->filename); return var_simple_generate(var, vartab, mptmp, value); } @@ -2562,6 +3009,8 @@ static int var_script_basename_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_script_filename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); char *value = msr->r->filename; return var_simple_generate(var, vartab, mptmp, value); } @@ -2571,7 +3020,13 @@ static int var_script_filename_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_script_gid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); char *value = apr_psprintf(mptmp, "%ld", (long)msr->r->finfo.group); + if (!value) { + msr_log(msr, 1, "SCRIPT_GID: Memory allocation error"); + return -1; + } return var_simple_generate(var, vartab, mptmp, value); } @@ -2580,6 +3035,9 @@ static int var_script_gid_generate(modsec_rec *msr, msre_var *var, msre_rule *ru static int var_script_groupname_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); + assert(mptmp != NULL); char *value = NULL; if (apr_gid_name_get(&value, msr->r->finfo.group, mptmp) == APR_SUCCESS) { return var_simple_generate(var, vartab, mptmp, value); @@ -2592,6 +3050,9 @@ static int var_script_groupname_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_script_mode_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); + assert(mptmp != NULL); char *value = apr_psprintf(mptmp, "%04x", msr->r->finfo.protection); return var_simple_generate(var, vartab, mptmp, value); } @@ -2601,6 +3062,9 @@ static int var_script_mode_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_script_uid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); + assert(mptmp != NULL); char *value = apr_psprintf(mptmp, "%ld", (long)msr->r->finfo.user); return var_simple_generate(var, vartab, mptmp, value); } @@ -2610,6 +3074,9 @@ static int var_script_uid_generate(modsec_rec *msr, msre_var *var, msre_rule *ru static int var_script_username_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); + assert(mptmp != NULL); char *value = NULL; if (apr_uid_name_get(&value, msr->r->finfo.user, mptmp) == APR_SUCCESS) { return var_simple_generate(var, vartab, mptmp, value); @@ -2622,6 +3089,7 @@ static int var_script_username_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_auth_type_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); char *value = msr->r->ap_auth_type; return var_simple_generate(var, vartab, mptmp, value); } @@ -2631,6 +3099,7 @@ static int var_auth_type_generate(modsec_rec *msr, msre_var *var, msre_rule *rul static int var_path_info_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); const char *value = msr->r->path_info; return var_simple_generate(var, vartab, mptmp, value); } @@ -2640,6 +3109,7 @@ static int var_path_info_generate(modsec_rec *msr, msre_var *var, msre_rule *rul static int var_stream_output_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->stream_output_data != NULL) { return var_simple_generate_ex(var, vartab, mptmp, msr->stream_output_data, msr->stream_output_length); @@ -2653,6 +3123,7 @@ static int var_stream_output_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_stream_input_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->stream_input_data != NULL) { return var_simple_generate_ex(var, vartab, mptmp, msr->stream_input_data, msr->stream_input_length); @@ -2666,6 +3137,7 @@ static int var_stream_input_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_response_body_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->resbody_data != NULL) { return var_simple_generate_ex(var, vartab, mptmp, msr->resbody_data, msr->resbody_length); @@ -2679,6 +3151,10 @@ static int var_response_body_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_response_headers_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2705,11 +3181,19 @@ static int var_response_headers_generate(modsec_rec *msr, msre_var *var, msre_ru /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "RESPONSE_HEADERS: Memory allocation error"); + return -1; + } rvar->value = te[i].val; rvar->value_len = strlen(rvar->value); rvar->name = apr_psprintf(mptmp, "RESPONSE_HEADERS:%s", log_escape_nq(mptmp, te[i].key)); + if (!rvar->name) { + msr_log(msr, 1, "RESPONSE_HEADERS: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -2724,6 +3208,10 @@ static int var_response_headers_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_response_headers_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2748,11 +3236,19 @@ static int var_response_headers_names_generate(modsec_rec *msr, msre_var *var, m /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "RESPONSE_HEADERS_NAMES: Memory allocation error"); + return -1; + } rvar->value = te[i].key; rvar->value_len = strlen(rvar->value); rvar->name = apr_psprintf(mptmp, "RESPONSE_HEADERS_NAMES:%s", log_escape_nq(mptmp, te[i].key)); + if (!rvar) { + msr_log(msr, 1, "RESPONSE_HEADERS_NAMES: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -2767,6 +3263,7 @@ static int var_response_headers_names_generate(modsec_rec *msr, msre_var *var, m static int var_status_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); const char *value = msr->status_line; return var_simple_generate(var, vartab, mptmp, value); } @@ -2776,6 +3273,7 @@ static int var_status_line_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_response_protocol_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); const char *value = msr->response_protocol; return var_simple_generate(var, vartab, mptmp, value); } @@ -2785,6 +3283,7 @@ static int var_response_protocol_generate(modsec_rec *msr, msre_var *var, msre_r static int var_response_status_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); const char *value = apr_psprintf(mptmp, "%u", msr->response_status); return var_simple_generate(var, vartab, mptmp, value); } @@ -2794,6 +3293,8 @@ static int var_response_status_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_response_content_type(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); return var_simple_generate(var, vartab, mptmp, msr->r->content_type); } @@ -2802,6 +3303,8 @@ static int var_response_content_type(modsec_rec *msr, msre_var *var, msre_rule * static int var_response_content_length(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); const char *value = apr_psprintf(mptmp, "%" APR_OFF_T_FMT, msr->r->clength); return var_simple_generate(var, vartab, mptmp, value); } @@ -2811,6 +3314,7 @@ static int var_response_content_length(modsec_rec *msr, msre_var *var, msre_rule static int var_userid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); const char *value = msr->userid; return var_simple_generate(var, vartab, mptmp, value); } @@ -2820,6 +3324,7 @@ static int var_userid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_sessionid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); const char *value = msr->sessionid; return var_simple_generate(var, vartab, mptmp, value); } @@ -2829,6 +3334,8 @@ static int var_sessionid_generate(modsec_rec *msr, msre_var *var, msre_rule *rul static int var_webappid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->txcfg != NULL); const char *value = msr->txcfg->webappid; return var_simple_generate(var, vartab, mptmp, value); } diff --git a/configure.ac b/configure.ac index aac9d52dbc..c75335c14d 100644 --- a/configure.ac +++ b/configure.ac @@ -305,6 +305,22 @@ if test "$build_docs" -eq 1; then fi +# Add assert() usage + +AC_ARG_ENABLE(assertions, + AS_HELP_STRING([--enable-assertions], + [Turn on assertions checks (undefine NDEBUG)]), +[ + if test "${enableval}" = "yes"; then + assertions='-UNDEBUG' + else + assertions='-DNDEBUG' + fi +], +[ + assertions='-DNDEBUG' +]) + # Add PCRE Studying AC_ARG_ENABLE(pcre-study, @@ -828,7 +844,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_context $collection_global_lock $large_stream_input" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_context $collection_global_lock $large_stream_input $assertions" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" @@ -905,7 +921,7 @@ AC_LINK_IFELSE( CFLAGS="$ORIG_CFLAGS" CPPFLAGS="$ORIG_CPPFLAGS" -# Current our unique download backend is curl, furhter we can support more. +# Currently our unique download backend is curl, further we can support more. if test ! -z "${CURL_VERSION}"; then AC_DEFINE([WITH_REMOTE_RULES], [1], [Enables SecRemoteRules support]) MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS -DWITH_REMOTE_RULES" diff --git a/design.md b/design.md new file mode 100644 index 0000000000..a8e56e128e --- /dev/null +++ b/design.md @@ -0,0 +1,29 @@ +Design notes for source code +== +This file give some explanations and guidelines regarding ModSecurity v2 source code. +The goal is to discuss topics that are not related to a specific location in the code, so that cannot be best explained by comments. +The goal is not to replace comments where it is probably better. +It's quite short for the moment, but the goal is to extend it from time to time. + +## Null pointer check +The default behaviour is to check for null pointer dereference everywhere it may be needed. +In case a pointer cannot be null, it has to be explained with a comment at the beginning of the function of when dereferencing the pointer. +On top of that, an explicit check should be done when compiling in debug mode with the following code: +``` + assert(mypointer); +``` +In case a pointer that cannot be null is used at several locations (say more than 3 times), +the explanation could be given globally in this file. + +### Pointers never null +The following pointers can never be null: + +#### msr + +msr is assigned at the following places: +- mod_security2.c (14 x): initialization +In all the above calls, and all calling functions, it immediately returns (with an error code) in case msr is null, up to a place where no mod_security2 processing at all occurs. +In subsequent calls, there's thus no possibility to have msr null. +- apache2_io.c (2 x): assign a previously initialized msr +- msc_json (9 x): assign a previously initialized msr +- msc_lua.c (4 x): assign a previously initialized msr