Skip to content

Commit d9016e2

Browse files
authored
Merge pull request owasp-modsecurity#3120 from marcstern/v2/mst/nullcheck2
Check for null pointer dereference (almost) everywhere
2 parents 788c36d + dd400f7 commit d9016e2

26 files changed

+1954
-1042
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
- name: autogen.sh
3333
run: ./autogen.sh
3434
- name: configure ${{ matrix.configure.label }}
35-
run: ./configure ${{ matrix.configure.opt }}
35+
run: ./configure --enable-assertions ${{ matrix.configure.opt }}
3636
- uses: ammaraskar/gcc-problem-matcher@master
3737
- name: make
3838
run: make -j `nproc`

apache2/apache2_config.c

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@
3030
APLOG_USE_MODULE(security2);
3131
#endif
3232

33+
// Returns the rule id if existing, otherwise the file name & line number
34+
const char* id_log(msre_rule* rule) {
35+
assert(rule != NULL);
36+
assert(rule->actionset != NULL);
37+
const char* id = rule->actionset->id;
38+
if (!id || !*id || id == NOT_SET_P) id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num);
39+
return id;
40+
}
41+
3342
/* -- Directory context creation and initialisation -- */
3443

3544
/**
@@ -239,19 +248,19 @@ static void copy_rules_phase(apr_pool_t *mp,
239248

240249
if (copy > 0) {
241250
#ifdef DEBUG_CONF
242-
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy rule %pp [id \"%s\"]", rule, rule->actionset->id);
251+
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy rule %pp [id \"%s\"]", rule, id_log(rule));
243252
#endif
244253

245254
/* Copy the rule. */
246255
*(msre_rule **)apr_array_push(child_phase_arr) = rule;
247-
if (rule->actionset && rule->actionset->is_chained) mode = 2;
256+
if (rule->actionset->is_chained) mode = 2;
248257
} else {
249-
if (rule->actionset && rule->actionset->is_chained) mode = 1;
258+
if (rule->actionset->is_chained) mode = 1;
250259
}
251260
} else {
252261
if (mode == 2) {
253262
#ifdef DEBUG_CONF
254-
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);
263+
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));
255264
#endif
256265

257266
/* 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,
906915
*/
907916
rule->actionset = msre_actionset_merge(modsecurity->msre, cmd->pool, dcfg->tmp_default_actionset,
908917
rule->actionset, 1);
918+
if (rule->actionset == NULL) return apr_psprintf(cmd->pool, "ModSecurity: cannot merge actionset (memory full?).");
909919

910920
/* Keep track of the parent action for "block" */
911-
if (rule->actionset) {
912-
rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec;
913-
rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action;
914-
}
921+
rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec;
922+
rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action;
915923

916924
/* Must NOT specify a disruptive action in logging phase. */
917-
if ((rule->actionset != NULL)
918-
&& (rule->actionset->phase == PHASE_LOGGING)
925+
if ( (rule->actionset->phase == PHASE_LOGGING)
919926
&& (rule->actionset->intercept_action != ACTION_ALLOW)
920927
&& (rule->actionset->intercept_action != ACTION_ALLOW_REQUEST)
921928
&& (rule->actionset->intercept_action != ACTION_NONE)
@@ -926,9 +933,7 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type,
926933

927934
if (dcfg->tmp_chain_starter != NULL) {
928935
rule->chain_starter = dcfg->tmp_chain_starter;
929-
if (rule->actionset) {
930-
rule->actionset->phase = rule->chain_starter->actionset->phase;
931-
}
936+
rule->actionset->phase = rule->chain_starter->actionset->phase;
932937
}
933938

934939
if (rule->actionset->is_chained != 1) {
@@ -967,8 +972,7 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type,
967972

968973
#ifdef DEBUG_CONF
969974
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
970-
"Adding rule %pp phase=%d id=\"%s\".", rule, rule->actionset->phase, (rule->actionset->id == NOT_SET_P
971-
? "(none)" : rule->actionset->id));
975+
"Adding rule %pp phase=%d id=\"%s\".", rule, rule->actionset->phase, id_log(rule));
972976
#endif
973977

974978
/* Add rule to the recipe. */
@@ -1042,8 +1046,7 @@ static const char *add_marker(cmd_parms *cmd, directory_config *dcfg,
10421046
for (p = PHASE_FIRST; p <= PHASE_LAST; p++) {
10431047
#ifdef DEBUG_CONF
10441048
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
1045-
"Adding marker %pp phase=%d id=\"%s\".", rule, p, (rule->actionset->id == NOT_SET_P
1046-
? "(none)" : rule->actionset->id));
1049+
"Adding marker %pp phase=%d id=\"%s\".", rule, p, id_log(rule));
10471050
#endif
10481051

10491052
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,
10911094
return NULL;
10921095
}
10931096

1094-
/* Check the rule actionset */
1095-
/* ENH: Can this happen? */
1096-
if (rule->actionset == NULL) {
1097-
return apr_psprintf(cmd->pool, "ModSecurity: Attempt to update action for rule \"%s\" failed: Rule does not have an actionset.", p1);
1098-
}
1097+
assert(rule->actionset != NULL);
10991098

