]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2654 in SNORT/snort3 from ~KATHARVE/snort3:http_mem to master
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Mon, 14 Dec 2020 21:18:29 +0000 (21:18 +0000)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Mon, 14 Dec 2020 21:18:29 +0000 (21:18 +0000)
Squashed commit of the following:

commit 1d1ae0a0c472fd241db960b3463c451271d5bdd5
Author: Katura Harvey <katharve@cisco.com>
Date:   Thu Dec 3 12:34:01 2020 -0500

    http_inspect: explicit memory allocation for transactions and partial inspections

16 files changed:
src/service_inspectors/http2_inspect/http2_flow_data.cc
src/service_inspectors/http2_inspect/http2_flow_data.h
src/service_inspectors/http2_inspect/http2_stream.cc
src/service_inspectors/http_inspect/http_enum.h
src/service_inspectors/http_inspect/http_flow_data.cc
src/service_inspectors/http_inspect/http_flow_data.h
src/service_inspectors/http_inspect/http_msg_body.cc
src/service_inspectors/http_inspect/http_msg_head_shared.cc
src/service_inspectors/http_inspect/http_msg_head_shared.h
src/service_inspectors/http_inspect/http_msg_start.cc
src/service_inspectors/http_inspect/http_msg_start.h
src/service_inspectors/http_inspect/http_stream_splitter_reassemble.cc
src/service_inspectors/http_inspect/http_tables.cc
src/service_inspectors/http_inspect/http_transaction.cc
src/service_inspectors/http_inspect/http_transaction.h
src/service_inspectors/http_inspect/test/http_transaction_test.cc

index c766a12b3da83cf4b5faee1c5ce730148ae2e3b3..e202b207911477eaadb9af9f11f1c522fdd39ed0 100644 (file)
@@ -170,14 +170,14 @@ uint32_t Http2FlowData::get_current_stream_id(const HttpCommon::SourceId source_
     return current_stream[source_id];
 }
 
-void Http2FlowData::allocate_hi_memory()
+void Http2FlowData::allocate_hi_memory(HttpFlowData* hi_flow_data)
 {
-    update_allocations(HttpFlowData::get_memory_usage_estimate());
+    update_allocations(hi_flow_data->size_of());
 }
 
-void Http2FlowData::deallocate_hi_memory()
+void Http2FlowData::deallocate_hi_memory(HttpFlowData* hi_flow_data)
 {
-    update_deallocations(HttpFlowData::get_memory_usage_estimate());
+    update_deallocations(hi_flow_data->size_of());
 }
 
 bool Http2FlowData::is_mid_frame() const
index 2b2758eae4b2c119debf4fd94eb6fd66c0a87946..932dcf2ac086b73c468236dc0485cd0c4a6636c9 100644 (file)
@@ -199,8 +199,8 @@ private:
 
     // When H2I allocates http_inspect flows, it bypasses the usual FlowData memory allocation
     // bookkeeping. So H2I needs to update memory allocations and deallocations itself.
-    void allocate_hi_memory();
-    void deallocate_hi_memory();
+    void allocate_hi_memory(HttpFlowData* hi_flow_data);
+    void deallocate_hi_memory(HttpFlowData* hi_flow_data);
 };
 
 #endif
index 5aed057ecc4a7c68c2d29dc7ec0972d7e958a7da..26b197a52e7f6a48d42a633293476da8bc80abfc 100644 (file)
@@ -46,7 +46,7 @@ Http2Stream::~Http2Stream()
 {
     delete current_frame;
     if (hi_flow_data)
-        session_data->deallocate_hi_memory();
+        session_data->deallocate_hi_memory(hi_flow_data);
     delete hi_flow_data;
 }
 
@@ -80,9 +80,9 @@ void Http2Stream::clear_frame()
     if ((state[SRC_CLIENT] >= STREAM_COMPLETE) && (state[SRC_SERVER] >= STREAM_COMPLETE) &&
         (hi_flow_data != nullptr))
     {
+        session_data->deallocate_hi_memory(hi_flow_data);
         delete hi_flow_data;
         hi_flow_data = nullptr;
-        session_data->deallocate_hi_memory();
     }
 }
 
