From: Victor Julien Date: Thu, 24 Oct 2024 12:26:41 +0000 (+0200) Subject: smb: use lru for ssn2tree; rename X-Git-Tag: suricata-8.0.0-beta1~719 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0f23557ef7c1e27e85fc48a873b01322000ea4d6;p=thirdparty%2Fsuricata.git smb: use lru for ssn2tree; rename Turn the map mapping the smb session key to smb tree into a lru cache, limited to 1024 by default. Add `app-layer.protocols.smb.max-tree-cache-size` option to control the limit. Ticket: #5672. --- diff --git a/rust/src/smb/debug.rs b/rust/src/smb/debug.rs index e945de286e..d4b28cb232 100644 --- a/rust/src/smb/debug.rs +++ b/rust/src/smb/debug.rs @@ -69,11 +69,11 @@ impl SMBState { #[cfg(feature = "debug")] pub fn _debug_state_stats(&self) { - SCLogDebug!("ssn2vec_map {} guid2name_cache {} read_offset_cache {} ssn2tree_map {} ssnguid2vec_map {} file_ts_guid {} file_tc_guid {} transactions {}", + SCLogDebug!("ssn2vec_map {} guid2name_cache {} read_offset_cache {} ssn2tree_cache {} ssnguid2vec_map {} file_ts_guid {} file_tc_guid {} transactions {}", self.ssn2vec_map.len(), self.guid2name_cache.len(), self.read_offset_cache.len(), - self.ssn2tree_map.len(), + self.ssn2tree_cache.len(), self.ssnguid2vec_map.len(), self.file_ts_guid.len(), self.file_tc_guid.len(), diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index 3ef84a3552..d195001daa 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -86,6 +86,8 @@ pub static mut SMB_CFG_MAX_WRITE_QUEUE_CNT: u32 = 64; pub static mut SMB_CFG_MAX_GUID_CACHE_SIZE: usize = 1024; /// SMBState::read_offset_cache pub static mut SMB_CFG_MAX_READ_OFFSET_CACHE_SIZE: usize = 128; +/// For SMBState::ssn2tree_cache +pub static mut SMB_CFG_MAX_TREE_CACHE_SIZE: usize = 512; static mut ALPROTO_SMB: AppProto = ALPROTO_UNKNOWN; @@ -707,8 +709,8 @@ pub struct SMBState<> { /// map ssn key to read offset pub read_offset_cache: LruCache, - - pub ssn2tree_map: HashMap, + /// Map session key to SMBTree + pub ssn2tree_cache: LruCache, // store partial data records that are transferred in multiple // requests for DCERPC. @@ -784,7 +786,7 @@ impl SMBState { ssn2vec_map:HashMap::new(), guid2name_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_GUID_CACHE_SIZE }).unwrap()), read_offset_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_READ_OFFSET_CACHE_SIZE }).unwrap()), - ssn2tree_map:HashMap::new(), + ssn2tree_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_TREE_CACHE_SIZE }).unwrap()), ssnguid2vec_map:HashMap::new(), skip_ts:0, skip_tc:0, @@ -1302,7 +1304,7 @@ impl SMBState { // if complete. let tree_key = SMBCommonHdr::new(SMBHDR_TYPE_SHARE, r.ssn_id as u64, r.tree_id as u32, 0); - let is_pipe = match self.ssn2tree_map.get(&tree_key) { + let is_pipe = match self.ssn2tree_cache.get(&tree_key) { Some(n) => n.is_pipe, None => false, }; @@ -1638,7 +1640,7 @@ impl SMBState { if r.command == SMB1_COMMAND_READ_ANDX { let tree_key = SMBCommonHdr::new(SMBHDR_TYPE_SHARE, r.ssn_id as u64, r.tree_id as u32, 0); - let is_pipe = match self.ssn2tree_map.get(&tree_key) { + let is_pipe = match self.ssn2tree_cache.get(&tree_key) { Some(n) => n.is_pipe, None => false, }; @@ -2469,6 +2471,18 @@ pub unsafe extern "C" fn rs_smb_register_parser() { SCLogError!("Invalid max-read-offset-cache-size value"); } } + let retval = conf_get("app-layer.protocols.smb.max-tree-cache-size"); + if let Some(val) = retval { + if let Ok(v) = val.parse::() { + if v > 0 { + SMB_CFG_MAX_TREE_CACHE_SIZE = v; + } else { + SCLogError!("Invalid max-tree-cache-size value"); + } + } else { + SCLogError!("Invalid max-tree-cache-size value"); + } + } SCLogConfig!("read: max record size: {}, max queued chunks {}, max queued size {}", SMB_CFG_MAX_READ_SIZE, SMB_CFG_MAX_READ_QUEUE_CNT, SMB_CFG_MAX_READ_QUEUE_SIZE); SCLogConfig!("write: max record size: {}, max queued chunks {}, max queued size {}", diff --git a/rust/src/smb/smb1.rs b/rust/src/smb/smb1.rs index cce552de91..c169930d24 100644 --- a/rust/src/smb/smb1.rs +++ b/rust/src/smb/smb1.rs @@ -527,7 +527,7 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and }, SMB1_COMMAND_TREE_DISCONNECT => { let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE); - state.ssn2tree_map.remove(&tree_key); + state.ssn2tree_cache.pop(&tree_key); false }, SMB1_COMMAND_CLOSE => { @@ -702,7 +702,7 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an if found { let tree = SMBTree::new(share_name.to_vec(), is_pipe); let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE); - state.ssn2tree_map.insert(tree_key, tree); + state.ssn2tree_cache.put(tree_key, tree); } found }, @@ -716,7 +716,7 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an // normally removed when processing request, // but in case we missed that try again here let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE); - state.ssn2tree_map.remove(&tree_key); + state.ssn2tree_cache.pop(&tree_key); false }, SMB1_COMMAND_NT_CREATE_ANDX => { @@ -977,7 +977,7 @@ pub fn smb1_write_request_record(state: &mut SMBState, r: &SmbRecord, andx_offse }; if !found { let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE); - let (share_name, is_pipe) = match state.ssn2tree_map.get(&tree_key) { + let (share_name, is_pipe) = match state.ssn2tree_cache.get(&tree_key) { Some(n) => (n.name.to_vec(), n.is_pipe), None => (Vec::new(), false), }; @@ -1050,7 +1050,7 @@ pub fn smb1_read_response_record(state: &mut SMBState, r: &SmbRecord, andx_offse SCLogDebug!("SMBv1 READ: FID {:?} offset {}", file_fid, offset); let tree_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_SHARE); - let (is_pipe, share_name) = match state.ssn2tree_map.get(&tree_key) { + let (is_pipe, share_name) = match state.ssn2tree_cache.get(&tree_key) { Some(n) => (n.is_pipe, n.name.to_vec()), _ => { (false, Vec::new()) }, }; diff --git a/rust/src/smb/smb2.rs b/rust/src/smb/smb2.rs index 17603202aa..5eb57dd7b7 100644 --- a/rust/src/smb/smb2.rs +++ b/rust/src/smb/smb2.rs @@ -189,7 +189,7 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema SCLogDebug!("existing file tx? {}", found); if !found { let tree_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_SHARE); - let (share_name, mut is_pipe) = match state.ssn2tree_map.get(&tree_key) { + let (share_name, mut is_pipe) = match state.ssn2tree_cache.get(&tree_key) { Some(n) => (n.name.to_vec(), n.is_pipe), _ => { (Vec::new(), false) }, }; @@ -208,7 +208,7 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema SCLogDebug!("SMBv2/READ: looks like dcerpc"); // insert fake tree to assist in follow up lookups let tree = SMBTree::new(b"suricata::dcerpc".to_vec(), true); - state.ssn2tree_map.insert(tree_key, tree); + state.ssn2tree_cache.put(tree_key, tree); if !is_dcerpc { _ = state.guid2name_cache.put(file_guid.to_vec(), b"suricata::dcerpc".to_vec()); } @@ -332,7 +332,7 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema }; if !found { let tree_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_SHARE); - let (share_name, mut is_pipe) = match state.ssn2tree_map.get(&tree_key) { + let (share_name, mut is_pipe) = match state.ssn2tree_cache.get(&tree_key) { Some(n) => { (n.name.to_vec(), n.is_pipe) }, _ => { (Vec::new(), false) }, }; @@ -352,7 +352,7 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema SCLogDebug!("SMBv2/WRITE: looks like we have dcerpc"); let tree = SMBTree::new(b"suricata::dcerpc".to_vec(), true); - state.ssn2tree_map.insert(tree_key, tree); + state.ssn2tree_cache.put(tree_key, tree); if !is_dcerpc { _ = state.guid2name_cache.put(file_guid.to_vec(), b"suricata::dcerpc".to_vec()); @@ -484,7 +484,7 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) }, SMB2_COMMAND_TREE_DISCONNECT => { let tree_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_SHARE); - state.ssn2tree_map.remove(&tree_key); + state.ssn2tree_cache.pop(&tree_key); false } SMB2_COMMAND_NEGOTIATE_PROTOCOL => { @@ -728,7 +728,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) // normally removed when processing request, // but in case we missed that try again here let tree_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_SHARE); - state.ssn2tree_map.remove(&tree_key); + state.ssn2tree_cache.pop(&tree_key); false } SMB2_COMMAND_TREE_CONNECT => { @@ -756,7 +756,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record) if found { let tree = SMBTree::new(share_name.to_vec(), is_pipe); let tree_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_SHARE); - state.ssn2tree_map.insert(tree_key, tree); + state.ssn2tree_cache.put(tree_key, tree); } true } else {