@@ -325,7 +325,14 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) {
325
325
}
326
326
327
327
msr -> mpd -> mpp_state = 1 ;
328
+ msr -> mpd -> mpp_substate_part_data_read = 0 ;
328
329
msr -> mpd -> mpp -> last_header_name = NULL ;
330
+
331
+ /* Record the last part header line in the collection */
332
+ if (msr -> mpd -> mpp -> last_header_line != NULL ) {
333
+ * (char * * )apr_array_push (msr -> mpd -> mpp -> header_lines ) = msr -> mpd -> mpp -> last_header_line ;
334
+ msr_log (msr , 9 , "Multipart: Added part header line \"%s\"" , msr -> mpd -> mpp -> last_header_line );
335
+ }
329
336
} else {
330
337
/* Header line. */
331
338
@@ -379,12 +386,28 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) {
379
386
* error_msg = apr_psprintf (msr -> mp , "Multipart: Part header too long." );
380
387
return -1 ;
381
388
}
389
+ if ((msr -> mpd -> mpp -> last_header_line != NULL ) && (msr -> mpd -> mpp -> last_header_name != NULL )
390
+ && (new_value != NULL )) {
391
+ msr -> mpd -> mpp -> last_header_line = apr_psprintf (msr -> mp ,
392
+ "%s: %s" , msr -> mpd -> mpp -> last_header_name , new_value );
393
+ }
394
+
382
395
} else {
383
396
char * header_name , * header_value , * data ;
384
397
385
398
/* new header */
386
399
400
+ /* Record the most recently-seen part header line in the collection */
401
+ if (msr -> mpd -> mpp -> last_header_line != NULL ) {
402
+ * (char * * )apr_array_push (msr -> mpd -> mpp -> header_lines ) = msr -> mpd -> mpp -> last_header_line ;
403
+ msr_log (msr , 9 , "Multipart: Added part header line \"%s\"" , msr -> mpd -> mpp -> last_header_line );
404
+ }
405
+
387
406
data = msr -> mpd -> buf ;
407
+
408
+ msr -> mpd -> mpp -> last_header_line = apr_pstrdup (msr -> mp , data );
409
+ remove_lf_crlf_inplace (msr -> mpd -> mpp -> last_header_line );
410
+
388
411
while ((* data != ':' ) && (* data != '\0' )) data ++ ;
389
412
if (* data == '\0' ) {
390
413
* error_msg = apr_psprintf (msr -> mp , "Multipart: Invalid part header (colon missing): %s." ,
@@ -438,6 +461,8 @@ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) {
438
461
if (error_msg == NULL ) return -1 ;
439
462
* error_msg = NULL ;
440
463
464
+ msr -> mpd -> mpp_substate_part_data_read = 1 ;
465
+
441
466
/* Preserve some bytes for later. */
442
467
if ( ((MULTIPART_BUF_SIZE - msr -> mpd -> bufleft ) >= 1 )
443
468
&& (* (p - 1 ) == '\n' ) )
@@ -680,10 +705,14 @@ static int multipart_process_boundary(modsec_rec *msr, int last_part, char **err
680
705
if (msr -> mpd -> mpp == NULL ) return -1 ;
681
706
msr -> mpd -> mpp -> type = MULTIPART_FORMDATA ;
682
707
msr -> mpd -> mpp_state = 0 ;
708
+ msr -> mpd -> mpp_substate_part_data_read = 0 ;
683
709
684
710
msr -> mpd -> mpp -> headers = apr_table_make (msr -> mp , 10 );
685
711
if (msr -> mpd -> mpp -> headers == NULL ) return -1 ;
686
712
msr -> mpd -> mpp -> last_header_name = NULL ;
713
+ msr -> mpd -> mpp -> last_header_line = NULL ;
714
+ msr -> mpd -> mpp -> header_lines = apr_array_make (msr -> mp , 2 , sizeof (char * ));
715
+ if (msr -> mpd -> mpp -> header_lines == NULL ) return -1 ;
687
716
688
717
msr -> mpd -> reserve [0 ] = 0 ;
689
718
msr -> mpd -> reserve [1 ] = 0 ;
@@ -983,6 +1012,19 @@ int multipart_complete(modsec_rec *msr, char **error_msg) {
983
1012
&& (* (msr -> mpd -> buf + 2 + strlen (msr -> mpd -> boundary )) == '-' )
984
1013
&& (* (msr -> mpd -> buf + 2 + strlen (msr -> mpd -> boundary ) + 1 ) == '-' ) )
985
1014
{
1015
+ if ((msr -> mpd -> crlf_state_buf_end == 2 ) && (msr -> mpd -> flag_lf_line != 1 )) {
1016
+ msr -> mpd -> flag_lf_line = 1 ;
1017
+ if (msr -> mpd -> flag_crlf_line ) {
1018
+ msr_log (msr , 4 , "Multipart: Warning: mixed line endings used (CRLF/LF)." );
1019
+ } else {
1020
+ msr_log (msr , 4 , "Multipart: Warning: incorrect line endings used (LF)." );
1021
+ }
1022
+ }
1023
+ if (msr -> mpd -> mpp_substate_part_data_read == 0 ) {
1024
+ /* it looks like the final boundary, but it's where part data should begin */
1025
+ msr -> mpd -> flag_invalid_part = 1 ;
1026
+ msr_log (msr , 4 , "Multipart: Warning: Invalid part (data contains final boundary)" );
1027
+ }
986
1028
/* Looks like the final boundary - process it. */
987
1029
if (multipart_process_boundary (msr , 1 /* final */ , error_msg ) < 0 ) {
988
1030
msr -> mpd -> flag_error = 1 ;
@@ -1075,54 +1117,63 @@ int multipart_process_chunk(modsec_rec *msr, const char *buf,
1075
1117
if ( (strlen (msr -> mpd -> buf ) >= strlen (msr -> mpd -> boundary ) + 2 )
1076
1118
&& (strncmp (msr -> mpd -> buf + 2 , msr -> mpd -> boundary , strlen (msr -> mpd -> boundary )) == 0 ) )
1077
1119
{
1078
- char * boundary_end = msr -> mpd -> buf + 2 + strlen (msr -> mpd -> boundary );
1079
- int is_final = 0 ;
1120
+ if (msr -> mpd -> crlf_state_buf_end == 2 ) {
1121
+ msr -> mpd -> flag_lf_line = 1 ;
1122
+ }
1123
+ if ((msr -> mpd -> mpp_substate_part_data_read == 0 ) && (msr -> mpd -> boundary_count > 0 )) {
1124
+ /* string matches our boundary, but it's where part data should begin */
1125
+ msr -> mpd -> flag_invalid_part = 1 ;
1126
+ msr_log (msr , 4 , "Multipart: Warning: Invalid part (data contains boundary)" );
1127
+ } else {
1128
+ char * boundary_end = msr -> mpd -> buf + 2 + strlen (msr -> mpd -> boundary );
1129
+ int is_final = 0 ;
1130
+
1131
+ /* Is this the final boundary? */
1132
+ if ((* boundary_end == '-' ) && (* (boundary_end + 1 )== '-' )) {
1133
+ is_final = 1 ;
1134
+ boundary_end += 2 ;
1135
+
1136
+ if (msr -> mpd -> is_complete != 0 ) {
1137
+ msr -> mpd -> flag_error = 1 ;
1138
+ * error_msg = apr_psprintf (msr -> mp ,
1139
+ "Multipart: Invalid boundary (final duplicate)." );
1140
+ return -1 ;
1141
+ }
1142
+ }
1080
1143
1081
- /* Is this the final boundary? */
1082
- if ((* boundary_end == '-' ) && (* (boundary_end + 1 )== '-' )) {
1083
- is_final = 1 ;
1084
- boundary_end += 2 ;
1144
+ /* Allow for CRLF and LF line endings. */
1145
+ if ( ( (* boundary_end == '\r' )
1146
+ && (* (boundary_end + 1 ) == '\n' )
1147
+ && (* (boundary_end + 2 ) == '\0' ) )
1148
+ || ( (* boundary_end == '\n' )
1149
+ && (* (boundary_end + 1 ) == '\0' ) ) )
1150
+ {
1151
+ if (* boundary_end == '\n' ) {
1152
+ msr -> mpd -> flag_lf_line = 1 ;
1153
+ } else {
1154
+ msr -> mpd -> flag_crlf_line = 1 ;
1155
+ }
1085
1156
1086
- if (msr -> mpd -> is_complete != 0 ) {
1087
- msr -> mpd -> flag_error = 1 ;
1088
- * error_msg = apr_psprintf (msr -> mp ,
1089
- "Multipart: Invalid boundary (final duplicate)." );
1090
- return -1 ;
1091
- }
1092
- }
1157
+ if (multipart_process_boundary (msr , (is_final ? 1 : 0 ), error_msg ) < 0 ) {
1158
+ msr -> mpd -> flag_error = 1 ;
1159
+ return -1 ;
1160
+ }
1093
1161
1094
- /* Allow for CRLF and LF line endings. */
1095
- if ( ( (* boundary_end == '\r' )
1096
- && (* (boundary_end + 1 ) == '\n' )
1097
- && (* (boundary_end + 2 ) == '\0' ) )
1098
- || ( (* boundary_end == '\n' )
1099
- && (* (boundary_end + 1 ) == '\0' ) ) )
1100
- {
1101
- if (* boundary_end == '\n' ) {
1102
- msr -> mpd -> flag_lf_line = 1 ;
1103
- } else {
1104
- msr -> mpd -> flag_crlf_line = 1 ;
1105
- }
1162
+ if (is_final ) {
1163
+ msr -> mpd -> is_complete = 1 ;
1164
+ }
1106
1165
1107
- if (multipart_process_boundary (msr , (is_final ? 1 : 0 ), error_msg ) < 0 ) {
1166
+ processed_as_boundary = 1 ;
1167
+ msr -> mpd -> boundary_count ++ ;
1168
+ }
1169
+ else {
1170
+ /* error */
1108
1171
msr -> mpd -> flag_error = 1 ;
1172
+ * error_msg = apr_psprintf (msr -> mp ,
1173
+ "Multipart: Invalid boundary: %s" ,
1174
+ log_escape_nq (msr -> mp , msr -> mpd -> buf ));
1109
1175
return -1 ;
1110
1176
}
1111
-
1112
- if (is_final ) {
1113
- msr -> mpd -> is_complete = 1 ;
1114
- }
1115
-
1116
- processed_as_boundary = 1 ;
1117
- msr -> mpd -> boundary_count ++ ;
1118
- }
1119
- else {
1120
- /* error */
1121
- msr -> mpd -> flag_error = 1 ;
1122
- * error_msg = apr_psprintf (msr -> mp ,
1123
- "Multipart: Invalid boundary: %s" ,
1124
- log_escape_nq (msr -> mp , msr -> mpd -> buf ));
1125
- return -1 ;
1126
1177
}
1127
1178
} else { /* It looks like a boundary but we couldn't match it. */
1128
1179
char * p = NULL ;
@@ -1221,6 +1272,21 @@ int multipart_process_chunk(modsec_rec *msr, const char *buf,
1221
1272
msr -> mpd -> bufptr = msr -> mpd -> buf ;
1222
1273
msr -> mpd -> bufleft = MULTIPART_BUF_SIZE ;
1223
1274
msr -> mpd -> buf_contains_line = (c == 0x0a ) ? 1 : 0 ;
1275
+
1276
+ if (c == 0x0a ) {
1277
+ if (msr -> mpd -> crlf_state == 1 ) {
1278
+ msr -> mpd -> crlf_state = 3 ;
1279
+ } else {
1280
+ msr -> mpd -> crlf_state = 2 ;
1281
+ }
1282
+ }
1283
+ msr -> mpd -> crlf_state_buf_end = msr -> mpd -> crlf_state ;
1284
+ }
1285
+
1286
+ if (c == 0x0d ) {
1287
+ msr -> mpd -> crlf_state = 1 ;
1288
+ } else if (c != 0x0a ) {
1289
+ msr -> mpd -> crlf_state = 0 ;
1224
1290
}
1225
1291
1226
1292
if ((msr -> mpd -> is_complete ) && (inleft != 0 )) {
0 commit comments