Skip to content

Commit

Permalink
smb: use lru for ssn2vec_map
Browse files Browse the repository at this point in the history
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: OISF#5672.
  • Loading branch information
victorjulien committed Nov 6, 2024
1 parent ba7a4ec commit 543429f
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 16 deletions.
4 changes: 2 additions & 2 deletions rust/src/smb/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
19 changes: 16 additions & 3 deletions rust/src/smb/smb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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
///
Expand Down Expand Up @@ -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()),
Expand Down Expand Up @@ -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 {}",
Expand Down
12 changes: 6 additions & 6 deletions rust/src/smb/smb1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);

Expand Down
10 changes: 5 additions & 5 deletions rust/src/smb/smb2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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()},
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 543429f

Please sign in to comment.