Skip to content

Commit b9ee899

Browse files
Сарайкин Антон ЮрьевичСарайкин Антон Юрьевич
Сарайкин Антон Юрьевич
authored and
Сарайкин Антон Юрьевич
committed
Merge pull request owasp-modsecurity#15 in SECURITYGW/ngx_http_modsecurity from feature/SECURITYGW-708-response-custom-error_page to develop
* commit '1759337c69ea63bfd38adff0b4326f863bc5acf9': Added workaround for correct working ModSecurity with custom error page
2 parents 4338d62 + 1759337 commit b9ee899

5 files changed

+216
-23
lines changed

src/ngx_http_modsecurity_common.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ typedef struct {
5555
ngx_chain_t* temp_chain;
5656
ngx_chain_t* current_chain;
5757
unsigned response_body_filtered:1;
58-
unsigned logged:1;
5958
} ngx_http_modsecurity_ctx_t;
6059

6160

@@ -66,6 +65,8 @@ typedef struct {
6665
ngx_flag_t sanity_checks_enabled;
6766

6867
Rules *rules_set;
68+
69+
Rules *rules_backup;
6970
} ngx_http_modsecurity_conf_t;
7071

7172

@@ -86,6 +87,10 @@ ngx_http_modsecurity_ctx_t *ngx_http_modsecurity_create_ctx(ngx_http_request_t *
8687
char *ngx_str_to_char(ngx_str_t a, ngx_pool_t *p);
8788
ngx_pool_t *ngx_http_modsecurity_pcre_malloc_init(ngx_pool_t *pool);
8889
void ngx_http_modsecurity_pcre_malloc_done(ngx_pool_t *old_pool);
90+
ngx_http_variable_t *ngx_http_get_variable_by_name(ngx_http_request_t *r, ngx_str_t *name);
91+
ngx_int_t ngx_http_get_intervention_status(ngx_http_request_t *r);
92+
ngx_int_t ngx_http_set_intervention_status_done(ngx_http_request_t *r);
93+
void ngx_http_restore_ruleset_from_variable(ngx_http_request_t *r, ngx_http_modsecurity_conf_t *cf);
8994

9095
/* ngx_http_modsecurity_body_filter.c */
9196
ngx_int_t ngx_http_modsecurity_body_filter_init(void);

src/ngx_http_modsecurity_log.c

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,24 @@ ngx_http_modsecurity_log_handler(ngx_http_request_t *r)
4444
dd("catching a new _log_ phase handler");
4545

4646
cf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity_module);
47-
if (cf == NULL || cf->enable != 1)
48-
{
49-
dd("ModSecurity not enabled... returning");
47+
if (cf == NULL) {
48+
dd("Something bad happened... returning");
5049
return NGX_OK;
5150
}
5251

52+
if (cf->enable != 1) {
53+
if (!ngx_http_get_intervention_status(r)) {
54+
dd("ModSecurity not enabled... returning");
55+
return NGX_OK;
56+
}
57+
}
58+
59+
if (ngx_http_get_intervention_status(r) == 1 && cf->rules_backup != NULL) {
60+
dd("restore ruleset %p from backup for current location", cf->rules_backup);
61+
cf->rules_set = cf->rules_backup;
62+
cf->rules_backup = NULL;
63+
}
64+
5365
/*
5466
if (r->method != NGX_HTTP_GET &&
5567
r->method != NGX_HTTP_POST && r->method != NGX_HTTP_HEAD) {
@@ -67,15 +79,12 @@ ngx_http_modsecurity_log_handler(ngx_http_request_t *r)
6779
return NGX_ERROR;
6880
}
6981

70-
if (ctx->logged) {
71-
dd("already logged earlier");
72-
return NGX_OK;
73-
}
74-
7582
dd("calling msc_process_logging for %p", ctx);
7683
old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
7784
msc_process_logging(ctx->modsec_transaction);
7885
ngx_http_modsecurity_pcre_malloc_done(old_pool);
7986

87+
88+
8089
return NGX_OK;
8190
}

src/ngx_http_modsecurity_module.c

Lines changed: 153 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,19 @@ static char *ngx_http_modsecurity_merge_srv_conf(ngx_conf_t *cf, void *parent, v
3232
static void ngx_http_modsecurity_config_cleanup(void *data);
3333
static char *ngx_http_modsecurity_init_main_conf(ngx_conf_t *cf, void *conf);
3434

35+
static ngx_int_t ngx_http_modsecurity_add_variables(ngx_conf_t *cf);
36+
static ngx_int_t ngx_http_intervention_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
37+
static ngx_int_t ngx_http_rules_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
38+
39+
ngx_http_variable_t ngx_http_modsecurity_vars[] = {
40+
{ ngx_string("intervention_done"), NULL,
41+
ngx_http_intervention_variable, 0,
42+
NGX_HTTP_VAR_NOCACHEABLE, 0},
43+
{ ngx_string("rules"), NULL,
44+
ngx_http_rules_variable, 0,
45+
NGX_HTTP_VAR_NOCACHEABLE, 0},
46+
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
47+
};
3548

3649
/*
3750
* PCRE malloc/free workaround, based on
@@ -137,14 +150,12 @@ ngx_http_modsecurity_process_intervention (Transaction *transaction, ngx_http_re
137150
intervention.url = NULL;
138151
intervention.log = NULL;
139152
intervention.disruptive = 0;
140-
ngx_http_modsecurity_ctx_t *ctx = NULL;
141153

142154
dd("processing intervention");
143155

144-
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
145-
if (ctx == NULL)
146-
{
147-
return NGX_HTTP_INTERNAL_SERVER_ERROR;
156+
if (ngx_http_get_intervention_status(r)) {
157+
dd("already done earlier");
158+
return 0;
148159
}
149160

150161
if (msc_intervention(transaction, &intervention) == 0) {
@@ -201,8 +212,7 @@ ngx_http_modsecurity_process_intervention (Transaction *transaction, ngx_http_re
201212

202213
if (intervention.status != 200)
203214
{
204-
ngx_http_modsecurity_log_handler(r);
205-
ctx->logged = 1;
215+
ngx_http_set_intervention_status_done(r);
206216

207217
if (r->header_sent)
208218
{
@@ -257,7 +267,7 @@ ngx_http_modsecurity_create_ctx(ngx_http_request_t *r)
257267
ctx->modsec_transaction = msc_new_transaction(cf->modsec, loc_cf->rules_set, r->connection->log);
258268

259269
dd("transaction created");
260-
270+
261271
ctx->response_body_filtered = 0;
262272
ngx_http_set_ctx(r, ctx, ngx_http_modsecurity_module);
263273

@@ -395,7 +405,7 @@ static ngx_command_t ngx_http_modsecurity_commands[] = {
395405

396406

397407
static ngx_http_module_t ngx_http_modsecurity_ctx = {
398-
NULL, /* preconfiguration */
408+
ngx_http_modsecurity_add_variables, /* preconfiguration */
399409
ngx_http_modsecurity_init, /* postconfiguration */
400410

401411
ngx_http_modsecurity_create_main_conf, /* create main configuration */
@@ -672,3 +682,137 @@ ngx_http_modsecurity_config_cleanup(void *data)
672682

673683

674684
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
685+
686+
static ngx_int_t
687+
ngx_http_modsecurity_add_variables(ngx_conf_t *cf)
688+
{
689+
ngx_http_variable_t *var, *v;
690+
ngx_int_t index;
691+
692+
dd("adding variable");
693+
694+
for (v = ngx_http_modsecurity_vars; v->name.len; v++) {
695+
var = ngx_http_add_variable(cf, &v->name, v->flags);
696+
if (var == NULL) {
697+
return NGX_ERROR;
698+
}
699+
var->get_handler = v->get_handler;
700+
701+
// initialization a variable
702+
index = ngx_http_get_variable_index(cf, &v->name);
703+
if (index == NGX_ERROR) {
704+
return NGX_ERROR;
705+
}
706+
dd("variable %s, index %d", v->name.data, index);
707+
}
708+
709+
return NGX_OK;
710+
}
711+
712+
static ngx_int_t
713+
ngx_http_intervention_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data)
714+
{
715+
if (v->data == NULL) {
716+
dd("initialize variable at first time");
717+
ngx_str_t str = ngx_string("no");
718+
v->valid = 1;
719+
v->not_found = 0;
720+
v->no_cacheable = 0;
721+
v->data = str.data;
722+
v->len = str.len;
723+
}
724+
return NGX_OK;
725+
}
726+
727+
static ngx_int_t
728+
ngx_http_rules_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data)
729+
{
730+
return NGX_OK;
731+
}
732+
733+
ngx_int_t
734+
ngx_http_get_intervention_status(ngx_http_request_t *r)
735+
{
736+
ngx_http_variable_value_t *vv = NULL;
737+
ngx_uint_t key;
738+
ngx_str_t str = ngx_string("yes");
739+
u_char* buf;
740+
741+
buf = ngx_palloc(r->pool, ngx_http_modsecurity_vars[0].name.len);
742+
key = ngx_hash_strlow(buf, ngx_http_modsecurity_vars[0].name.data, ngx_http_modsecurity_vars[0].name.len);
743+
vv = ngx_http_get_variable(r, &ngx_http_modsecurity_vars[0].name, key);
744+
if (vv == NULL) {
745+
return NGX_ERROR;
746+
}
747+
748+
if (ngx_strncasecmp(vv->data, str.data, str.len) == 0) {
749+
return 1;
750+
}
751+
752+
return 0;
753+
}
754+
755+
ngx_int_t
756+
ngx_http_set_intervention_status_done(ngx_http_request_t *r)
757+
{
758+
ngx_http_variable_value_t *vv = NULL;
759+
ngx_uint_t key;
760+
ngx_str_t str = ngx_string("yes");
761+
u_char* buf;
762+
763+
buf = ngx_palloc(r->pool, ngx_http_modsecurity_vars[0].name.len);
764+
key = ngx_hash_strlow(buf, ngx_http_modsecurity_vars[0].name.data, ngx_http_modsecurity_vars[0].name.len);
765+
vv = ngx_http_get_variable(r, &ngx_http_modsecurity_vars[0].name, key);
766+
if (vv == NULL) {
767+
return NGX_ERROR;
768+
}
769+
770+
vv->data = str.data;
771+
vv->len = str.len;
772+
773+
return 1;
774+
}
775+
776+
ngx_http_variable_t *
777+
ngx_http_get_variable_by_name(ngx_http_request_t *r, ngx_str_t *name)
778+
{
779+
ngx_http_core_main_conf_t *cmcf;
780+
ngx_http_variable_t *v;
781+
ngx_uint_t i;
782+
783+
if (name->len == 0) {
784+
ngx_log_error(NGX_LOG_EMERG, r->connection->log, 0, "invalid variable name");
785+
return NULL;
786+
}
787+
788+
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
789+
790+
v = cmcf->variables.elts;
791+
792+
for (i = 0; i < cmcf->variables.nelts; i++) {
793+
if (name->len != v[i].name.len || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0) {
794+
continue;
795+
}
796+
return v;
797+
}
798+
799+
return NULL;
800+
}
801+
802+
void
803+
ngx_http_restore_ruleset_from_variable(ngx_http_request_t *r, ngx_http_modsecurity_conf_t *cf)
804+
{
805+
ngx_http_variable_t *v;
806+
807+
// saving the ruleset pointer to make it available for the cleanup callback that invoked when the config pool will be destroyed
808+
dd("backup ruleset %p for current location", cf->rules_set);
809+
cf->rules_backup = cf->rules_set;
810+
811+
v = ngx_http_get_variable_by_name(r, &ngx_http_modsecurity_vars[1].name);
812+
if (v != NULL) {
813+
dd("restore ruleset %p from variable", (void *)v->data);
814+
cf->rules_set = (Rules *)v->data;
815+
} else {
816+
dd("failed to restore ruleset from varibale");
817+
}
818+
}

