]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
http2: limits the number of active transactions per flow
authorPhilippe Antoine <contact@catenacyber.fr>
Thu, 2 Dec 2021 08:54:05 +0000 (09:54 +0100)
committerVictor Julien <vjulien@oisf.net>
Tue, 1 Feb 2022 06:17:38 +0000 (07:17 +0100)
Ticket: 4530

So, that we do not get DOS by quadratic complexity, while
looking for a new stream id over the ever growing list
of active streams

rules/http2-events.rules
rust/src/http2/http2.rs

index 15b7eed51cca19eeba6053eb9d984fecbf6525c8..c7a88b0c2b8fd333653b2694ffe6d8b46255d2af 100644 (file)
@@ -17,3 +17,4 @@ alert http2 any any -> any any (msg:"SURICATA HTTP2 invalid HTTP1 settings durin
 alert http2 any any -> any any (msg:"SURICATA HTTP2 failed decompression"; flow:established; app-layer-event:http2.failed_decompression; classtype:protocol-command-decode; sid:2290009; rev:1;)
 alert http2 any any -> any any (msg:"SURICATA HTTP2 invalid range header"; flow:established; app-layer-event:http2.invalid_range; classtype:protocol-command-decode; sid:2290010; rev:1;)
 alert http2 any any -> any any (msg:"SURICATA HTTP2 variable-length integer overflow"; flow:established; app-layer-event:http2.header_integer_overflow; classtype:protocol-command-decode; sid:2290011; rev:1;)
+alert http2 any any -> any any (msg:"SURICATA HTTP2 too many streams"; flow:established; app-layer-event:http2.too_many_streams; classtype:protocol-command-decode; sid:2290012; rev:1;)
index def71d70e28c5b8357730133a4c9ab8f6acba2f4..7d9488519d4cd68cffc341b4577147b51faba83d 100644 (file)
@@ -58,8 +58,9 @@ const HTTP2_FRAME_GOAWAY_LEN: usize = 4;
 const HTTP2_FRAME_RSTSTREAM_LEN: usize = 4;
 const HTTP2_FRAME_PRIORITY_LEN: usize = 5;
 const HTTP2_FRAME_WINDOWUPDATE_LEN: usize = 4;
-//TODO make this configurable
+//TODO make these configurable
 pub const HTTP2_MAX_TABLESIZE: u32 = 0x10000; // 65536
+pub const HTTP2_MAX_STREAMS: usize = 0x1000; // 4096
 
 #[repr(u8)]
 #[derive(Copy, Clone, PartialOrd, PartialEq, Debug)]
@@ -110,6 +111,8 @@ pub enum HTTP2TransactionState {
     HTTP2StateClosed = 7,
     //not a RFC-defined state, used for stream 0 frames appyling to the global connection
     HTTP2StateGlobal = 8,
+    //not a RFC-defined state, dropping this old tx because we have too many
+    HTTP2StateTodrop = 9,
 }
 
 #[derive(Debug)]
@@ -367,6 +370,7 @@ pub enum HTTP2Event {
     FailedDecompression,
     InvalidRange,
     HeaderIntegerOverflow,
+    TooManyStreams,
 }
 
 pub struct HTTP2DynTable {
@@ -571,6 +575,18 @@ impl HTTP2State {
             tx.tx_id = self.tx_id;
             tx.stream_id = sid;
             tx.state = HTTP2TransactionState::HTTP2StateOpen;
+            // do not use SETTINGS_MAX_CONCURRENT_STREAMS as it can grow too much
+            if self.transactions.len() > HTTP2_MAX_STREAMS {
+                // set at least one another transaction to the drop state
+                for tx_old in &mut self.transactions {
+                    if tx_old.state != HTTP2TransactionState::HTTP2StateTodrop {
+                        // use a distinct state, even if we do not log it
+                        tx_old.set_event(HTTP2Event::TooManyStreams);
+                        tx_old.state = HTTP2TransactionState::HTTP2StateTodrop;
+                        break;
+                    }
+                }
+            }
             self.transactions.push(tx);
             return self.transactions.last_mut().unwrap();
         }