@@ -99,7 +99,7 @@ void Http2Stream::set_hi_flow_data(HttpFlowData* flow_data)
 {
     assert(hi_flow_data == nullptr);
     hi_flow_data = flow_data;
-    session_data->allocate_hi_memory();
+    session_data->allocate_hi_memory(hi_flow_data);
 }
 
 const Field& Http2Stream::get_buf(unsigned id)
index e8523bb409743fe112b304241e9d0c1f8fac1904..c1202247b648a52c77b0413b21a23a137174bfcd 100755 (executable)
@@ -62,7 +62,7 @@ enum PEG_COUNT { PEG_FLOW = 0, PEG_SCAN, PEG_REASSEMBLE, PEG_INSPECT, PEG_REQUES
     PEG_OTHER_METHOD, PEG_REQUEST_BODY, PEG_CHUNKED, PEG_URI_NORM, PEG_URI_PATH, PEG_URI_CODING,
     PEG_CONCURRENT_SESSIONS, PEG_MAX_CONCURRENT_SESSIONS, PEG_DETAINED, PEG_SCRIPT_DETECTION,
     PEG_PARTIAL_INSPECT, PEG_EXCESS_PARAMS, PEG_PARAMS, PEG_CUTOVERS, PEG_SSL_SEARCH_ABND_EARLY,
-    PEG_COUNT_MAX };
+    PEG_PIPELINED_FLOWS, PEG_PIPELINED_REQUESTS, PEG_COUNT_MAX };
 
 // Result of scanning by splitter
 enum ScanResult { SCAN_NOT_FOUND, SCAN_NOT_FOUND_ACCELERATE, SCAN_FOUND, SCAN_FOUND_PIECE,
index f505e02dc3437f5d1d019586859af1e911a665bd..12ea0ff2f3f580f080a007f05fc774fa742bef89 100644 (file)
@@ -46,10 +46,6 @@ unsigned HttpFlowData::inspector_id = 0;
 uint64_t HttpFlowData::instance_count = 0;
 #endif
 
-const uint16_t HttpFlowData::memory_usage_estimate = sizeof(HttpFlowData) + sizeof(HttpTransaction)
-    + sizeof(HttpMsgRequest) + sizeof(HttpMsgStatus) + (2 * sizeof(HttpMsgHeader)) + sizeof(HttpUri)
-    + header_size_estimate + small_things;
-
 HttpFlowData::HttpFlowData() : FlowData(inspector_id)
 {
 #ifdef REG_TEST
@@ -89,7 +85,9 @@ HttpFlowData::~HttpFlowData()
         delete events[k];
         delete[] section_buffer[k];
         delete[] partial_buffer[k];
+        update_deallocations(partial_buffer_length[k]);
         delete[] partial_detect_buffer[k];
+        update_deallocations(partial_detect_length[k]);
         HttpTransaction::delete_transaction(transaction[k], nullptr);
         delete cutter[k];
         if (compress_stream[k] != nullptr)
@@ -116,6 +114,11 @@ HttpFlowData::~HttpFlowData()
     }
 }
 
+size_t HttpFlowData::size_of()
+{
+    return sizeof(HttpFlowData) + (2 * sizeof(HttpEventGen));
+}
+
 void HttpFlowData::half_reset(SourceId source_id)
 {
     assert((source_id == SRC_CLIENT) || (source_id == SRC_SERVER));
@@ -206,6 +209,7 @@ bool HttpFlowData::add_to_pipeline(HttpTransaction* latest)
     if (pipeline == nullptr)
     {
         pipeline = new HttpTransaction*[MAX_PIPELINE];
+        HttpModule::increment_peg_counts(PEG_PIPELINED_FLOWS);
     }
     assert(!pipeline_overflow && !pipeline_underflow);
     int new_back = (pipeline_back+1) % MAX_PIPELINE;
@@ -216,6 +220,7 @@ bool HttpFlowData::add_to_pipeline(HttpTransaction* latest)
     }
     pipeline[pipeline_back] = latest;
     pipeline_back = new_back;
+    HttpModule::increment_peg_counts(PEG_PIPELINED_REQUESTS);
     return true;
 }
 
