]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
http/multipart: process incomplete file data
authorVictor Julien <victor@inliniac.net>
Mon, 25 Nov 2019 14:21:32 +0000 (15:21 +0100)
committerVictor Julien <victor@inliniac.net>
Mon, 9 Dec 2019 10:13:51 +0000 (11:13 +0100)
Start processing multipart data as soon as it is available to
allow inspection sooner.

src/app-layer-htp.c

index 5a85aa45676813f7986dde65d91ed96d813d2ced..22f3c16c395b22168a90a54bda1026e94df7d881 100644 (file)
@@ -1311,14 +1311,16 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud,
     HtpRequestBodySetupBoundary(htud, boundary, htud->boundary_len + 4);
 
     /* search for the header start, header end and form end */
-    uint8_t *header_start = Bs2bmSearch(chunks_buffer, chunks_buffer_len,
+    const uint8_t *header_start = Bs2bmSearch(chunks_buffer, chunks_buffer_len,
             boundary, expected_boundary_len);
+    /* end marker belonging to header_start */
     uint8_t *header_end = NULL;
     if (header_start != NULL) {
         header_end = Bs2bmSearch(header_start, chunks_buffer_len - (header_start - chunks_buffer),
                 (uint8_t *)"\r\n\r\n", 4);
     }
-    uint8_t *form_end = Bs2bmSearch(chunks_buffer, chunks_buffer_len,
+    /* end of the multipart form */
+    const uint8_t *form_end = Bs2bmSearch(chunks_buffer, chunks_buffer_len,
             boundary, expected_boundary_end_len);
 
     SCLogDebug("header_start %p, header_end %p, form_end %p", header_start,
@@ -1329,20 +1331,27 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud,
     tx_progress = AppLayerParserGetStateProgress(IPPROTO_TCP, ALPROTO_HTTP, tx, STREAM_TOSERVER);
     /* if we're in the file storage process, deal with that now */
     if (htud->tsflags & HTP_FILENAME_SET) {
-        if (header_start != NULL || form_end != NULL || (tx_progress > HTP_REQUEST_BODY)) {
+        if (header_start != NULL || (tx_progress > HTP_REQUEST_BODY)) {
             SCLogDebug("reached the end of the file");
 
             const uint8_t *filedata = chunks_buffer;
             uint32_t filedata_len = 0;
             uint8_t flags = 0;
 
-            if (header_start < form_end || (header_start != NULL && form_end == NULL)) {
-                filedata_len = header_start - filedata - 2; /* 0d 0a */
-            } else if (form_end != NULL && form_end < header_start) {
-                filedata_len = form_end - filedata;
-            } else if (form_end != NULL && form_end == header_start) {
-                filedata_len = form_end - filedata - 2; /* 0d 0a */
-            } else if (tx_progress > HTP_REQUEST_BODY) {
+            if (header_start != NULL) {
+                if (header_start == filedata + 2) {
+                    /* last chunk had all data, but not the boundary */
+                    SCLogDebug("last chunk had all data, but not the boundary");
+                    filedata_len = 0;
+                } else if (header_start > filedata + 2) {
+                    SCLogDebug("some data from last file before the boundary");
+                    /* some data from last file before the boundary */
+                    filedata_len = header_start - filedata - 2;
+                }
+            }
+            /* body parsing done, we did not get our form end. Use all data
+             * we still have and signal to files API we have an issue. */
+            if (tx_progress > HTP_REQUEST_BODY) {
                 filedata_len = chunks_buffer_len;
                 flags = FILE_TRUNCATED;
             }
@@ -1413,14 +1422,14 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud,
 
         uint32_t header_len = header_end - header_start;
         SCLogDebug("header_len %u", header_len);
-        uint8_t *header = header_start;
+        uint8_t *header = (uint8_t *)header_start;
 
         /* skip empty records */
         if (expected_boundary_len == header_len) {
             goto next;
         } else if ((uint32_t)(expected_boundary_len + 2) <= header_len) {
             header_len -= (expected_boundary_len + 2);
-            header = header_start + (expected_boundary_len + 2); // + for 0d 0a
+            header = (uint8_t *)header_start + (expected_boundary_len + 2); // + for 0d 0a
         }
 
         HtpRequestBodyMultipartParseHeader(hstate, htud, header, header_len,
@@ -1440,6 +1449,8 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud,
 
             /* everything until the final boundary is the file */
             if (form_end != NULL) {
+                SCLogDebug("have form_end");
+
                 filedata = header_end + 4;
                 if (form_end == filedata) {
                     HTPSetEvent(hstate, htud, STREAM_TOSERVER,
@@ -1507,23 +1518,27 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud,
                 PrintRawDataFp(stdout, filedata, filedata_len);
                 printf("FILEDATA END: \n");
 #endif
-                /* form doesn't end in this chunk, but part might. Lets
+                /* form doesn't end in this chunk, but the part might. Lets
                  * see if have another coming up */
                 uint8_t *header_next = Bs2bmSearch(filedata, filedata_len,
                         boundary, expected_boundary_len);
                 SCLogDebug("header_next %p", header_next);
                 if (header_next == NULL) {
-                    /* no, but we'll handle the file data when we see the
-                     * form_end */
-
                     SCLogDebug("more file data to come");
 
                     uint32_t offset = (header_end + 4) - chunks_buffer;
                     SCLogDebug("offset %u", offset);
                     htud->request_body.body_parsed += offset;
 
+                    if (filedata_len >= (uint32_t)(expected_boundary_len + 2)) {
+                        filedata_len -= (uint32_t)(expected_boundary_len + 2 - 1);
+                        SCLogDebug("opening file with partial data");
+                    } else {
+                        filedata = NULL;
+                        filedata_len = 0;
+                    }
                     result = HTPFileOpen(hstate, filename, filename_len,
-                            NULL, 0, HtpGetActiveRequestTxID(hstate),
+                            filedata, filedata_len, HtpGetActiveRequestTxID(hstate),
                             STREAM_TOSERVER);
                     if (result == -1) {
                         goto end;
@@ -1531,6 +1546,8 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud,
                         htud->tsflags |= HTP_DONTSTORE;
                     }
                     FlagDetectStateNewFile(htud, STREAM_TOSERVER);
+                    htud->request_body.body_parsed += filedata_len;
+                    SCLogDebug("htud->request_body.body_parsed %"PRIu64, htud->request_body.body_parsed);
 
                 } else if (header_next - filedata > 2) {
                     filedata_len = header_next - filedata - 2;