]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2721 in SNORT/snort3 from ~KATHARVE/snort3:h2i_stream_limit to...
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Fri, 29 Jan 2021 16:27:13 +0000 (16:27 +0000)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Fri, 29 Jan 2021 16:27:13 +0000 (16:27 +0000)
Squashed commit of the following:

commit 8dc19216a06d0e2b18fc4f02aabc4b2955e2e65e
Author: Katura Harvey <katharve@cisco.com>
Date:   Fri Jan 22 14:46:34 2021 -0500

    http2_inspect: limit number of concurrent streams

src/service_inspectors/http2_inspect/http2_data_frame.cc
src/service_inspectors/http2_inspect/http2_enum.h
src/service_inspectors/http2_inspect/http2_flow_data.h
src/service_inspectors/http2_inspect/http2_headers_frame_with_startline.cc
src/service_inspectors/http2_inspect/http2_push_promise_frame.cc
src/service_inspectors/http2_inspect/http2_stream.cc
src/service_inspectors/http2_inspect/http2_tables.cc

index f0b8c487a6d6f66a02f949119656a30aa999a274..0fbf844d8fed2b04e7e43fccc419c53c16dddc87 100644 (file)
@@ -85,7 +85,11 @@ void Http2DataFrame::update_stream_state()
                 }
             }
             if (stream->is_end_stream_on_data_flush(source_id))
+            {
+                if (data_length > 0)
+                    session_data->concurrent_files -= 1;
                 stream->set_state(source_id, STREAM_COMPLETE);
+            }
             break;
         case STREAM_BODY:
             if (stream->is_end_stream_on_data_flush(source_id))
index 64c5b8632cb7a24e87f95af6ace6d15386ba614d..d2c57bb64225ec4802b538377230b8d41f535834 100644 (file)
@@ -28,6 +28,7 @@ static const int MAX_OCTETS = 63780;
 static const int DATA_SECTION_SIZE = 16384;
 static const int FRAME_HEADER_LENGTH = 9;
 static const uint32_t NO_STREAM_ID = 0xFFFFFFFF;
+static const uint32_t CONCURRENT_STREAMS_LIMIT = 100;
 
 static const uint32_t HTTP2_GID = 121;
 
@@ -48,8 +49,8 @@ enum HTTP2_BUFFER { HTTP2_BUFFER_FRAME_HEADER = 1, HTTP2_BUFFER_FRAME_DATA,
 // Peg counts
 // This enum must remain synchronized with Http2Module::peg_names[] in http2_tables.cc
 enum PEG_COUNT { PEG_FLOW = 0, PEG_CONCURRENT_SESSIONS, PEG_MAX_CONCURRENT_SESSIONS,
-    PEG_MAX_TABLE_ENTRIES, PEG_MAX_CONCURRENT_FILES, PEG_TOTAL_BYTES,
-    PEG_COUNT__MAX };
+    PEG_MAX_TABLE_ENTRIES, PEG_MAX_CONCURRENT_FILES, PEG_TOTAL_BYTES, PEG_MAX_CONCURRENT_STREAMS,
+    PEG_FLOWS_OVER_STREAM_LIMIT, PEG_COUNT__MAX };
 
 enum EventSid
 {
@@ -80,6 +81,7 @@ enum EventSid
     EVENT_INVALID_PUSH_FRAME = 24,
     EVENT_BAD_PUSH_SEQUENCE = 25,
     EVENT_BAD_SETTINGS_VALUE = 26,
+    EVENT_TOO_MANY_STREAMS = 27,
     EVENT__MAX_VALUE
 };
 
@@ -129,6 +131,7 @@ enum Infraction
     INF_TRUNCATED_HEADER_LINE = 39,
     INF_REQUEST_WITHOUT_METHOD = 40,
     INF_CONNECT_WITHOUT_AUTHORITY = 41,
+    INF_TOO_MANY_STREAMS = 42,
     INF__MAX_VALUE
 };
 
index a7e9c7baaa69f35cbd654b13fab960824e5c0d4e..49e63da5343573569e6d1ee5e52885038cee407c 100644 (file)
@@ -161,6 +161,7 @@ protected:
     Http2HpackDecoder hpack_decoder[2];
     std::list<class StreamInfo> streams;
     uint32_t concurrent_files = 0;
+    uint32_t concurrent_streams = 0;
 
     // Internal to scan()
     bool preface[2] = { true, false };
index 5ce237eb4ade7bea31143b242af5a727fd5dce80..f4a3a4778adba22959ac8a2bd0abf5f1df56949d 100644 (file)
@@ -33,6 +33,7 @@
 #include "http2_enum.h"
 #include "http2_flow_data.h"
 #include "http2_hpack.h"