@@ -249,11 +254,6 @@ HttpInfractions* HttpFlowData::get_infractions(SourceId source_id)
     return transaction[source_id]->get_infractions(source_id);
 }
 
-uint16_t HttpFlowData::get_memory_usage_estimate()
-{
-    return memory_usage_estimate;
-}
-
 void HttpFlowData::finish_h2_body(HttpCommon::SourceId source_id, HttpEnums::H2BodyState state,
     bool clear_partial_buffer)
 {
@@ -264,14 +264,18 @@ void HttpFlowData::finish_h2_body(HttpCommon::SourceId source_id, HttpEnums::H2B
     {
         // We've already sent all data through detection so no need to reinspect. Just need to
         // prep for trailers
+        update_deallocations(partial_buffer_length[source_id]);
         partial_buffer_length[source_id] = 0;
         delete[] partial_buffer[source_id];
         partial_buffer[source_id] = nullptr;
-        body_octets[source_id] += partial_inspected_octets[source_id];
-        partial_inspected_octets[source_id] = 0;
+
+        update_deallocations(partial_detect_length[source_id]);
         partial_detect_length[source_id] = 0;
         delete[] partial_detect_buffer[source_id];
         partial_detect_buffer[source_id] = nullptr;
+
+        body_octets[source_id] += partial_inspected_octets[source_id];
+        partial_inspected_octets[source_id] = 0;
     }
 }
 
index a88aa3a91554686b2dd9004655a4a7403a8756e4..8f8ef970e6b8c996d2580f055e30b92c6be3fd3e 100644 (file)
@@ -46,7 +46,7 @@ public:
     ~HttpFlowData() override;
     static unsigned inspector_id;
     static void init() { inspector_id = snort::FlowData::create_flow_data_id(); }
-    size_t size_of() override { return sizeof(*this); }
+    size_t size_of() override;
 
     friend class HttpInspect;
     friend class HttpMsgSection;
@@ -77,8 +77,6 @@ public:
     void reset_partial_flush(HttpCommon::SourceId source_id)
     { partial_flush[source_id] = false; }
 
-    static uint16_t get_memory_usage_estimate();
-
 private:
     // HTTP/2 handling
     bool for_http2 = false;
@@ -192,12 +190,6 @@ private:
     // Transactions with uncleared sections awaiting deletion
     HttpTransaction* discard_list = nullptr;
 
-    // Estimates of how much memory http_inspect uses to process a stream for H2I
-    static const uint16_t header_size_estimate = 3000;  // combined raw size of request and
-                                                        //response message headers
-    static const uint16_t small_things = 400; // minor memory costs not otherwise accounted for
-    static const uint16_t memory_usage_estimate;
-
 #ifdef REG_TEST
     static uint64_t instance_count;
     uint64_t seq_num;
index f19395fe04a2b4dbbdf2d5f74f6f7695a7e19467..253dab51ec1d9cc298928aaf06da931af8d7aba5 100644 (file)
@@ -92,6 +92,7 @@ void HttpMsgBody::analyze()
         }
 
         delete[] partial_detect_buffer;
+        session_data->update_deallocations(partial_detect_length);
 
         if (!session_data->partial_flush[source_id])
         {
@@ -105,6 +106,7 @@ void HttpMsgBody::analyze()
             memcpy(save_partial, detect_data.start(), detect_data.length());
             partial_detect_buffer = save_partial;
             partial_detect_length = detect_data.length();
+            session_data->update_allocations(partial_detect_length);
         }
 
         set_file_data(const_cast<uint8_t*>(detect_data.start()),
index 002407053e914124045817ccbbd0f0b0b567ce71..8bf81aefd254779062767bdadcbbe7a78e6cf794 100755 (executable)
@@ -34,6 +34,15 @@ using namespace HttpCommon;
 using namespace HttpEnums;
 using namespace snort;
 
+HttpMsgHeadShared::HttpMsgHeadShared(const uint8_t* buffer, const uint16_t buf_size, HttpFlowData* session_data_,
+    HttpCommon::SourceId source_id_, bool buf_owner, snort::Flow* flow_,
+    const HttpParaList* params_): HttpMsgSection(buffer, buf_size, session_data_, source_id_,
+    buf_owner, flow_, params_), own_msg_buffer(buf_owner)
+{
+    if (own_msg_buffer)
+        session_data->update_allocations(msg_text.length());
+}
+
 HttpMsgHeadShared::~HttpMsgHeadShared()
 {
     delete[] header_line;
@@ -47,6 +56,9 @@ HttpMsgHeadShared::~HttpMsgHeadShared()
         list_ptr = list_ptr->next;
         delete temp_ptr;
     }
+
+    if (own_msg_buffer)
+        session_data->update_deallocations(msg_text.length());
 }
 
 // All the header processing that is done for every message (i.e. not just-in-time) is done here.
