]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
smb: use lru for ssn2tree; rename
authorVictor Julien <vjulien@oisf.net>
Thu, 24 Oct 2024 12:26:41 +0000 (14:26 +0200)
committerVictor Julien <victor@inliniac.net>
Wed, 6 Nov 2024 20:33:33 +0000 (21:33 +0100)
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.

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

index e945de286e6fa5c363f09c817d3d2a1049edbe16..d4b28cb232c2cc75eb4568759c204492b923f575 100644 (file)
@@ -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(),
index 3ef84a35528944aa8314a432e69619fc2a50d0cd..d195001daa6f658529ad0f6e99b9806183a06aa5 100644 (file)
@@ -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<SMBCommonHdr, SMBFileGUIDOffset>,
-
-    pub ssn2tree_map: HashMap<SMBCommonHdr, SMBTree>,
+    /// Map session key to SMBTree
+    pub ssn2tree_cache: LruCache<SMBCommonHdr, SMBTree>,
 
     // 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::<usize>() {
+                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 {}",
index cce552de91a0361edc447b2e598a147cbef52126..c169930d24d0215247f353ff73e0ac52f2c2e558 100644 (file)
@@ -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()) },
                 };
index 17603202aabeacc7f4a98ef6709cf30371204870..5eb57dd7b7261a260fee998e4611ce797a7f27e5 100644 (file)
@@ -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 {