+#include "http2_module.h"
 #include "http2_request_line.h"
 #include "http2_start_line.h"
 #include "http2_status_line.h"
@@ -42,7 +43,6 @@ using namespace snort;
 using namespace HttpCommon;
 using namespace Http2Enums;
 
-
 Http2HeadersFrameWithStartline::~Http2HeadersFrameWithStartline()
 {
     delete start_line_generator;
@@ -54,6 +54,31 @@ bool Http2HeadersFrameWithStartline::process_start_line(HttpFlowData*& http_flow
     if (session_data->abort_flow[source_id])
         return false;
 
+    if (!stream->get_hi_flow_data())
+    {
+        if (session_data->concurrent_streams < CONCURRENT_STREAMS_LIMIT)
+        {
+            session_data->concurrent_streams += 1;
+            if (session_data->concurrent_streams >
+                Http2Module::get_peg_counts(PEG_MAX_CONCURRENT_STREAMS))
+
+            {
+                Http2Module::increment_peg_counts(PEG_MAX_CONCURRENT_STREAMS);
+            }
+        }
+        else
+        {
+            *session_data->infractions[source_id] += INF_TOO_MANY_STREAMS;
+            session_data->events[source_id]->create_event(EVENT_TOO_MANY_STREAMS);
+            Http2Module::increment_peg_counts(PEG_FLOWS_OVER_STREAM_LIMIT);
+            session_data->abort_flow[SRC_CLIENT] = true;
+            session_data->abort_flow[SRC_SERVER] = true;
+            stream->set_state(SRC_CLIENT, STREAM_ERROR);
+            stream->set_state(SRC_SERVER, STREAM_ERROR);
+            return false;
+        }
+    }
+
     // http_inspect scan() of start line
     {
         uint32_t flush_offset;
index 81a6ce47c6993d9a16b0b7b01ea6e3f3b716a153..90da5d7421ebb5452b50e5227c5cccf191f7c251 100644 (file)
@@ -135,7 +135,8 @@ void Http2PushPromiseFrame::update_stream_state()
     if (stream->get_state(SRC_CLIENT) == STREAM_EXPECT_HEADERS)
         stream->set_state(SRC_CLIENT, STREAM_COMPLETE);
 
-    assert(stream->get_state(SRC_SERVER) == STREAM_EXPECT_HEADERS);
+    assert(stream->get_state(SRC_SERVER) == STREAM_EXPECT_HEADERS or
+        stream->get_state(SRC_SERVER) == STREAM_ERROR);
     assert((stream->get_state(SRC_CLIENT) == STREAM_COMPLETE) or
         (stream->get_state(SRC_CLIENT) == STREAM_ERROR));
 }
index 0a1575fb23910d5e00833a02099b2e9cc6e643cd..a41c5c2d98d5dbef5e04052048145080ff4fac27 100644 (file)
@@ -83,6 +83,9 @@ void Http2Stream::clear_frame()
         session_data->deallocate_hi_memory(hi_flow_data);
         delete hi_flow_data;
         hi_flow_data = nullptr;
+
+        assert(session_data->concurrent_streams > 0);
+        session_data->concurrent_streams -= 1;
     }
 }
 
index 5dfd7df6c9d54acb91d3403a36fde37e0d774384..8f7186b0a08ef651e637295673d58e1dc13b967d 100644 (file)
@@ -57,6 +57,7 @@ const RuleMap Http2Module::http2_events[] =
     { EVENT_INVALID_PUSH_FRAME, "invalid HTTP/2 push promise frame" },
     { EVENT_BAD_PUSH_SEQUENCE, "HTTP/2 push promise frame sent at invalid time" },
     { EVENT_BAD_SETTINGS_VALUE, "invalid parameter value sent in HTTP/2 settings frame" },
+    { EVENT_TOO_MANY_STREAMS, "excessive concurrent HTTP/2 streams" },
     { 0, nullptr }
 };
 
@@ -69,6 +70,9 @@ const PegInfo Http2Module::peg_names[PEG_COUNT__MAX+1] =
     { CountType::MAX, "max_concurrent_files", "maximum concurrent file transfers per HTTP/2 "
         "connection" },
     { CountType::SUM, "total_bytes", "total HTTP/2 data bytes inspected" },
+    { CountType::MAX, "max_concurrent_streams", "maximum concurrent streams per HTTP/2 "
+        "connection" },
+    { CountType::SUM, "flows_over_stream_limit", "HTTP/2 flows exceeding 100 concurrent streams" },
     { CountType::END, nullptr, nullptr }
 };