From 4f90d4254e5a897ddbf4fb8c3c1fabefe20b977e Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 6 Jan 2022 16:04:17 +0100 Subject: [PATCH] http2: makes some settings configurable max-streams and max-table-size Allows users to find balance between completeness of decoding and increases resource consumption, which can DOS suricata. --- rust/src/http2/http2.rs | 24 +++++++++++++++++++----- rust/src/http2/parser.rs | 2 +- suricata.yaml.in | 4 ++++ 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/rust/src/http2/http2.rs b/rust/src/http2/http2.rs index 7d9488519d..bf80379c2f 100644 --- a/rust/src/http2/http2.rs +++ b/rust/src/http2/http2.rs @@ -21,6 +21,7 @@ use super::parser; use super::range; use crate::applayer::{self, *}; +use crate::conf::conf_get; use crate::core::*; use crate::filecontainer::*; use crate::filetracker::*; @@ -58,9 +59,8 @@ 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 these configurable -pub const HTTP2_MAX_TABLESIZE: u32 = 0x10000; // 65536 -pub const HTTP2_MAX_STREAMS: usize = 0x1000; // 4096 +pub static mut HTTP2_MAX_TABLESIZE: u32 = 65536; // 0x10000 +static mut HTTP2_MAX_STREAMS: usize = 4096; // 0x1000 #[repr(u8)] #[derive(Copy, Clone, PartialOrd, PartialEq, Debug)] @@ -576,7 +576,7 @@ impl HTTP2State { 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 { + if self.transactions.len() > unsafe { 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 { @@ -656,7 +656,7 @@ impl HTTP2State { &mut self.dynamic_headers_tc }; dyn_headers.max_size = set[i].value as usize; - if set[i].value > HTTP2_MAX_TABLESIZE { + if set[i].value > unsafe { HTTP2_MAX_TABLESIZE } { //mark potential overflow dyn_headers.overflow = 1; } else { @@ -1224,6 +1224,20 @@ pub unsafe extern "C" fn rs_http2_register_parser() { if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { let _ = AppLayerRegisterParser(&parser, alproto); } + if let Some(val) = conf_get("app-layer.protocols.http2.max-streams") { + if let Ok(v) = val.parse::() { + HTTP2_MAX_STREAMS = v; + } else { + SCLogError!("Invalid value for http2.max-streams"); + } + } + if let Some(val) = conf_get("app-layer.protocols.http2.max-table-size") { + if let Ok(v) = val.parse::() { + HTTP2_MAX_TABLESIZE = v; + } else { + SCLogError!("Invalid value for http2.max-table-size"); + } + } SCLogDebug!("Rust http2 parser registered."); } else { SCLogNotice!("Protocol detector and parser disabled for HTTP2."); diff --git a/rust/src/http2/parser.rs b/rust/src/http2/parser.rs index a4edd84235..f768026547 100644 --- a/rust/src/http2/parser.rs +++ b/rust/src/http2/parser.rs @@ -445,7 +445,7 @@ fn http2_parse_headers_block_literal_incindex<'a>( //in case of overflow, best effort is to keep first headers if dyn_headers.overflow > 0 { if dyn_headers.overflow == 1 { - if dyn_headers.current_size <= (HTTP2_MAX_TABLESIZE as usize) { + if dyn_headers.current_size <= (unsafe { HTTP2_MAX_TABLESIZE } as usize) { //overflow had not yet happened dyn_headers.table.push(headcopy); } else if dyn_headers.current_size > dyn_headers.max_size { diff --git a/suricata.yaml.in b/suricata.yaml.in index d2a1f9f1e2..479087a0e0 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -833,6 +833,10 @@ app-layer: #hassh: yes http2: enabled: yes + # Maximum number of live HTTP2 streams in a flow + #max-streams: 4096 + # Maximum headers table size + #max-table-size: 65536 smtp: enabled: yes raw-extraction: no -- 2.47.2