11001099
/* Create a new actionset */
11011100
new_actionset = msre_actionset_create(modsecurity->msre, cmd->pool, p2, &my_error_msg);
@@ -1117,16 +1116,15 @@ static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg,
11171116
char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset);
11181117
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
11191118
"Update rule %pp id=\"%s\" old action: \"%s\"",
1120-
rule,
1121-
(rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id),
1122-
actions);
1119+
rule, id_log(rule), actions);
11231120
}
11241121
#endif
11251122

11261123
/* Merge new actions with the rule */
11271124
/* ENH: Will this leak the old actionset? */
11281125
rule->actionset = msre_actionset_merge(modsecurity->msre, cmd->pool, rule->actionset,
11291126
new_actionset, 1);
1127+
if (rule->actionset == NULL) return apr_psprintf(cmd->pool, "ModSecurity: cannot merge actionset (memory full?).");
11301128
msre_actionset_set_defaults(rule->actionset);
11311129

11321130
/* Update the unparsed rule */
@@ -1137,9 +1135,7 @@ static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg,
11371135
char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset);
11381136
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
11391137
"Update rule %pp id=\"%s\" new action: \"%s\"",
1140-
rule,
1141-
(rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id),
1142-
actions);
1138+
rule, id_log(rule), actions);
11431139
}
11441140
#endif
11451141

@@ -1746,6 +1742,9 @@ char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2,
17461742

17471743
config_orig_path = apr_pstrndup(mp, filename,
17481744
strlen(filename) - strlen(apr_filepath_name_get(filename)));
1745+
if (config_orig_path == NULL) {
1746+
return apr_psprintf(mp, "ModSecurity: failed to duplicate filename in parser_conn_limits_operator");
1747+
}
17491748

17501749
apr_filepath_merge(&file, config_orig_path, param, APR_FILEPATH_TRUENAME,
17511750
mp);
@@ -2452,8 +2451,12 @@ static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg,
24522451
const char *p1)
24532452
{
24542453
directory_config *dcfg = (directory_config *)_dcfg;
2455-
rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
24562454
if (dcfg == NULL) return NULL;
2455+
rule_exception* re = apr_pcalloc(cmd->pool, sizeof(rule_exception));
2456+
if (re == NULL) {
2457+
ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, cmd->pool, "cmd_rule_remove_by_id: Cannot allocate memory");
2458+
return NULL;
2459+
}
24572460

24582461
re->type = RULE_EXCEPTION_REMOVE_ID;
24592462
re->param = p1;

apache2/apache2_io.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,13 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
179179
* Reads request body from a client.
180180
*/
181181
apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
182+
assert(msr != NULL);
183+
assert(error_msg!= NULL);
182184
request_rec *r = msr->r;
183185
unsigned int finished_reading;
184186
apr_bucket_brigade *bb_in;
185187
apr_bucket *bucket;
186188

187-
if (error_msg == NULL) return -1;
188189
*error_msg = NULL;
189190

