]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #5169: mime: partial header memory optimization using vectors to preallo...
authorAndres Avila Segura (aavilase) <aavilase@cisco.com>
Fri, 13 Mar 2026 12:05:52 +0000 (12:05 +0000)
committerChris Sherwin (chsherwi) <chsherwi@cisco.com>
Fri, 13 Mar 2026 12:05:52 +0000 (12:05 +0000)
Merge in SNORT/snort3 from ~AAVILASE/snort3:partial_header_memory_optimization to master

Squashed commit of the following:

commit 1765049b41acf70372173da2f0509fb177a15e41
Author: Andres Avila <aavilase@cisco.com>
Date:   Wed Feb 18 14:00:16 2026 -0500

    mime: partial header memory optimization using vectors to preallocate memory rather than allocating for every new chunk of header appended

src/mime/file_mime_process.cc
src/mime/file_mime_process.h

index 0d462a227bec819cdbd623fdf7ec4d89fbfe9f86..6fa08613d847b07881b5bffc03cebdd2117c53f7 100644 (file)
@@ -33,6 +33,7 @@
 #include "mime/file_mime_form_data.h"
 #include "search_engines/search_tool.h"
 #include "utils/util_cstring.h"
+#include <algorithm>
 
 using namespace snort;
 
@@ -192,35 +193,40 @@ const uint8_t* MimeSession::process_mime_header(Packet* p, const uint8_t* ptr,
         // Save partial header lines until we have the full line
         if (!found_end_marker)
         {
-            if (partial_header)
+            if (!partial_header.empty())
             {
                 // Single header line split into >2 sections, accumulate
-                // FIXIT-P: could allocate reasonable-size buf and only reallocate if needed
                 const uint32_t new_len = data_end_marker - ptr;
-                const uint32_t cum_len = partial_header_len + new_len;
-                uint8_t* tmp = new uint8_t[cum_len];
-                memcpy(tmp, partial_header, partial_header_len);
-                memcpy(tmp + partial_header_len, ptr, new_len);
-                delete[] partial_header;
-                partial_header_len = cum_len;
-                partial_header = tmp;
+                const uint32_t old_len = partial_header.size();
+                const uint32_t cum_len = old_len + new_len;
+                if (cum_len > MAX_MIME_HEADER_LEN)
+                {
+#ifdef REG_TEST
+                    LogMessage("partial header exceeds max size!");
+#endif
+                    partial_header.clear();
+                    partial_header.shrink_to_fit();
+                    return nullptr;
+                }
+                partial_header.resize(cum_len);
+                std::copy(ptr, data_end_marker, partial_header.begin() + old_len);
             }
             else
             {
-                partial_header_len = data_end_marker - ptr;
-                partial_header = new uint8_t[partial_header_len];
-                memcpy(partial_header, ptr, partial_header_len);
+                partial_header.resize(data_end_marker - ptr);
+                std::copy(ptr, data_end_marker, partial_header.begin());
             }
             return data_end_marker;
         }
-        if (partial_header)
+        if (!partial_header.empty())
         {
             const uint32_t remainder_header_len = eol - ptr;
-            const uint32_t full_header_len = partial_header_len + remainder_header_len;
-            const uint8_t* full_header = new uint8_t[full_header_len];
+            const uint32_t old_len = partial_header.size();
+            const uint32_t full_header_len = old_len + remainder_header_len;
+            partial_header.resize(full_header_len);
+            std::copy(ptr, ptr + remainder_header_len, partial_header.begin() + old_len);
+            const uint8_t* full_header = partial_header.data();
             const uint8_t* head_ptr = full_header;
-            memcpy((void*)full_header, partial_header, partial_header_len);
-            memcpy((void*)(full_header + partial_header_len), ptr, remainder_header_len);
             ptr = eol;
             // Update eol and eolm to point to full_header buffer. eol points to byte after end
             // marker and eolm points to start of the end marker - either \n or \r if CR precedes LF
@@ -232,10 +238,8 @@ const uint8_t* MimeSession::process_mime_header(Packet* p, const uint8_t* ptr,
 
             cont = process_header_line(head_ptr, eol, eolm, start_hdr, p);
 
-            delete[] partial_header;
-            partial_header = nullptr;
-            partial_header_len = 0;
-            delete[] full_header;
+            partial_header.clear();
+            partial_header.shrink_to_fit();
         }
         else
         {
@@ -725,10 +729,8 @@ void MimeSession::reset_part_state()
     state_flags = 0;
     attribute_state = ATTRIBUTE_NAME;
 
-    delete[] partial_header;
-    partial_header = nullptr;
-    partial_header_len = 0;
-
+    partial_header.clear();
+    partial_header.shrink_to_fit();
     delete[] partial_data;
     partial_data = nullptr;
     partial_data_len = 0;
@@ -974,7 +976,6 @@ MimeSession::MimeSession(Packet* p, const DecodeConfig* dconf, MailLogConfig* lc
 MimeSession::~MimeSession()
 {
     delete decode_state;
-    delete[] partial_header;
     delete[] partial_data;
     delete[] rebuilt_data;
 }
index b69d6c8070ed797c96fc9544cfcd00bb7d42fafe..e6366d8642c1ea3834d8a60c41f431e2ce8d9162 100644 (file)
@@ -23,7 +23,9 @@
 
 // Provides list of MIME processing functions. Encoded file data will be decoded
 // and file name will be extracted from MIME header
+#include <cstdint>
 #include <string>
+#include <vector>
 #include "file_api/file_api.h"
 #include "mime/file_mime_config.h"
 #include "mime/file_mime_decode.h"
@@ -48,6 +50,7 @@ namespace snort
 #define STATE_DATA_HEADER  1    /* Data header section of data state */
 #define STATE_DATA_BODY    2    /* Data body section of data state */
 #define STATE_MIME_HEADER  3    /* MIME header section within data section */
+#define MAX_MIME_HEADER_LEN 131072 /*Mime header cap to avoid endless header allocation*/
 
 enum AttributeState
 {
@@ -153,8 +156,7 @@ private:
     int extract_value(const char*& start, uint32_t length);
     int extract_attribute(const char*& start, int length, const char* attr);
 
-    uint8_t* partial_header = nullptr;      // single header line split into multiple sections
-    uint32_t partial_header_len = 0;
+    std::vector<uint8_t> partial_header;
     uint8_t* partial_data = nullptr;        // attachment's trailing bytes (suspected boundary)
     uint32_t partial_data_len = 0;
     uint8_t* rebuilt_data = nullptr;        // prepended attachment data for detection module