index fe06b4d968629cdccf4c115e1bfdff95aba456d2..8b3ba4ef6e0b1208740e14fad161893a0633bd63 100755 (executable)
@@ -60,9 +60,7 @@ public:
 protected:
     HttpMsgHeadShared(const uint8_t* buffer, const uint16_t buf_size,
         HttpFlowData* session_data_, HttpCommon::SourceId source_id_, bool buf_owner, snort::Flow* flow_,
-        const HttpParaList* params_)
-        : HttpMsgSection(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_)
-        { }
+        const HttpParaList* params_);
     ~HttpMsgHeadShared() override;
     // Get the next item in a comma-separated header value and convert it to an enum value
     static int32_t get_next_code(const Field& field, int32_t& offset, const StrCode table[]);
@@ -130,6 +128,8 @@ private:
     Field content_disposition_filename;
     uint64_t file_cache_index = 0;
     bool file_cache_index_computed = false;
+
+    bool own_msg_buffer;
 };
 
 #endif
index 276a6b7818ab4321dd846e4f24225961661ac754..06f9621c03f98f2be8348026d423518325c91133 100644 (file)
 
 using namespace HttpEnums;
 
+HttpMsgStart::HttpMsgStart(const uint8_t* buffer, const uint16_t buf_size, HttpFlowData* session_data_,
+    HttpCommon::SourceId source_id_, bool buf_owner, snort::Flow* flow_,
+    const HttpParaList* params_) : HttpMsgSection(buffer, buf_size, session_data_, source_id_,
+    buf_owner, flow_, params_), own_msg_buffer(buf_owner)
+{
+    if (own_msg_buffer)
+        session_data->update_allocations(msg_text.length());
+}
+
+HttpMsgStart::~HttpMsgStart()
+{
+    if (own_msg_buffer)
+        session_data->update_deallocations(msg_text.length());
+}
+
 void HttpMsgStart::analyze()
 {
     start_line.set(msg_text);
index 124b74f0ea30f1b967f5fbf65d39847377b1e2e9..a265dec7f4eec211ff078ca26b6b6d71467fe862 100644 (file)
@@ -38,14 +38,14 @@ public:
 protected:
     HttpMsgStart(const uint8_t* buffer, const uint16_t buf_size, HttpFlowData* session_data_,
         HttpCommon::SourceId source_id_, bool buf_owner, snort::Flow* flow_,
-        const HttpParaList* params_)
-        : HttpMsgSection(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_)
-        { }
+        const HttpParaList* params_);
+    ~HttpMsgStart() override;
     virtual void parse_start_line() = 0;
     void derive_version_id();
 
     Field start_line;
     Field version;
+    bool own_msg_buffer;
 };
 
 #endif
index 478dab8bf7d04d9103a10111a0b639b4b5924a5b..a0c46cc785628f58f31410b0b6c0ab010da18350 100644 (file)
@@ -386,8 +386,9 @@ const StreamBuffer HttpStreamSplitter::reassemble(Flow* flow, unsigned total,
         assert(session_data->section_offset[source_id] == 0);
         memcpy(buffer, partial_buffer, partial_buffer_length);
         session_data->section_offset[source_id] = partial_buffer_length;
-        partial_buffer_length = 0;
         delete[] partial_buffer;
+        session_data->update_deallocations(partial_buffer_length);
+        partial_buffer_length = 0;
         partial_buffer = nullptr;
     }
 
@@ -420,6 +421,7 @@ const StreamBuffer HttpStreamSplitter::reassemble(Flow* flow, unsigned total,
             memcpy(partial_buffer, buffer, buf_size);
             partial_buffer_length = buf_size;
             partial_raw_bytes += total;
+            session_data->update_allocations(partial_buffer_length);
         }
         else
             partial_raw_bytes = 0;