src/ngx_http_modsecurity_pre_access.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,17 @@ ngx_http_modsecurity_pre_access_handler(ngx_http_request_t *r)
5050
dd("catching a new _preaccess_ phase handler");
5151

5252
cf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity_module);
53-
if (cf == NULL || cf->enable != 1)
54-
{
55-
dd("ModSecurity not enabled... returning");
53+
if (cf == NULL) {
54+
dd("Something bad happened... returning");
5655
return NGX_DECLINED;
5756
}
57+
58+
if (cf->enable != 1) {
59+
if (!ngx_http_get_intervention_status(r)) {
60+
dd("ModSecurity not enabled... returning");
61+
return NGX_DECLINED;
62+
}
63+
}
5864
/*
5965
* FIXME:
6066
* In order to perform some tests, let's accept everything.

src/ngx_http_modsecurity_rewrite.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,42 @@ ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r)
2626
ngx_http_modsecurity_ctx_t *ctx = NULL;
2727
ngx_http_modsecurity_conf_t *cf;
2828
ngx_pool_t *old_pool;
29+
ngx_http_variable_t *v;
2930

3031
cf = ngx_http_get_module_loc_conf(r, ngx_http_modsecurity_module);
31-
if (cf == NULL || cf->enable != 1) {
32-
dd("ModSecurity not enabled... returning");
32+
if (cf == NULL) {
33+
dd("Something bad happened... returning");
3334
return NGX_DECLINED;
3435
}
3536

37+
if (cf->enable != 1) {
38+
if (!ngx_http_get_intervention_status(r)) {
39+
dd("ModSecurity not enabled... returning");
40+
return NGX_DECLINED;
41+
}
42+
}
43+
44+
//explicitly clearing value
45+
cf->rules_backup = NULL;
46+
47+
if (ngx_http_get_intervention_status(r)) {
48+
dd("ruleset before restore: %p", cf->rules_set);
49+
ngx_http_restore_ruleset_from_variable(r, cf);
50+
}
51+
52+
if (!ngx_http_get_intervention_status(r)) {
53+
dd("save current ruleset pointer");
54+
ngx_str_t tmp = ngx_string("rules");
55+
v = ngx_http_get_variable_by_name(r, &tmp);
56+
if (v != NULL) {
57+
dd("save ruleset %p to variable", cf->rules_set);
58+
v->data = (uintptr_t) cf->rules_set;
59+
} else {
60+
dd("failed to save ruleset to varibale");
61+
return NGX_DECLINED;
62+
}
63+
}
64+
3665
/*
3766
if (r->method != NGX_HTTP_GET &&
3867
r->method != NGX_HTTP_POST && r->method != NGX_HTTP_HEAD) {

0 commit comments

Comments
 (0)