]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
smb: use lru for ssn2vec_map
authorVictor Julien <vjulien@oisf.net>
Thu, 24 Oct 2024 13:29:21 +0000 (15:29 +0200)
committerVictor Julien <victor@inliniac.net>
Wed, 6 Nov 2024 20:33:33 +0000 (21:33 +0100)
Generic ssn2vec_map was a HashMap used for mapping session key to
different types of vector data:
- GUID
- filename
- share name

Turn this into a bounded LruCache. Rename to ssn2vec_cache.

Size of the cache is 512 by default, and can be configured using:

`app-layer.protocols.smb.max-session-cache-size`

Ticket: #5672.

rust/src/smb/debug.rs
rust/src/smb/smb.rs
rust/src/smb/smb1.rs
rust/src/smb/smb2.rs

index f2c3d9a7a393d36df0037e11a21b7b1064bc1a1a..0c19a2c58d02b4a1ce435bc3eeca626d7eea7701 100644 (file)
@@ -69,8 +69,8 @@ impl SMBState {
 
     #[cfg(feature = "debug")]
     pub fn _debug_state_stats(&self) {
-        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(),
+        SCLogDebug!("ssn2vec_cache {} guid2name_cache {} read_offset_cache {} ssn2tree_cache {} dcerpc_rec_frag_cache {} file_ts_guid {} file_tc_guid {} transactions {}",
+            self.ssn2vec_cache.len(),
             self.guid2name_cache.len(),
             self.read_offset_cache.len(),
             self.ssn2tree_cache.len(),
index 004bff9f2fae93aa9abe926d23689bf81bffbe00..901ed2a2392788adf9080a3010c01c3457c546bf 100644 (file)
@@ -28,7 +28,6 @@
 use std;
 use std::str;
 use std::ffi::{self, CString};
-use std::collections::HashMap;
 use std::collections::VecDeque;
  
 use nom7::{Err, Needed};
@@ -90,6 +89,8 @@ pub static mut SMB_CFG_MAX_READ_OFFSET_CACHE_SIZE: usize = 128;
 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;
+/// For SMBState::ssn2vec_cache
+pub static mut SMB_CFG_MAX_SSN2VEC_CACHE_SIZE: usize = 512;
 
 static mut ALPROTO_SMB: AppProto = ALPROTO_UNKNOWN;
 
@@ -697,7 +698,7 @@ pub struct SMBState<> {
     pub state_data: AppLayerStateData,
 
     /// map ssn/tree/msgid to vec (guid/name/share)
-    pub ssn2vec_map: HashMap<SMBCommonHdr, Vec<u8>>,
+    pub ssn2vec_cache: LruCache<SMBCommonHdr, Vec<u8>>,
 
     /// map guid to filename
     ///
@@ -785,7 +786,7 @@ impl SMBState {
     pub fn new() -> Self {
         Self {
             state_data:AppLayerStateData::new(),
-            ssn2vec_map:HashMap::new(),
+            ssn2vec_cache:LruCache::new(NonZeroUsize::new(unsafe { SMB_CFG_MAX_SSN2VEC_CACHE_SIZE }).unwrap()),
             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()),
@@ -2497,6 +2498,18 @@ pub unsafe extern "C" fn rs_smb_register_parser() {
                 SCLogError!("Invalid max-dcerpc-frag-cache-size value");
             }
         }
+        let retval = conf_get("app-layer.protocols.smb.max-session-cache-size");
+        if let Some(val) = retval {
+            if let Ok(v) = val.parse::<usize>() {
+                if v > 0 {
+                    SMB_CFG_MAX_SSN2VEC_CACHE_SIZE = v;
+                } else {
+                    SCLogError!("Invalid max-session-cache-size value");
+                }
+            } else {
+                SCLogError!("Invalid max-session-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 {}",
index 7c49b3bdc8d46ad86882f1554b2517297f3e75a5..c74ab5fd02693ba9067623bf39d8caf144acbcad 100644 (file)
@@ -479,7 +479,7 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and
 
                     let name_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_FILENAME);
                     let name_val = cr.file_name.to_vec();
-                    state.ssn2vec_map.insert(name_key, name_val);
+                    state.ssn2vec_cache.put(name_key, name_val);
 
                     let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX);
                     let tx = state.new_create_tx(&cr.file_name,
@@ -537,7 +537,7 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and
                     fid.extend_from_slice(&u32_as_bytes(r.ssn_id));
 
                     let _name = state.guid2name_cache.pop(&fid);
-                    state.ssn2vec_map.insert(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID), fid.to_vec());
+                    state.ssn2vec_cache.put(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID), fid.to_vec());
 
                     SCLogDebug!("closing FID {:?}/{:?}", cd.fid, fid);
                     smb1_close_file(state, &fid, Direction::ToServer);
@@ -727,7 +727,7 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an
                         SCLogDebug!("Create AndX {:?}", cr);
 
                         let guid_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_FILENAME);
-                        if let Some(mut p) = state.ssn2vec_map.remove(&guid_key) {
+                        if let Some(mut p) = state.ssn2vec_cache.pop(&guid_key) {
                             p.retain(|&i|i != 0x00);
 
                             let mut fid = cr.fid.to_vec();
@@ -767,7 +767,7 @@ fn smb1_response_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, an
             }
         },
         SMB1_COMMAND_CLOSE => {
-            let fid = state.ssn2vec_map.remove(&SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID));
+            let fid = state.ssn2vec_cache.pop(&SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID));
             if let Some(fid) = fid {
                 SCLogDebug!("closing FID {:?}", fid);
                 smb1_close_file(state, &fid, Direction::ToClient);
@@ -857,7 +857,7 @@ pub fn smb1_trans_request_record(state: &mut SMBState, r: &SmbRecord)
             let mut pipe_dcerpc = false;
             if rd.pipe.is_some() {
                 let pipe = rd.pipe.unwrap();
-                state.ssn2vec_map.insert(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID),
+                state.ssn2vec_cache.put(SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID),
                         pipe.fid.to_vec());
 
                 let mut frankenfid = pipe.fid.to_vec();
@@ -893,7 +893,7 @@ pub fn smb1_trans_response_record(state: &mut SMBState, r: &SmbRecord)
             SCLogDebug!("TRANS response {:?}", rd);
 
             // see if we have a stored fid
-            let fid = state.ssn2vec_map.remove(
+            let fid = state.ssn2vec_cache.pop(
                     &SMBCommonHdr::from1(r, SMBHDR_TYPE_GUID)).unwrap_or_default();
             SCLogDebug!("FID {:?}", fid);
 
index 5eb57dd7b7261a260fee998e4611ce797a7f27e5..97deb702ecef793cddf81077286848c377ac624c 100644 (file)
@@ -299,7 +299,7 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema
 
             /* update key-guid map */
             let guid_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_GUID);
-            state.ssn2vec_map.insert(guid_key, wr.guid.to_vec());
+            state.ssn2vec_cache.put(guid_key, wr.guid.to_vec());
 
             let file_guid = wr.guid.to_vec();
             let file_name = match state.guid2name_cache.get(&file_guid) {
@@ -448,7 +448,7 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record)
                                         b"<unknown>".to_vec()
                                     } else {
                                         guid_key.msg_id -= 1;
-                                        match state.ssn2vec_map.get(&guid_key) {
+                                        match state.ssn2vec_cache.get(&guid_key) {
                                             Some(n) => { n.to_vec() },
                                             None => { b"<unknown>".to_vec()},
                                         }
@@ -558,7 +558,7 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record)
                 SCLogDebug!("create_options {:08x}", cr.create_options);
 
                 let name_key = SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_FILENAME);
-                state.ssn2vec_map.insert(name_key, cr.data.to_vec());
+                state.ssn2vec_cache.put(name_key, cr.data.to_vec());
 
                 let tx_hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX);
                 let tx = state.new_create_tx(cr.data, cr.disposition, del, dir, tx_hdr);
@@ -651,7 +651,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record)
                     /* search key-guid map */
                     let guid_key = SMBCommonHdr::new(SMBHDR_TYPE_GUID,
                         r.session_id, r.tree_id, r.message_id);
-                    let _guid_vec = state.ssn2vec_map.remove(&guid_key).unwrap_or_default();
+                    let _guid_vec = state.ssn2vec_cache.pop(&guid_key).unwrap_or_default();
                     SCLogDebug!("SMBv2 write response for GUID {:?}", _guid_vec);
                 } else {
                     events.push(SMBEvent::MalformedData);
@@ -693,7 +693,7 @@ pub fn smb2_response_record(state: &mut SMBState, r: &Smb2Record)
                     SCLogDebug!("SMBv2: Create response => {:?}", cr);
 
                     let guid_key = SMBCommonHdr::from2_notree(r, SMBHDR_TYPE_FILENAME);
-                    if let Some(mut p) = state.ssn2vec_map.remove(&guid_key) {
+                    if let Some(mut p) = state.ssn2vec_cache.pop(&guid_key) {
                         p.retain(|&i|i != 0x00);
                         _ = state.guid2name_cache.put(cr.guid.to_vec(), p);
                     } else {