diff --git a/rust/src/smb/dcerpc.rs b/rust/src/smb/dcerpc.rs index 5cb1adeba2..0f0b4c2e51 100644 --- a/rust/src/smb/dcerpc.rs +++ b/rust/src/smb/dcerpc.rs @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 Open Information Security Foundation +/* Copyright (C) 2017-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -124,9 +124,9 @@ impl SMBTransactionDCERPC { impl SMBState { fn new_dcerpc_tx(&mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, cmd: u8, call_id: u32) - -> &mut SMBTransaction + -> Option<&mut SMBTransaction> { - let mut tx = self.new_tx(); + let mut tx = self.new_tx()?; tx.hdr = hdr; tx.vercmd = vercmd; tx.type_data = Some(SMBTransactionTypeData::DCERPC( @@ -134,14 +134,13 @@ impl SMBState { SCLogDebug!("SMB: TX DCERPC created: ID {} hdr {:?}", tx.id, tx.hdr); self.transactions.push_back(tx); - let tx_ref = self.transactions.back_mut(); - return tx_ref.unwrap(); + self.transactions.back_mut() } fn new_dcerpc_tx_for_response(&mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, call_id: u32) - -> &mut SMBTransaction + -> Option<&mut SMBTransaction> { - let mut tx = self.new_tx(); + let mut tx = self.new_tx()?; tx.hdr = hdr; tx.vercmd = vercmd; tx.type_data = Some(SMBTransactionTypeData::DCERPC( @@ -149,8 +148,7 @@ impl SMBState { SCLogDebug!("SMB: TX DCERPC created: ID {} hdr {:?}", tx.id, tx.hdr); self.transactions.push_back(tx); - let tx_ref = self.transactions.back_mut(); - return tx_ref.unwrap(); + self.transactions.back_mut() } fn get_dcerpc_tx(&mut self, hdr: &SMBCommonHdr, vercmd: &SMBVerCmdStat, call_id: u32) @@ -237,7 +235,10 @@ pub fn smb_write_dcerpc_record(state: &mut SMBState, } } - let tx = state.new_dcerpc_tx(hdr, vercmd, dcer.packet_type, dcer.call_id); + let tx = match state.new_dcerpc_tx(hdr, vercmd, dcer.packet_type, dcer.call_id) { + Some(tx) => tx, + None => return false, + }; match dcer.packet_type { DCERPC_TYPE_REQUEST => { match parse_dcerpc_request_record(dcer.data, dcer.frag_len, dcer.little_endian) { @@ -514,7 +515,11 @@ pub fn smb_read_dcerpc_record(state: &mut SMBState, }; if !found { // pick up DCERPC tx even if we missed the request - let tx = state.new_dcerpc_tx_for_response(hdr, vercmd.clone(), dcer.call_id); + let tx = match state.new_dcerpc_tx_for_response( + hdr, vercmd.clone(), dcer.call_id) { + Some(tx) => tx, + None => return false, + }; dcerpc_response_handle(tx, vercmd, &dcer); } }, diff --git a/rust/src/smb/files.rs b/rust/src/smb/files.rs index ef9e620bb8..1f11825866 100644 --- a/rust/src/smb/files.rs +++ b/rust/src/smb/files.rs @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2022 Open Information Security Foundation +/* Copyright (C) 2018-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -85,9 +85,9 @@ fn filetracker_update(ft: &mut FileTransferTracker, data: &[u8], gap_size: u32) impl SMBState { pub fn new_file_tx(&mut self, fuid: &[u8], file_name: &[u8], direction: Direction) - -> &mut SMBTransaction + -> Option<&mut SMBTransaction> { - let mut tx = self.new_tx(); + let mut tx = self.new_tx()?; tx.type_data = Some(SMBTransactionTypeData::FILE(SMBTransactionFile::new())); if let Some(SMBTransactionTypeData::FILE(ref mut d)) = tx.type_data { d.direction = direction; @@ -102,8 +102,7 @@ impl SMBState { SCLogDebug!("SMB: new_file_tx: TX FILE created: ID {} NAME {}", tx.id, String::from_utf8_lossy(file_name)); self.transactions.push_back(tx); - let tx_ref = self.transactions.back_mut(); - return tx_ref.unwrap(); + self.transactions.back_mut() } /// get file tx for a open file. Returns None if a file for the fuid exists, diff --git a/rust/src/smb/session.rs b/rust/src/smb/session.rs index 241973fc2b..113599075a 100644 --- a/rust/src/smb/session.rs +++ b/rust/src/smb/session.rs @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Open Information Security Foundation +/* Copyright (C) 2018-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -36,9 +36,9 @@ impl SMBTransactionSessionSetup { impl SMBState { pub fn new_sessionsetup_tx(&mut self, hdr: SMBCommonHdr) - -> &mut SMBTransaction + -> Option<&mut SMBTransaction> { - let mut tx = self.new_tx(); + let mut tx = self.new_tx()?; tx.hdr = hdr; tx.type_data = Some(SMBTransactionTypeData::SESSIONSETUP( @@ -48,8 +48,7 @@ impl SMBState { SCLogDebug!("SMB: TX SESSIONSETUP created: ID {}", tx.id); self.transactions.push_back(tx); - let tx_ref = self.transactions.back_mut(); - return tx_ref.unwrap(); + self.transactions.back_mut() } pub fn get_sessionsetup_tx(&mut self, hdr: SMBCommonHdr) diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index 0a0fc10824..1494b8147c 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2022 Open Information Security Foundation +/* Copyright (C) 2017-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -330,9 +330,9 @@ impl SMBTransactionSetFilePathInfo { impl SMBState { pub fn new_setfileinfo_tx(&mut self, filename: Vec, fid: Vec, subcmd: u16, loi: u16, delete_on_close: bool) - -> &mut SMBTransaction + -> Option<&mut SMBTransaction> { - let mut tx = self.new_tx(); + let mut tx = self.new_tx()?; tx.type_data = Some(SMBTransactionTypeData::SETFILEPATHINFO( SMBTransactionSetFilePathInfo::new( @@ -342,15 +342,14 @@ impl SMBState { SCLogDebug!("SMB: TX SETFILEPATHINFO created: ID {}", tx.id); self.transactions.push_back(tx); - let tx_ref = self.transactions.back_mut(); - return tx_ref.unwrap(); + self.transactions.back_mut() } pub fn new_setpathinfo_tx(&mut self, filename: Vec, subcmd: u16, loi: u16, delete_on_close: bool) - -> &mut SMBTransaction + -> Option<&mut SMBTransaction> { - let mut tx = self.new_tx(); + let mut tx = self.new_tx()?; let fid : Vec = Vec::new(); tx.type_data = Some(SMBTransactionTypeData::SETFILEPATHINFO( @@ -361,8 +360,7 @@ impl SMBState { SCLogDebug!("SMB: TX SETFILEPATHINFO created: ID {}", tx.id); self.transactions.push_back(tx); - let tx_ref = self.transactions.back_mut(); - return tx_ref.unwrap(); + self.transactions.back_mut() } } @@ -383,9 +381,9 @@ impl SMBTransactionRename { impl SMBState { pub fn new_rename_tx(&mut self, fuid: Vec, oldname: Vec, newname: Vec) - -> &mut SMBTransaction + -> Option<&mut SMBTransaction> { - let mut tx = self.new_tx(); + let mut tx = self.new_tx()?; tx.type_data = Some(SMBTransactionTypeData::RENAME( SMBTransactionRename::new(fuid, oldname, newname))); @@ -394,8 +392,7 @@ impl SMBState { SCLogDebug!("SMB: TX RENAME created: ID {}", tx.id); self.transactions.push_back(tx); - let tx_ref = self.transactions.back_mut(); - return tx_ref.unwrap(); + self.transactions.back_mut() } } @@ -726,7 +723,6 @@ pub struct SMBState<> { /// transactions list pub transactions: VecDeque, - tx_index_completed: usize, /// tx counter for assigning incrementing id's to tx's tx_id: u64, @@ -783,9 +779,8 @@ impl SMBState { check_post_gap_file_txs: false, post_gap_files_checked: false, transactions: VecDeque::new(), - tx_index_completed: 0, - tx_id:0, - dialect:0, + tx_id: 0, + dialect: 0, dialect_vec: None, dcerpc_ifaces: None, ts: 0, @@ -798,28 +793,21 @@ impl SMBState { self._debug_tx_stats(); } - pub fn new_tx(&mut self) -> SMBTransaction { + pub fn new_tx(&mut self) -> Option { + if self.transactions.len() >= unsafe { SMB_MAX_TX } { + // Refuse to create a transaction once the list is at the limit. This + // bounds the number of transactions a single input can create, no + // matter the path (compound records, dcerpc, ...). Callers stop + // using the transaction and the parser puts the flow into an error + // state (see issue 8629). + self.set_event(SMBEvent::TooManyTransactions); + return None; + } let mut tx = SMBTransaction::new(); self.tx_id += 1; tx.id = self.tx_id; SCLogDebug!("TX {} created", tx.id); - if self.transactions.len() > unsafe { SMB_MAX_TX } { - let mut index = self.tx_index_completed; - for tx_old in &mut self.transactions.range_mut(self.tx_index_completed..) { - index += 1; - if !tx_old.request_done || !tx_old.response_done { - tx_old.tx_data.updated_tc = true; - tx_old.tx_data.updated_ts = true; - tx_old.request_done = true; - tx_old.response_done = true; - tx_old.set_event(SMBEvent::TooManyTransactions); - break; - } - } - self.tx_index_completed = index; - - } - return tx; + Some(tx) } pub fn free_tx(&mut self, tx_id: u64) { @@ -839,7 +827,6 @@ impl SMBState { if found { SCLogDebug!("freeing TX with ID {} TX.ID {} at index {} left: {} max id: {}", tx_id, tx_id+1, index, self.transactions.len(), self.tx_id); - self.tx_index_completed = 0; self.transactions.remove(index); } } @@ -888,9 +875,9 @@ impl SMBState { * track a single cmd request/reply pair. */ pub fn new_generic_tx(&mut self, smb_ver: u8, smb_cmd: u16, key: SMBCommonHdr) - -> &mut SMBTransaction + -> Option<&mut SMBTransaction> { - let mut tx = self.new_tx(); + let mut tx = self.new_tx()?; if smb_ver == 1 && smb_cmd <= 255 { tx.vercmd.set_smb1_cmd(smb_cmd as u8); } else if smb_ver == 2 { @@ -905,8 +892,7 @@ impl SMBState { SCLogDebug!("SMB: TX GENERIC created: ID {} tx list {} {:?}", tx.id, self.transactions.len(), &tx); self.transactions.push_back(tx); - let tx_ref = self.transactions.back_mut(); - return tx_ref.unwrap(); + self.transactions.back_mut() } pub fn get_last_tx(&mut self, smb_ver: u8, smb_cmd: u16) @@ -963,9 +949,9 @@ impl SMBState { } pub fn new_negotiate_tx(&mut self, smb_ver: u8) - -> &mut SMBTransaction + -> Option<&mut SMBTransaction> { - let mut tx = self.new_tx(); + let mut tx = self.new_tx()?; if smb_ver == 1 { tx.vercmd.set_smb1_cmd(SMB1_COMMAND_NEGOTIATE_PROTOCOL); } else if smb_ver == 2 { @@ -979,8 +965,7 @@ impl SMBState { SCLogDebug!("SMB: TX NEGOTIATE created: ID {} SMB ver {}", tx.id, smb_ver); self.transactions.push_back(tx); - let tx_ref = self.transactions.back_mut(); - return tx_ref.unwrap(); + self.transactions.back_mut() } pub fn get_negotiate_tx(&mut self, smb_ver: u8) @@ -1003,9 +988,9 @@ impl SMBState { } pub fn new_treeconnect_tx(&mut self, hdr: SMBCommonHdr, name: Vec) - -> &mut SMBTransaction + -> Option<&mut SMBTransaction> { - let mut tx = self.new_tx(); + let mut tx = self.new_tx()?; tx.hdr = hdr; tx.type_data = Some(SMBTransactionTypeData::TREECONNECT( @@ -1016,8 +1001,7 @@ impl SMBState { SCLogDebug!("SMB: TX TREECONNECT created: ID {} NAME {}", tx.id, String::from_utf8_lossy(&name)); self.transactions.push_back(tx); - let tx_ref = self.transactions.back_mut(); - return tx_ref.unwrap(); + self.transactions.back_mut() } pub fn get_treeconnect_tx(&mut self, hdr: SMBCommonHdr) @@ -1040,9 +1024,9 @@ impl SMBState { pub fn new_create_tx(&mut self, file_name: &[u8], disposition: u32, del: bool, dir: bool, hdr: SMBCommonHdr) - -> &mut SMBTransaction + -> Option<&mut SMBTransaction> { - let mut tx = self.new_tx(); + let mut tx = self.new_tx()?; tx.hdr = hdr; tx.type_data = Some(SMBTransactionTypeData::CREATE( SMBTransactionCreate::new( @@ -1052,8 +1036,7 @@ impl SMBState { tx.response_done = self.tc_trunc; // no response expected if tc is truncated self.transactions.push_back(tx); - let tx_ref = self.transactions.back_mut(); - return tx_ref.unwrap(); + self.transactions.back_mut() } pub fn get_service_for_guid(&self, guid: &[u8]) -> (&'static str, bool) @@ -1347,6 +1330,13 @@ impl SMBState { /// Parsing function, handling TCP chunks fragmentation pub fn parse_tcp_data_ts(&mut self, flow: *const Flow, stream_slice: &StreamSlice) -> AppLayerResult { + // The transaction list is full: new_tx() is refusing to create more, so + // put the flow into an error state and stop processing it (see issue + // 8629). + if self.transactions.len() >= unsafe { SMB_MAX_TX } { + self.set_event(SMBEvent::TooManyTransactions); + return AppLayerResult::err(); + } let mut cur_i = stream_slice.as_slice(); let consumed = self.handle_skip(Direction::ToServer, cur_i.len() as u32); if consumed > 0 { @@ -1684,6 +1674,13 @@ impl SMBState { /// Parsing function, handling TCP chunks fragmentation pub fn parse_tcp_data_tc(&mut self, flow: *const Flow, stream_slice: &StreamSlice) -> AppLayerResult { + // The transaction list is full: new_tx() is refusing to create more, so + // put the flow into an error state and stop processing it (see issue + // 8629). + if self.transactions.len() >= unsafe { SMB_MAX_TX } { + self.set_event(SMBEvent::TooManyTransactions); + return AppLayerResult::err(); + } let mut cur_i = stream_slice.as_slice(); let consumed = self.handle_skip(Direction::ToClient, cur_i.len() as u32); if consumed > 0 { diff --git a/rust/src/smb/smb1.rs b/rust/src/smb/smb1.rs index a3a45ac64f..a1c5422360 100644 --- a/rust/src/smb/smb1.rs +++ b/rust/src/smb/smb1.rs @@ -1,4 +1,4 @@ -/* Copyright (C) 2018-2022 Open Information Security Foundation +/* Copyright (C) 2018-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -198,7 +198,10 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and let mut oldname = rd.oldname; oldname.retain(|&i|i != 0x00); - let tx = state.new_rename_tx(Vec::new(), oldname, newname); + let tx = match state.new_rename_tx(Vec::new(), oldname, newname) { + Some(tx) => tx, + None => return, + }; tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_RENAME); @@ -227,8 +230,11 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and SCLogDebug!("TRANS2 SET_FILE_INFO DATA DISPOSITION DONE {:?}", disp); let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); - let tx = state.new_setpathinfo_tx(pd.oldname, - rd.subcmd, pd.loi, disp.delete); + let tx = match state.new_setpathinfo_tx(pd.oldname, + rd.subcmd, pd.loi, disp.delete) { + Some(tx) => tx, + None => return, + }; tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); @@ -257,7 +263,11 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and let fid : Vec = Vec::new(); - let tx = state.new_rename_tx(fid, pd.oldname, newname); + let tx = match state.new_rename_tx( + fid, pd.oldname, newname) { + Some(tx) => tx, + None => return, + }; tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); @@ -310,8 +320,11 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and Some(n) => n.to_vec(), None => b"".to_vec(), }; - let tx = state.new_setfileinfo_tx(filename, pd.fid.to_vec(), - rd.subcmd, pd.loi, disp.delete); + let tx = match state.new_setfileinfo_tx(filename, pd.fid.to_vec(), + rd.subcmd, pd.loi, disp.delete) { + Some(tx) => tx, + None => return, + }; tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); @@ -345,7 +358,10 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and Some(n) => n.to_vec(), None => b"".to_vec(), }; - let tx = state.new_rename_tx(pd.fid.to_vec(), oldname, newname); + let tx = match state.new_rename_tx(pd.fid.to_vec(), oldname, newname) { + Some(tx) => tx, + None => return, + }; tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); @@ -452,7 +468,10 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and None => { false }, }; if !found { - let tx = state.new_negotiate_tx(1); + let tx = match state.new_negotiate_tx(1) { + Some(tx) => tx, + None => return, + }; if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data { tdn.dialects = dialects; } @@ -482,8 +501,11 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and state.ssn2vec_map.insert(name_key, name_val); let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); - let tx = state.new_create_tx(&cr.file_name, - cr.disposition, del, dir, tx_hdr); + let tx = match state.new_create_tx(&cr.file_name, + cr.disposition, del, dir, tx_hdr) { + Some(tx) => tx, + None => return, + }; tx.vercmd.set_smb1_cmd(command); SCLogDebug!("TS CREATE TX {} created", tx.id); true @@ -511,7 +533,10 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and // store hdr as SMBHDR_TYPE_TREE, so with tree id 0 // when the response finds this we update it - let tx = state.new_treeconnect_tx(name_key, name_val); + let tx = match state.new_treeconnect_tx(name_key, name_val) { + Some(tx) => tx, + None => return, + }; if let Some(SMBTransactionTypeData::TREECONNECT(ref mut tdn)) = tx.type_data { tdn.req_service = Some(tr.service.to_vec()); } @@ -571,7 +596,10 @@ fn smb1_request_record_one(state: &mut SMBState, r: &SmbRecord, command: u8, and }; if !have_tx && smb1_create_new_tx(command) { let tx_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); - let tx = state.new_generic_tx(1, command as u16, tx_key); + let tx = match state.new_generic_tx(1, command as u16, tx_key) { + Some(tx) => tx, + None => return, + }; SCLogDebug!("tx {} created for {}/{}", tx.id, command, &smb1_command_string(command)); tx.set_events(events); if no_response_expected { @@ -984,7 +1012,11 @@ pub fn smb1_write_request_record(state: &mut SMBState, r: &SmbRecord, andx_offse let vercmd = SMBVerCmdStat::new1_with_ntstatus(command, r.nt_status); smb_write_dcerpc_record(state, vercmd, hdr, rd.data); } else { - let tx = state.new_file_tx(&file_fid, &file_name, Direction::ToServer); + let tx = match state.new_file_tx( + &file_fid, &file_name, Direction::ToServer) { + Some(tx) => tx, + None => return, + }; if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { let file_id : u32 = tx.id as u32; if rd.offset < tdf.file_tracker.tracked { @@ -1073,7 +1105,11 @@ pub fn smb1_read_response_record(state: &mut SMBState, r: &SmbRecord, andx_offse None => { false }, }; if !found { - let tx = state.new_file_tx(&file_fid, &file_name, Direction::ToClient); + let tx = match state.new_file_tx( + &file_fid, &file_name, Direction::ToClient) { + Some(tx) => tx, + None => return, + }; if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { let file_id : u32 = tx.id as u32; SCLogDebug!("FID {:?} found at tx {}", file_fid, tx.id); @@ -1119,7 +1155,10 @@ pub fn smb1_read_response_record(state: &mut SMBState, r: &SmbRecord, andx_offse fn smb1_request_record_generic(state: &mut SMBState, r: &SmbRecord, events: Vec) { if smb1_create_new_tx(r.command) || !events.is_empty() { let tx_key = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); - let tx = state.new_generic_tx(1, r.command as u16, tx_key); + let tx = match state.new_generic_tx(1, r.command as u16, tx_key) { + Some(tx) => tx, + None => return, + }; tx.set_events(events); } } @@ -1138,7 +1177,10 @@ fn smb1_response_record_generic(state: &mut SMBState, r: &SmbRecord, events: Vec return; } if !events.is_empty() { - let tx = state.new_generic_tx(1, r.command as u16, tx_key); + let tx = match state.new_generic_tx(1, r.command as u16, tx_key) { + Some(tx) => tx, + None => return, + }; tx.request_done = true; tx.response_done = true; SCLogDebug!("tx {} cmd {} is done", tx.id, r.command); diff --git a/rust/src/smb/smb1_session.rs b/rust/src/smb/smb1_session.rs index 80f23c8a64..f87799b975 100644 --- a/rust/src/smb/smb1_session.rs +++ b/rust/src/smb/smb1_session.rs @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Open Information Security Foundation +/* Copyright (C) 2018-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -131,7 +131,10 @@ pub fn smb1_session_setup_request(state: &mut SMBState, r: &SmbRecord, andx_offs Ok((rem, setup)) => { let hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER, r.ssn_id as u64, 0, r.multiplex_id as u64); - let tx = state.new_sessionsetup_tx(hdr); + let tx = match state.new_sessionsetup_tx(hdr) { + Some(tx) => tx, + None => return, + }; tx.vercmd.set_smb1_cmd(r.command); if let Some(SMBTransactionTypeData::SESSIONSETUP(ref mut td)) = tx.type_data { diff --git a/rust/src/smb/smb2.rs b/rust/src/smb/smb2.rs index 98ed30da1c..76db5933cd 100644 --- a/rust/src/smb/smb2.rs +++ b/rust/src/smb/smb2.rs @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2022 Open Information Security Foundation +/* Copyright (C) 2017-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -234,7 +234,10 @@ pub fn smb2_read_response_record(state: &mut SMBState, r: &Smb2Record, nbss_rema None => { b"".to_vec() } }; - let tx = state.new_file_tx(&file_guid, &file_name, Direction::ToClient); + let tx = match state.new_file_tx(&file_guid, &file_name, Direction::ToClient) { + Some(tx) => tx, + None => return, + }; tx.vercmd.set_smb2_cmd(SMB2_COMMAND_READ); tx.hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER, r.session_id, r.tree_id, 0); // TODO move into new_file_tx @@ -279,7 +282,10 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema SCLogDebug!("SMBv2/WRITE: request record"); if smb2_create_new_tx(r.command) { let tx_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); - let tx = state.new_generic_tx(2, r.command, tx_key); + let tx = match state.new_generic_tx(2, r.command, tx_key) { + Some(tx) => tx, + None => return, + }; tx.request_done = true; } match parse_smb2_request_write(r.data) { @@ -374,7 +380,10 @@ pub fn smb2_write_request_record(state: &mut SMBState, r: &Smb2Record, nbss_rema SCLogDebug!("non-DCERPC pipe: skip rest of the record"); state.set_skip(Direction::ToServer, nbss_remaining); } else { - let tx = state.new_file_tx(&file_guid, &file_name, Direction::ToServer); + let tx = match state.new_file_tx(&file_guid, &file_name, Direction::ToServer) { + Some(tx) => tx, + None => return, + }; tx.vercmd.set_smb2_cmd(SMB2_COMMAND_WRITE); tx.hdr = SMBCommonHdr::new(SMBHDR_TYPE_HEADER, r.session_id, r.tree_id, 0); // TODO move into new_file_tx @@ -433,7 +442,10 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) Some(n) => { n.to_vec() }, None => { b"".to_vec() }, }; - let tx = state.new_rename_tx(rd.guid.to_vec(), oldname, newname); + let tx = match state.new_rename_tx(rd.guid.to_vec(), oldname, newname) { + Some(tx) => tx, + None => return, + }; tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb2_cmd(SMB2_COMMAND_SET_INFO); @@ -457,7 +469,10 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) } }, }; - let tx = state.new_setfileinfo_tx(fname, rd.guid.to_vec(), rd.class as u16, rd.infolvl as u16, dis.delete); + let tx = match state.new_setfileinfo_tx(fname, rd.guid.to_vec(), rd.class as u16, rd.infolvl as u16, dis.delete) { + Some(tx) => tx, + None => return, + }; tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb2_cmd(SMB2_COMMAND_SET_INFO); @@ -507,7 +522,10 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) None => { false }, }; if !found { - let tx = state.new_negotiate_tx(2); + let tx = match state.new_negotiate_tx(2) { + Some(tx) => tx, + None => return, + }; if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data { tdn.dialects2 = dialects; tdn.client_guid = Some(rd.client_guid.to_vec()); @@ -536,7 +554,10 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) name_val = name_val[1..].to_vec(); } - let tx = state.new_treeconnect_tx(name_key, name_val); + let tx = match state.new_treeconnect_tx(name_key, name_val) { + Some(tx) => tx, + None => return, + }; tx.request_done = true; tx.vercmd.set_smb2_cmd(SMB2_COMMAND_TREE_CONNECT); true @@ -581,8 +602,11 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) state.ssn2vec_map.insert(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); + let tx = match state.new_create_tx(cr.data, + cr.disposition, del, dir, tx_hdr) { + Some(tx) => tx, + None => return, + }; tx.vercmd.set_smb2_cmd(r.command); SCLogDebug!("TS CREATE TX {} created", tx.id); true @@ -645,7 +669,10 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) /* if we don't have a tx, create it here (maybe) */ if !have_tx && smb2_create_new_tx(r.command) { let tx_key = SMBCommonHdr::from2(r, SMBHDR_TYPE_GENERICTX); - let tx = state.new_generic_tx(2, r.command, tx_key); + let tx = match state.new_generic_tx(2, r.command, tx_key) { + Some(tx) => tx, + None => return, + }; SCLogDebug!("TS TX {} command {} created with session_id {} tree_id {} message_id {}", tx.id, r.command, r.session_id, r.tree_id, r.message_id); tx.set_events(events); diff --git a/rust/src/smb/smb2_ioctl.rs b/rust/src/smb/smb2_ioctl.rs index ff85a5fefb..06f4f55c3d 100644 --- a/rust/src/smb/smb2_ioctl.rs +++ b/rust/src/smb/smb2_ioctl.rs @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Open Information Security Foundation +/* Copyright (C) 2018-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -39,9 +39,9 @@ impl SMBTransactionIoctl { impl SMBState { pub fn new_ioctl_tx(&mut self, hdr: SMBCommonHdr, func: u32) - -> &mut SMBTransaction + -> Option<&mut SMBTransaction> { - let mut tx = self.new_tx(); + let mut tx = self.new_tx()?; tx.hdr = hdr; tx.type_data = Some(SMBTransactionTypeData::IOCTL( SMBTransactionIoctl::new(func))); @@ -51,8 +51,7 @@ impl SMBState { SCLogDebug!("SMB: TX IOCTL created: ID {} FUNC {:08x}: {}", tx.id, func, &fsctl_func_to_string(func)); self.transactions.push_back(tx); - let tx_ref = self.transactions.back_mut(); - return tx_ref.unwrap(); + self.transactions.back_mut() } } @@ -74,12 +73,18 @@ pub fn smb2_ioctl_request_record(state: &mut SMBState, r: &Smb2Record) smb_write_dcerpc_record(state, vercmd, hdr, rd.data); } else { SCLogDebug!("IOCTL {:08x} {}", rd.function, &fsctl_func_to_string(rd.function)); - let tx = state.new_ioctl_tx(hdr, rd.function); + let tx = match state.new_ioctl_tx(hdr, rd.function) { + Some(tx) => tx, + None => return, + }; tx.vercmd.set_smb2_cmd(SMB2_COMMAND_IOCTL); } }, _ => { - let tx = state.new_generic_tx(2, r.command, hdr); + let tx = match state.new_generic_tx(2, r.command, hdr) { + Some(tx) => tx, + None => return, + }; tx.set_event(SMBEvent::MalformedData); }, }; diff --git a/rust/src/smb/smb2_session.rs b/rust/src/smb/smb2_session.rs index 31a34165e4..2760fb99e8 100644 --- a/rust/src/smb/smb2_session.rs +++ b/rust/src/smb/smb2_session.rs @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 Open Information Security Foundation +/* Copyright (C) 2018-2026 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -27,7 +27,10 @@ pub fn smb2_session_setup_request(state: &mut SMBState, r: &Smb2Record) match parse_smb2_request_session_setup(r.data) { Ok((_, setup)) => { let hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER); - let tx = state.new_sessionsetup_tx(hdr); + let tx = match state.new_sessionsetup_tx(hdr) { + Some(tx) => tx, + None => return, + }; tx.vercmd.set_smb2_cmd(r.command); if let Some(SMBTransactionTypeData::SESSIONSETUP(ref mut td)) = tx.type_data {