190191
if (msr->reqbody_should_exist != 1) {
@@ -368,6 +369,8 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
368369
* run or not.
369370
*/
370371
static int output_filter_should_run(modsec_rec *msr, request_rec *r) {
372+
assert(msr != NULL);
373+
assert(r != NULL);
371374
char *content_type = NULL;
372375

373376
/* Check configuration. */
@@ -429,10 +432,13 @@ static int output_filter_should_run(modsec_rec *msr, request_rec *r) {
429432
static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f,
430433
apr_bucket_brigade *bb_in)
431434
{
435+
assert(msr != NULL);
436+
assert(f != NULL);
432437
request_rec *r = f->r;
433438
const char *s_content_length = NULL;
434439
apr_status_t rc;
435440

441+
assert(msr != NULL);
436442
msr->of_brigade = apr_brigade_create(msr->mp, f->c->bucket_alloc);
437443
if (msr->of_brigade == NULL) {
438444
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,
496502
* and to the client.
497503
*/
498504
static apr_status_t send_of_brigade(modsec_rec *msr, ap_filter_t *f) {
505+
assert(msr != NULL);
506+
assert(f != NULL);
499507
apr_status_t rc;
500508

501509
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) {
537545
*
538546
*/
539547
static void inject_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) {
548+
assert(msr != NULL);
549+
assert(f != NULL);
540550
apr_bucket *b;
541551

542552
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) {
563573
*
564574
*/
565575
static void prepend_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) {
576+
assert(msr != NULL);
577+
assert(f != NULL);
566578
if ((msr->txcfg->content_injection_enabled) && (msr->content_prepend) && (!msr->of_skipping)) {
567579
apr_bucket *bucket_ci = NULL;
568580

@@ -1008,6 +1020,12 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
10081020
/* Now send data down the filter stream
10091021
* (full-buffering only).
10101022
*/
1023+
if (!eos_bucket) {
1024+
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
1025+
"ModSecurity: Internal Error: eos_bucket is NULL.");
1026+
return APR_EGENERAL;
1027+
}
1028+
10111029
if ((msr->of_skipping == 0)&&(!msr->of_partial)) {
10121030
if(msr->of_stream_changed == 1) {
10131031
inject_content_to_of_brigade(msr,f);

apache2/apache2_util.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
* Sends a brigade with an error bucket down the filter chain.
2626
*/
2727
apr_status_t send_error_bucket(modsec_rec *msr, ap_filter_t *f, int status) {
28+
assert(msr != NULL);
29+
assert(f != NULL);
2830
apr_bucket_brigade *brigade = NULL;
2931
apr_bucket *bucket = NULL;
3032

@@ -61,6 +63,9 @@ apr_status_t send_error_bucket(modsec_rec *msr, ap_filter_t *f, int status) {
6163
* the "output" parameter.
6264
*/
6365
int apache2_exec(modsec_rec *msr, const char *command, const char **argv, char **output) {
66+
assert(msr != NULL);
67+
assert(command != NULL);
68+
6469
apr_procattr_t *procattr = NULL;
6570
apr_proc_t *procnew = NULL;
6671
apr_status_t rc = APR_SUCCESS;
@@ -204,6 +209,9 @@ char *get_env_var(request_rec *r, char *name) {
204209
static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *msr,
205210
int level, int fixup, const char *text, va_list ap)
206211
{
212+
assert(r != NULL);
213+
assert(msr != NULL);
214+
assert(text != NULL);
207215
apr_size_t nbytes, nbytes_written;
208216
apr_file_t *debuglog_fd = NULL;
209217
int filter_debug_level = 0;
@@ -303,6 +311,8 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *
303311
* Apache error log if the message is important enough.
304312
*/
305313
void msr_log(modsec_rec *msr, int level, const char *text, ...) {
314+
assert(msr != NULL);
315+
assert(text != NULL);
306316
va_list ap;
307317

308318
va_start(ap, text);
@@ -316,6 +326,8 @@ void msr_log(modsec_rec *msr, int level, const char *text, ...) {
316326
* Apache error log. This is intended for error callbacks.
317327
*/
318328
void msr_log_error(modsec_rec *msr, const char *text, ...) {
329+
assert(msr != NULL);
330+
assert(text != NULL);
319331
va_list ap;
320332

321333
va_start(ap, text);
@@ -330,6 +342,8 @@ void msr_log_error(modsec_rec *msr, const char *text, ...) {
330342
* The 'text' will first be escaped.
331343
*/
332344
void msr_log_warn(modsec_rec *msr, const char *text, ...) {
345+
assert(msr != NULL);
346+
assert(text != NULL);
333347
va_list ap;
334348

335349
va_start(ap, text);

apache2/mod_security2.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,8 @@ static modsec_rec *retrieve_tx_context(request_rec *r) {
475475
* phases, redirections, or subrequests.
476476
*/
477477
static void store_tx_context(modsec_rec *msr, request_rec *r) {
478+
assert(msr != NULL);
479+
assert(r != NULL);
478480
apr_table_setn(r->notes, NOTE_MSR, (void *)msr);
479481
}
480482

@@ -491,7 +493,10 @@ static modsec_rec *create_tx_context(request_rec *r) {
491493
apr_allocator_create(&allocator);
492494
apr_allocator_max_free_set(allocator, 1024);
493495
apr_pool_create_ex(&msr->mp, r->pool, NULL, allocator);
494-
if (msr->mp == NULL) return NULL;
496+
if (msr->mp == NULL) {
497+
apr_allocator_destroy(allocator);
498+
return NULL;
499+
}
495500
apr_allocator_owner_set(allocator, msr->mp);
496501

497502
msr->modsecurity = modsecurity;
@@ -863,6 +868,9 @@ static int hook_request_early(request_rec *r) {
863868
*/
864869
msr = create_tx_context(r);
865870
if (msr == NULL) return DECLINED;
871+
if (msr->txcfg->debuglog_level >= 9) {
872+
msr_log(msr, 9, "Context created after request failure.");
873+
}
866874

867875
#ifdef REQUEST_EARLY
868876

@@ -1150,17 +1158,12 @@ static void hook_error_log(const char *file, int line, int level, apr_status_t s
11501158
#endif
11511159
if (msr_ap_server) {
11521160
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
1153-
msr = create_tx_context((request_rec *)info->r);
1161+
msr = create_tx_context((request_rec*)info->r);
11541162
#else
1155-
msr = create_tx_context((request_rec *)r);
1163+
msr = create_tx_context((request_rec*)r);
11561164
#endif
1157-
if (msr != NULL && msr->txcfg->debuglog_level >= 9) {
1158-
if (msr == NULL) {
1159-
msr_log(msr, 9, "Failed to create context after request failure.");
1160-
}
1161-
else {
1162-
msr_log(msr, 9, "Context created after request failure.");
1163-
}
1165+
if (msr && msr->txcfg->debuglog_level >= 9) {
1166+
msr_log(msr, 9, "Context created after request failure.");
11641167
}
11651168
}
11661169
if (msr == NULL) return;

0 commit comments

Comments
 (0)