From: Victor Julien Date: Thu, 24 Oct 2024 13:13:40 +0000 (+0200) Subject: smb: use lru for ssnguid2vec_map; rename X-Git-Tag: suricata-8.0.0-beta1~718 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ba7a4ece76f06db9a83abdbf6a5ae424aa73bba6;p=thirdparty%2Fsuricata.git smb: use lru for ssnguid2vec_map; rename Reimplement the ssnguid2vec_map HashMap as a LruCache. Since this is a DCERPC record cache, name it as such. Default size is 128. Can be controlled by `app-layer.protocols.smb.max-dcerpc-frag-cache-size`. Ticket: #5672. --- diff --git a/rust/src/smb/dcerpc.rs b/rust/src/smb/dcerpc.rs index de6b8def73..771e2538c2 100644 --- a/rust/src/smb/dcerpc.rs +++ b/rust/src/smb/dcerpc.rs @@ -455,7 +455,7 @@ pub fn smb_read_dcerpc_record(state: &mut SMBState, // msg_id 0 as this data crosses cmd/reply pairs let ehdr = SMBHashKeyHdrGuid::new(SMBCommonHdr::new(SMBHDR_TYPE_TRANS_FRAG, hdr.ssn_id, hdr.tree_id, 0_u64), guid.to_vec()); - let mut prevdata = state.ssnguid2vec_map.remove(&ehdr).unwrap_or_default(); + let mut prevdata = state.dcerpc_rec_frag_cache.pop(&ehdr).unwrap_or_default(); SCLogDebug!("indata {} prevdata {}", indata.len(), prevdata.len()); prevdata.extend_from_slice(indata); let data = prevdata; @@ -476,7 +476,7 @@ pub fn smb_read_dcerpc_record(state: &mut SMBState, if ntstatus == SMB_NTSTATUS_BUFFER_OVERFLOW && data.len() < dcer.frag_len as usize { SCLogDebug!("short record {} < {}: storing partial data in state", data.len(), dcer.frag_len); - state.ssnguid2vec_map.insert(ehdr, data.to_vec()); + state.dcerpc_rec_frag_cache.put(ehdr, data.to_vec()); return true; // TODO review } diff --git a/rust/src/smb/debug.rs b/rust/src/smb/debug.rs index d4b28cb232..f2c3d9a7a3 100644 --- a/rust/src/smb/debug.rs +++ b/rust/src/smb/debug.rs @@ -69,12 +69,12 @@ impl SMBState { #[cfg(feature = "debug")] pub fn _debug_state_stats(&self) { - SCLogDebug!("ssn2vec_map {} guid2name_cache {} read_offset_cache {} ssn2tree_cache {} ssnguid2vec_map {} file_ts_guid {} file_tc_guid {} transactions {}", + SCLogDebug!("ssn2vec_map {} guid2name_cache {} read_offset_cache {} ssn2tree_cache {} dcerpc_rec_frag_cache {} file_ts_guid {} file_tc_guid {} transactions {}", self.ssn2vec_map.len(), self.guid2name_cache.len(), self.read_offset_cache.len(), self.ssn2tree_cache.len(), - self.ssnguid2vec_map.len(), + self.dcerpc_rec_frag_cache.len(), self.file_ts_guid.len(), self.file_tc_guid.len(), self.transactions.len()); diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index d195001daa..004bff9f2f 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -88,6 +88,8 @@ pub static mut SMB_CFG_MAX_GUID_CACHE_SIZE: usize = 1024; 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; +/// For SMBState::dcerpc_rec_frag_cache +pub static mut SMB_CFG_MAX_FRAG_CACHE_SIZE: usize = 128; static mut ALPROTO_SMB: AppProto = ALPROTO_UNKNOWN; @@ -712,9 +714,9 @@ pub struct SMBState<> { /// Map session key to SMBTree pub ssn2tree_cache: LruCache, - // store partial data records that are transferred in multiple - // requests for DCERPC. - pub ssnguid2vec_map: HashMap>, + /// store partial data records that are transferred in multiple + /// requests for DCERPC. + pub dcerpc_rec_frag_cache: LruCache>, skip_ts: u32, skip_tc: u32, @@ -787,7 +789,7 @@ impl SMBState { 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_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_TREE_CACHE_SIZE }).unwrap()), - ssnguid2vec_map:HashMap::new(), + dcerpc_rec_frag_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_FRAG_CACHE_SIZE }).unwrap()), skip_ts:0, skip_tc:0, file_ts_left:0, @@ -2483,6 +2485,18 @@ pub unsafe extern "C" fn rs_smb_register_parser() { SCLogError!("Invalid max-tree-cache-size value"); } } + let retval = conf_get("app-layer.protocols.smb.max-dcerpc-frag-cache-size"); + if let Some(val) = retval { + if let Ok(v) = val.parse::() { + if v > 0 { + SMB_CFG_MAX_FRAG_CACHE_SIZE = v; + } else { + SCLogError!("Invalid max-dcerpc-frag-cache-size value"); + } + } else { + SCLogError!("Invalid max-dcerpc-frag-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 c169930d24..7c49b3bdc8 100644 --- a/rust/src/smb/smb1.rs +++ b/rust/src/smb/smb1.rs @@ -910,7 +910,7 @@ pub fn smb1_trans_response_record(state: &mut SMBState, r: &SmbRecord) if r.nt_status == SMB_NTSTATUS_BUFFER_OVERFLOW { let key = SMBHashKeyHdrGuid::new(SMBCommonHdr::from1(r, SMBHDR_TYPE_TRANS_FRAG), fid); SCLogDebug!("SMBv1/TRANS: queueing data for len {} key {:?}", rd.data.len(), key); - state.ssnguid2vec_map.insert(key, rd.data.to_vec()); + state.dcerpc_rec_frag_cache.put(key, rd.data.to_vec()); } else if is_dcerpc { SCLogDebug!("SMBv1 TRANS TO PIPE"); let hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_HEADER);