MODSEC-270

This commit is contained in:
brenosilva
2011-10-10 16:30:30 +00:00
parent a4f0957b0c
commit c99d14797a

View File

@@ -128,12 +128,14 @@ char *update_rule_target(cmd_parms *cmd, directory_config *dcfg,
targets = (msre_var **)rule->targets->elts; targets = (msre_var **)rule->targets->elts;
// TODO need a good way to remove the element from array, maybe change array by tables or rings // TODO need a good way to remove the element from array, maybe change array by tables or rings
for (i = 0; i < rule->targets->nelts; i++) { for (i = 0; i < rule->targets->nelts; i++) {
if((strncasecmp(targets[i]->name,name,name_len) == 0) && if((strlen(targets[i]->name) == strlen(name)) &&
(strncasecmp(targets[i]->name,name,strlen(targets[i]->name)) == 0) &&
(targets[i]->is_negated == is_negated) && (targets[i]->is_negated == is_negated) &&
(targets[i]->is_counting == is_counting)) { (targets[i]->is_counting == is_counting)) {
if(value != NULL && targets[i]->param != NULL) { if(value != NULL && targets[i]->param != NULL) {
if(strncasecmp(targets[i]->param,value,value_len) == 0) { if((strlen(targets[i]->param) == strlen(value)) &&
strncasecmp(targets[i]->param,value,strlen(targets[i]->param)) == 0) {
memset(targets[i]->name,0,strlen(targets[i]->name)); memset(targets[i]->name,0,strlen(targets[i]->name));
memset(targets[i]->param,0,strlen(targets[i]->param)); memset(targets[i]->param,0,strlen(targets[i]->param));
match = 1; match = 1;
@@ -196,37 +198,45 @@ char *update_rule_target(cmd_parms *cmd, directory_config *dcfg,
} else { } else {
name = param; name = param;
} }
name_len = strlen(name); name_len = strlen(name);
if(value != NULL) if(value != NULL)
value_len = strlen(value); value_len = strlen(value);
match = 0;
targets = (msre_var **)rule->targets->elts; targets = (msre_var **)rule->targets->elts;
for (i = 0; i < rule->targets->nelts; i++) { for (i = 0; i < rule->targets->nelts; i++) {
if((strncasecmp(targets[i]->name,name,name_len) == 0) && if((strlen(targets[i]->name) == strlen(name)) &&
(strncasecmp(targets[i]->name,name,strlen(targets[i]->name)) == 0) &&
(targets[i]->is_negated == is_negated) && (targets[i]->is_negated == is_negated) &&
(targets[i]->is_counting == is_counting)) { (targets[i]->is_counting == is_counting)) {
if(value != NULL && targets[i]->param != NULL) { if(value != NULL && targets[i]->param != NULL) {
if(strncasecmp(targets[i]->param,value,value_len) == 0) { if((strlen(targets[i]->param) == strlen(value)) &&
goto end; strncasecmp(targets[i]->param,value,strlen(targets[i]->param)) == 0) {
match = 1;
} }
} else if (value == NULL && targets[i]->param == NULL){ } else if (value == NULL && targets[i]->param == NULL){
goto end; match = 1;
} else } else
continue; continue;
} }
} }
if(target != NULL) { if(target != NULL) {
free(target); free(target);
target = NULL; target = NULL;
} }
rc = msre_parse_targets(ruleset, p, rule->targets, &my_error_msg); if(match == 0 ) {
if (rc < 0) { rc = msre_parse_targets(ruleset, p, rule->targets, &my_error_msg);
goto end; if (rc < 0) {
goto end;
}
} }
} }
@@ -281,13 +291,13 @@ static char *msre_generate_target_string(apr_pool_t *pool, msre_rule *rule) {
for (i = 0; i < rule->targets->nelts; i++) { for (i = 0; i < rule->targets->nelts; i++) {
if(targets[i]->name != NULL && strlen(targets[i]->name) > 0) { if(targets[i]->name != NULL && strlen(targets[i]->name) > 0) {
target_str = apr_pstrcat(pool, target_str = apr_pstrcat(pool,
(target_str == NULL) ? "" : apr_psprintf(pool, "%s|", target_str), (target_str == NULL) ? "" : apr_psprintf(pool, "%s|", target_str),
(targets[i]->is_negated == 0) ? "" : "!", (targets[i]->is_negated == 0) ? "" : "!",
(targets[i]->is_counting == 0) ? "" : "&", (targets[i]->is_counting == 0) ? "" : "&",
(targets[i]->name == NULL) ? "" : targets[i]->name, (targets[i]->name == NULL) ? "" : targets[i]->name,
(targets[i]->param == NULL) ? "" : apr_psprintf(pool, ":%s", targets[i]->param), (targets[i]->param == NULL) ? "" : apr_psprintf(pool, ":%s", targets[i]->param),
NULL); NULL);
} }
} }
@@ -319,14 +329,14 @@ static char *msre_actionset_generate_action_string(apr_pool_t *pool, const msre_
if (chain) { if (chain) {
/* Skip some actions that are not used in a chain. */ /* Skip some actions that are not used in a chain. */
if ( (action->metadata->type == ACTION_DISRUPTIVE) if ( (action->metadata->type == ACTION_DISRUPTIVE)
|| (action->metadata->type == ACTION_METADATA) || (action->metadata->type == ACTION_METADATA)
|| (strcmp("log", action->metadata->name) == 0) || (strcmp("log", action->metadata->name) == 0)
|| (strcmp("auditlog", action->metadata->name) == 0) || (strcmp("auditlog", action->metadata->name) == 0)
|| (strcmp("nolog", action->metadata->name) == 0) || (strcmp("nolog", action->metadata->name) == 0)
|| (strcmp("noauditlog", action->metadata->name) == 0) || (strcmp("noauditlog", action->metadata->name) == 0)
|| (strcmp("severity", action->metadata->name) == 0) || (strcmp("severity", action->metadata->name) == 0)
|| (strcmp("tag", action->metadata->name) == 0) || (strcmp("tag", action->metadata->name) == 0)
|| (strcmp("phase", action->metadata->name) == 0)) || (strcmp("phase", action->metadata->name) == 0))
{ {
continue; continue;
} }
@@ -345,14 +355,14 @@ static char *msre_actionset_generate_action_string(apr_pool_t *pool, const msre_
} }
actions = apr_pstrcat(pool, actions = apr_pstrcat(pool,
(actions == NULL) ? "" : actions, (actions == NULL) ? "" : actions,
(actions == NULL) ? "" : ",", (actions == NULL) ? "" : ",",
action->metadata->name, action->metadata->name,
(action->param == NULL) ? "" : ":", (action->param == NULL) ? "" : ":",
(use_quotes) ? "'" : "", (use_quotes) ? "'" : "",
(action->param == NULL) ? "" : action->param, (action->param == NULL) ? "" : action->param,
(use_quotes) ? "'" : "", (use_quotes) ? "'" : "",
NULL); NULL);
} }
return actions; return actions;
@@ -396,7 +406,7 @@ static void msre_actionset_action_add(msre_actionset *actionset, msre_action *ac
* given text string and places them into the supplied table. * given text string and places them into the supplied table.
*/ */
static apr_status_t msre_parse_targets(msre_ruleset *ruleset, const char *text, static apr_status_t msre_parse_targets(msre_ruleset *ruleset, const char *text,
apr_array_header_t *arr, char **error_msg) apr_array_header_t *arr, char **error_msg)
{ {
const apr_array_header_t *tarr; const apr_array_header_t *tarr;
const apr_table_entry_t *telts; const apr_table_entry_t *telts;
@@ -432,7 +442,7 @@ static apr_status_t msre_parse_targets(msre_ruleset *ruleset, const char *text,
* them into the supplied array. * them into the supplied array.
*/ */
static apr_status_t msre_parse_actions(msre_engine *engine, msre_actionset *actionset, static apr_status_t msre_parse_actions(msre_engine *engine, msre_actionset *actionset,
const char *text, char **error_msg) const char *text, char **error_msg)
{ {
const apr_array_header_t *tarr; const apr_array_header_t *tarr;
const apr_table_entry_t *telts; const apr_table_entry_t *telts;
@@ -592,7 +602,7 @@ static msre_var *msre_create_var(msre_ruleset *ruleset, const char *name, const
* Creates a new action instance given its name and an (optional) parameter. * Creates a new action instance given its name and an (optional) parameter.
*/ */
msre_action *msre_create_action(msre_engine *engine, const char *name, const char *param, msre_action *msre_create_action(msre_engine *engine, const char *name, const char *param,
char **error_msg) char **error_msg)
{ {
msre_action *action = apr_pcalloc(engine->mp, sizeof(msre_action)); msre_action *action = apr_pcalloc(engine->mp, sizeof(msre_action));
if (action == NULL) return NULL; if (action == NULL) return NULL;
@@ -610,7 +620,7 @@ msre_action *msre_create_action(msre_engine *engine, const char *name, const cha
if (param == NULL) { /* Parameter not present */ if (param == NULL) { /* Parameter not present */
if (action->metadata->argc_min > 0) { if (action->metadata->argc_min > 0) {
*error_msg = apr_psprintf(engine->mp, "Missing mandatory parameter for action %s", *error_msg = apr_psprintf(engine->mp, "Missing mandatory parameter for action %s",
name); name);
return NULL; return NULL;
} }
} else { /* Parameter present */ } else { /* Parameter present */
@@ -625,7 +635,7 @@ msre_action *msre_create_action(msre_engine *engine, const char *name, const cha
if ((param[0] == '+')||(param[0] == '-')) { if ((param[0] == '+')||(param[0] == '-')) {
if (action->metadata->allow_param_plusminus == 0) { if (action->metadata->allow_param_plusminus == 0) {
*error_msg = apr_psprintf(engine->mp, *error_msg = apr_psprintf(engine->mp,
"Action %s does not allow +/- modificators.", name); "Action %s does not allow +/- modificators.", name);
return NULL; return NULL;
} }
else { /* Modificators allowed. */ else { /* Modificators allowed. */
@@ -633,10 +643,10 @@ msre_action *msre_create_action(msre_engine *engine, const char *name, const cha
action->param = param + 1; action->param = param + 1;
action->param_plusminus = POSITIVE_VALUE; action->param_plusminus = POSITIVE_VALUE;
} else } else
if (param[0] == '-') { if (param[0] == '-') {
action->param = param + 1; action->param = param + 1;
action->param_plusminus = NEGATIVE_VALUE; action->param_plusminus = NEGATIVE_VALUE;
} }
} }
} else { } else {
action->param = param; action->param = param;
@@ -658,7 +668,7 @@ msre_action *msre_create_action(msre_engine *engine, const char *name, const cha
* them into the given table. * them into the given table.
*/ */
int msre_parse_generic(apr_pool_t *mp, const char *text, apr_table_t *vartable, int msre_parse_generic(apr_pool_t *mp, const char *text, apr_table_t *vartable,
char **error_msg) char **error_msg)
{ {
char *p = (char *)text; char *p = (char *)text;
int count = 0; int count = 0;
@@ -701,7 +711,7 @@ int msre_parse_generic(apr_pool_t *mp, const char *text, apr_table_t *vartable,
} }
*error_msg = apr_psprintf(mp, "Unexpected character at position %d: %s", *error_msg = apr_psprintf(mp, "Unexpected character at position %d: %s",
(int)(p - text), text); (int)(p - text), text);
return -1; return -1;
} }
@@ -736,28 +746,28 @@ int msre_parse_generic(apr_pool_t *mp, const char *text, apr_table_t *vartable,
for(;;) { for(;;) {
if (*p == '\0') { if (*p == '\0') {
*error_msg = apr_psprintf(mp, "Missing closing quote at position %d: %s", *error_msg = apr_psprintf(mp, "Missing closing quote at position %d: %s",
(int)(p - text), text); (int)(p - text), text);
free(value); free(value);
return -1; return -1;
} else } else
if (*p == '\\') { if (*p == '\\') {
if ( (*(p + 1) == '\0') || ((*(p + 1) != '\'')&&(*(p + 1) != '\\')) ) { if ( (*(p + 1) == '\0') || ((*(p + 1) != '\'')&&(*(p + 1) != '\\')) ) {
*error_msg = apr_psprintf(mp, "Invalid quoted pair at position %d: %s", *error_msg = apr_psprintf(mp, "Invalid quoted pair at position %d: %s",
(int)(p - text), text); (int)(p - text), text);
free(value); free(value);
return -1; return -1;
} }
p++; p++;
*(d++) = *(p++); *(d++) = *(p++);
} else } else
if (*p == '\'') { if (*p == '\'') {
*d = '\0'; *d = '\0';
p++; p++;
break; break;
} }
else { else {
*(d++) = *(p++); *(d++) = *(p++);
} }
} }
d = value; d = value;
@@ -788,10 +798,10 @@ int msre_parse_generic(apr_pool_t *mp, const char *text, apr_table_t *vartable,
* parsing the given string which contains a list of actions. * parsing the given string which contains a list of actions.
*/ */
msre_actionset *msre_actionset_create(msre_engine *engine, const char *text, msre_actionset *msre_actionset_create(msre_engine *engine, const char *text,
char **error_msg) char **error_msg)
{ {
msre_actionset *actionset = (msre_actionset *)apr_pcalloc(engine->mp, msre_actionset *actionset = (msre_actionset *)apr_pcalloc(engine->mp,
sizeof(msre_actionset)); sizeof(msre_actionset));
if (actionset == NULL) return NULL; if (actionset == NULL) return NULL;
actionset->actions = apr_table_make(engine->mp, 25); actionset->actions = apr_table_make(engine->mp, 25);
@@ -854,7 +864,7 @@ static msre_actionset *msre_actionset_copy(apr_pool_t *mp, msre_actionset *orig)
* Merges two actionsets into one. * Merges two actionsets into one.
*/ */
msre_actionset *msre_actionset_merge(msre_engine *engine, msre_actionset *parent, msre_actionset *msre_actionset_merge(msre_engine *engine, msre_actionset *parent,
msre_actionset *child, int inherit_by_default) msre_actionset *child, int inherit_by_default)
{ {
msre_actionset *merged = NULL; msre_actionset *merged = NULL;
const apr_array_header_t *tarr; const apr_array_header_t *tarr;
@@ -927,8 +937,8 @@ msre_actionset *msre_actionset_merge(msre_engine *engine, msre_actionset *parent
msre_actionset *msre_actionset_create_default(msre_engine *engine) { msre_actionset *msre_actionset_create_default(msre_engine *engine) {
char *my_error_msg = NULL; char *my_error_msg = NULL;
return msre_actionset_create(engine, return msre_actionset_create(engine,
"phase:2,log,auditlog,pass", "phase:2,log,auditlog,pass",
&my_error_msg); &my_error_msg);
} }
/** /**
@@ -1062,10 +1072,10 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr)
if (rule->placeholder == RULE_PH_MARKER) continue; if (rule->placeholder == RULE_PH_MARKER) continue;
msr_log(msr, 1, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"]: %u usec", rule, msr_log(msr, 1, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"]: %u usec", rule,
((rule->actionset != NULL)&&(rule->actionset->id != NULL)) ? rule->actionset->id : "-", ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) ? rule->actionset->id : "-",
rule->filename != NULL ? rule->filename : "-", rule->filename != NULL ? rule->filename : "-",
rule->line_num, rule->line_num,
(rule->execution_time / PERFORMANCE_MEASUREMENT_LOOP)); (rule->execution_time / PERFORMANCE_MEASUREMENT_LOOP));
} }
return rc; return rc;
@@ -1073,151 +1083,151 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr)
static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_rec *msr) { static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_rec *msr) {
#else #else
apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr) { apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr) {
#endif #endif
apr_array_header_t *arr = NULL; apr_array_header_t *arr = NULL;
msre_rule **rules; msre_rule **rules;
apr_status_t rc; apr_status_t rc;
const char *skip_after = NULL; const char *skip_after = NULL;
msre_rule *last_rule = NULL; msre_rule *last_rule = NULL;
msre_rule *rule_starter = NULL; msre_rule *rule_starter = NULL;
int i, mode, skip, skipped, saw_starter; int i, mode, skip, skipped, saw_starter;
/* First determine which set of rules we need to use. */ /* First determine which set of rules we need to use. */
switch (msr->phase) { switch (msr->phase) {
case PHASE_REQUEST_HEADERS : case PHASE_REQUEST_HEADERS :
arr = ruleset->phase_request_headers; arr = ruleset->phase_request_headers;
break; break;
case PHASE_REQUEST_BODY : case PHASE_REQUEST_BODY :
arr = ruleset->phase_request_body; arr = ruleset->phase_request_body;
break; break;
case PHASE_RESPONSE_HEADERS : case PHASE_RESPONSE_HEADERS :
arr = ruleset->phase_response_headers; arr = ruleset->phase_response_headers;
break; break;
case PHASE_RESPONSE_BODY : case PHASE_RESPONSE_BODY :
arr = ruleset->phase_response_body; arr = ruleset->phase_response_body;
break; break;
case PHASE_LOGGING : case PHASE_LOGGING :
arr = ruleset->phase_logging; arr = ruleset->phase_logging;
break; break;
default : default :
msr_log(msr, 1, "Internal Error: Invalid phase %d", msr->phase); msr_log(msr, 1, "Internal Error: Invalid phase %d", msr->phase);
return -1; return -1;
} }
if (msr->txcfg->debuglog_level >= 9) { if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "This phase consists of %d rule(s).", arr->nelts); msr_log(msr, 9, "This phase consists of %d rule(s).", arr->nelts);
} }
apr_table_clear(msr->matched_vars); apr_table_clear(msr->matched_vars);
/* Loop through the rules in the selected set. */ /* Loop through the rules in the selected set. */
skip = 0; skip = 0;
skipped = 0; skipped = 0;
saw_starter = 0; saw_starter = 0;
mode = NEXT_RULE; mode = NEXT_RULE;
rules = (msre_rule **)arr->elts; rules = (msre_rule **)arr->elts;
for (i = 0; i < arr->nelts; i++) { for (i = 0; i < arr->nelts; i++) {
msre_rule *rule = rules[i]; msre_rule *rule = rules[i];
#if defined(PERFORMANCE_MEASUREMENT) #if defined(PERFORMANCE_MEASUREMENT)
apr_time_t time1 = 0; apr_time_t time1 = 0;
#endif #endif
/* Reset the rule interception flag */ /* Reset the rule interception flag */
msr->rule_was_intercepted = 0; msr->rule_was_intercepted = 0;
/* SKIP_RULES is used to skip all rules until we hit a placeholder /* SKIP_RULES is used to skip all rules until we hit a placeholder
* with the specified rule ID and then resume execution after that. * with the specified rule ID and then resume execution after that.
*/ */
if (mode == SKIP_RULES) { if (mode == SKIP_RULES) {
/* Go to the next rule if we have not yet hit the skip_after ID */ /* Go to the next rule if we have not yet hit the skip_after ID */
if ((rule->placeholder == RULE_PH_NONE) || (rule->actionset->id == NULL) || (strcmp(skip_after, rule->actionset->id) != 0)) { if ((rule->placeholder == RULE_PH_NONE) || (rule->actionset->id == NULL) || (strcmp(skip_after, rule->actionset->id) != 0)) {
if(i-1 >=0) if(i-1 >=0)
last_rule = rules[i-1]; last_rule = rules[i-1];
else else
last_rule = rules[0]; last_rule = rules[0];
if((last_rule != NULL) && (last_rule->actionset != NULL) && last_rule->actionset->is_chained && (saw_starter == 1)) { if((last_rule != NULL) && (last_rule->actionset != NULL) && last_rule->actionset->is_chained && (saw_starter == 1)) {
mode = NEXT_RULE; mode = NEXT_RULE;
skipped = 1; skipped = 1;
--i; --i;
} else { } else {
mode = SKIP_RULES; mode = SKIP_RULES;
skipped = 0; skipped = 0;
saw_starter = 0; 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);
}
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);
} }
continue;
} }
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Found rule %pp id=\"%s\".", rule, skip_after);
}
/* Go to the rule *after* this one to continue execution. */
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Continuing execution after rule id=\"%s\".", skip_after);
}
saw_starter = 0;
skipped = 0;
skip_after = NULL;
mode = NEXT_RULE;
apr_table_clear(msr->matched_vars);
continue; continue;
} }
if (msr->txcfg->debuglog_level >= 9) { /* Skip any rule marked as a placeholder */
msr_log(msr, 9, "Found rule %pp id=\"%s\".", rule, skip_after); if (rule->placeholder != RULE_PH_NONE) {
continue;
} }
/* Go to the rule *after* this one to continue execution. */ /* NEXT_CHAIN is used when one of the rules in a chain
if (msr->txcfg->debuglog_level >= 4) { * fails to match and then we need to skip the remaining
msr_log(msr, 4, "Continuing execution after rule id=\"%s\".", skip_after); * rules in that chain in order to get to the next
} * rule that can execute.
saw_starter = 0;
skipped = 0;
skip_after = NULL;
mode = NEXT_RULE;
apr_table_clear(msr->matched_vars);
continue;
}
/* Skip any rule marked as a placeholder */
if (rule->placeholder != RULE_PH_NONE) {
continue;
}
/* NEXT_CHAIN is used when one of the rules in a chain
* fails to match and then we need to skip the remaining
* rules in that chain in order to get to the next
* rule that can execute.
*/
if (mode == NEXT_CHAIN) {
if (rule->actionset->is_chained == 0) {
mode = NEXT_RULE;
}
/* Go to the next rule. */
apr_table_clear(msr->matched_vars);
continue;
}
/* If we are here that means the mode is NEXT_RULE, which
* then means we have done processing any chains. However,
* if the "skip" parameter is set we need to skip over.
*/
if ((mode == NEXT_RULE)&&(skip > 0)) {
/* Decrement the skip counter by one. */
skip--;
/* If the current rule is part of a chain then
* we need to skip over the entire chain. Thus
* we change the mode to NEXT_CHAIN. The skip
* counter will not decrement as we are moving
* over the rules belonging to the chain.
*/ */
if (rule->actionset->is_chained) { if (mode == NEXT_CHAIN) {
mode = NEXT_CHAIN; if (rule->actionset->is_chained == 0) {
mode = NEXT_RULE;
}
/* Go to the next rule. */
apr_table_clear(msr->matched_vars);
continue;
} }
/* Go to the next rule. */ /* If we are here that means the mode is NEXT_RULE, which
apr_table_clear(msr->matched_vars); * then means we have done processing any chains. However,
continue; * if the "skip" parameter is set we need to skip over.
} */
if ((mode == NEXT_RULE)&&(skip > 0)) {
/* Decrement the skip counter by one. */
skip--;
/* Check if this rule was removed at runtime */ /* If the current rule is part of a chain then
* we need to skip over the entire chain. Thus
* we change the mode to NEXT_CHAIN. The skip
* counter will not decrement as we are moving
* over the rules belonging to the chain.
*/
if (rule->actionset->is_chained) {
mode = NEXT_CHAIN;
}
/* Go to the next rule. */
apr_table_clear(msr->matched_vars);
continue;
}
/* Check if this rule was removed at runtime */
if (((rule->actionset->id !=NULL) && !apr_is_empty_array(msr->removed_rules)) || (apr_is_empty_array(msr->removed_rules_tag)==0)) { if (((rule->actionset->id !=NULL) && !apr_is_empty_array(msr->removed_rules)) || (apr_is_empty_array(msr->removed_rules_tag)==0)) {
int j, act; int j, act;
int do_process = 1; int do_process = 1;