index 683e82c4d376baf31bf7075fdf922e9611f99c3c..1ba2d16e1e9dce6a8a14aaf951793d2c5ad2476a 100755 (executable)
@@ -438,6 +438,8 @@ const PegInfo HttpModule::peg_names[PEG_COUNT_MAX+1] =
     { CountType::SUM, "parameters", "HTTP parameters inspected" },
     { CountType::SUM, "connect_tunnel_cutovers", "CONNECT tunnel flow cutovers to wizard" },
     { CountType::SUM, "ssl_srch_abandoned_early", "total SSL search abandoned too soon" },
+    { CountType::SUM, "pipelined_flows", "total HTTP connections containing pipelined requests" },
+    { CountType::SUM, "pipelined_requests", "total requests placed in a pipeline" },
     { CountType::END, nullptr, nullptr }
 };
 
index e31e6f4a79ebbfbf5c74a35800aaf059e3431305..dec0f2f5544b270096ee1d51c5da303b905eacec 100644 (file)
@@ -36,6 +36,10 @@ using namespace HttpCommon;
 using namespace HttpEnums;
 using namespace snort;
 
+const uint16_t HttpTransaction::transaction_memory_usage_estimate = sizeof(HttpTransaction) +
+    sizeof(HttpMsgRequest) + sizeof(HttpMsgStatus) + (2 * sizeof(HttpMsgHeader)) + sizeof(HttpUri)
+    + (2 * sizeof(HttpInfractions)) + small_things;
+
 static void delete_section_list(HttpMsgSection* section_list)
 {
     while (section_list != nullptr)
@@ -46,6 +50,13 @@ static void delete_section_list(HttpMsgSection* section_list)
     }
 }
 
+HttpTransaction::HttpTransaction(HttpFlowData* session_data_): session_data(session_data_)
+{
+    infractions[0] = nullptr;
+    infractions[1] = nullptr;
+    session_data->update_allocations(transaction_memory_usage_estimate);
+}
+
 HttpTransaction::~HttpTransaction()
 {
     delete request;
@@ -58,6 +69,7 @@ HttpTransaction::~HttpTransaction()
     }
     delete_section_list(body_list);
     delete_section_list(discard_list);
+    session_data->update_deallocations(transaction_memory_usage_estimate);
 }
 
 HttpTransaction* HttpTransaction::attach_my_transaction(HttpFlowData* session_data, SourceId
index aa9fc19aaa428833095f4db2cb980ab087faa6d6..df9457b8687c206b0f9ff9b3f929ca38d95fc986 100644 (file)
@@ -69,11 +69,7 @@ public:
     HttpTransaction* next = nullptr;
 
 private:
-    HttpTransaction(HttpFlowData* session_data_) : session_data(session_data_)
-    {
-        infractions[0] = nullptr;
-        infractions[1] = nullptr;
-    }
+    HttpTransaction(HttpFlowData* session_data_);
     void discard_section(HttpMsgSection* section);
 
     HttpFlowData* const session_data;
@@ -96,6 +92,10 @@ private:
     // transaction in the fairly rare case where the request and response are received in
     // parallel.
     bool shared_ownership = false;
+
+    // Estimates of how much memory http_inspect uses to process a transaction
+    static const uint16_t small_things = 400; // minor memory costs not otherwise accounted for
+    static const uint16_t transaction_memory_usage_estimate;
 };
 
 #endif
index 85ae1e6007e2b5b68eda9489259d25b119e4b354..f6dd73685a393813f29b1222fe0c6179e090e554 100644 (file)
@@ -46,6 +46,8 @@ FlowData::~FlowData() = default;
 int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; }
 fd_status_t File_Decomp_StopFree(fd_session_t*) { return File_Decomp_OK; }
 uint32_t str_to_hash(const uint8_t *, size_t) { return 0; }
+void FlowData::update_allocations(unsigned long) {}
+void FlowData::update_deallocations(unsigned long) {}
 }
 
 THREAD_LOCAL PegCount HttpModule::peg_counts[PEG_COUNT_MAX] = { };