diff --git a/rust/src/smb/dcerpc.rs b/rust/src/smb/dcerpc.rs index 818aaa3a1f..148e2f6215 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 @@ -126,8 +126,8 @@ impl SMBTransactionDCERPC { impl SMBState { fn new_dcerpc_tx( &mut self, hdr: SMBCommonHdr, vercmd: SMBVerCmdStat, cmd: u8, call_id: u32, - ) -> &mut SMBTransaction { - let mut tx = self.new_tx(); + ) -> Option<&mut SMBTransaction> { + let mut tx = self.new_tx()?; tx.hdr = hdr; tx.vercmd = vercmd; tx.type_data = Some(SMBTransactionTypeData::DCERPC( @@ -136,14 +136,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 { - let mut tx = self.new_tx(); + ) -> Option<&mut SMBTransaction> { + let mut tx = self.new_tx()?; tx.hdr = hdr; tx.vercmd = vercmd; tx.type_data = Some(SMBTransactionTypeData::DCERPC( @@ -152,8 +151,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( @@ -251,7 +249,9 @@ pub fn smb_write_dcerpc_record( } } - let tx = state.new_dcerpc_tx(hdr, vercmd, dcer.packet_type, dcer.call_id); + let Some(tx) = state.new_dcerpc_tx(hdr, vercmd, dcer.packet_type, dcer.call_id) else { + return false; + }; match dcer.packet_type { DCERPC_TYPE_REQUEST => { match parse_dcerpc_request_record(dcer.data, dcer.frag_len, dcer.little_endian) @@ -556,7 +556,11 @@ pub fn smb_read_dcerpc_record( }; 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 Some(tx) = + state.new_dcerpc_tx_for_response(hdr, vercmd.clone(), dcer.call_id) + else { + return false; + }; dcerpc_response_handle(tx, vercmd, &dcer); } } diff --git a/rust/src/smb/files.rs b/rust/src/smb/files.rs index 8615a9a4a3..0ac41975b0 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 @@ -89,8 +89,8 @@ 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 { - let mut tx = self.new_tx(); + ) -> Option<&mut SMBTransaction> { + 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; @@ -112,8 +112,7 @@ impl SMBState { 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 f20f45b2ce..5161937dec 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,8 +36,8 @@ impl SMBTransactionSessionSetup { } impl SMBState { - pub fn new_sessionsetup_tx(&mut self, hdr: SMBCommonHdr) -> &mut SMBTransaction { - let mut tx = self.new_tx(); + pub fn new_sessionsetup_tx(&mut self, hdr: SMBCommonHdr) -> Option<&mut SMBTransaction> { + 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) -> Option<&mut SMBTransaction> { diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index 3f9d0d374a..2519c6cbd1 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 @@ -358,8 +358,8 @@ 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 { - let mut tx = self.new_tx(); + ) -> Option<&mut SMBTransaction> { + let mut tx = self.new_tx()?; tx.type_data = Some(SMBTransactionTypeData::SETFILEPATHINFO( SMBTransactionSetFilePathInfo::new(filename, fid, subcmd, loi, delete_on_close), @@ -369,14 +369,13 @@ 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 { - let mut tx = self.new_tx(); + ) -> Option<&mut SMBTransaction> { + let mut tx = self.new_tx()?; let fid: Vec = Vec::new(); tx.type_data = Some(SMBTransactionTypeData::SETFILEPATHINFO( @@ -387,8 +386,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() } } @@ -412,8 +410,8 @@ impl SMBTransactionRename { impl SMBState { pub fn new_rename_tx( &mut self, fuid: Vec, oldname: Vec, newname: Vec, - ) -> &mut SMBTransaction { - let mut tx = self.new_tx(); + ) -> Option<&mut SMBTransaction> { + let mut tx = self.new_tx()?; tx.type_data = Some(SMBTransactionTypeData::RENAME(SMBTransactionRename::new( fuid, oldname, newname, @@ -423,8 +421,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() } } @@ -745,7 +742,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, @@ -818,7 +814,6 @@ 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, dialect_vec: None, @@ -834,27 +829,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.0.updated_tc = true; - tx_old.tx_data.0.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) { @@ -885,7 +874,6 @@ impl SMBState { self.transactions.len(), self.tx_id ); - self.tx_index_completed = 0; self.transactions.remove(index); } } @@ -942,8 +930,8 @@ impl SMBState { pub fn new_generic_tx( &mut self, smb_ver: u8, smb_cmd: u16, key: SMBCommonHdr, - ) -> &mut SMBTransaction { - let mut tx = self.new_tx(); + ) -> Option<&mut SMBTransaction> { + 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 { @@ -962,8 +950,7 @@ impl SMBState { &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) -> Option<&mut SMBTransaction> { @@ -1017,8 +1004,8 @@ impl SMBState { return None; } - pub fn new_negotiate_tx(&mut self, smb_ver: u8) -> &mut SMBTransaction { - let mut tx = self.new_tx(); + pub fn new_negotiate_tx(&mut self, smb_ver: u8) -> Option<&mut SMBTransaction> { + let mut tx = self.new_tx()?; if smb_ver == 1 { tx.vercmd.set_smb1_cmd(SMB1_COMMAND_NEGOTIATE_PROTOCOL); } else if smb_ver == 2 { @@ -1037,8 +1024,7 @@ impl SMBState { 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) -> Option<&mut SMBTransaction> { @@ -1056,8 +1042,10 @@ impl SMBState { return None; } - pub fn new_treeconnect_tx(&mut self, hdr: SMBCommonHdr, name: Vec) -> &mut SMBTransaction { - let mut tx = self.new_tx(); + pub fn new_treeconnect_tx( + &mut self, hdr: SMBCommonHdr, name: Vec, + ) -> Option<&mut SMBTransaction> { + let mut tx = self.new_tx()?; tx.hdr = hdr; tx.type_data = Some(SMBTransactionTypeData::TREECONNECT( @@ -1072,8 +1060,7 @@ impl SMBState { 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) -> Option<&mut SMBTransaction> { @@ -1094,8 +1081,8 @@ impl SMBState { pub fn new_create_tx( &mut self, file_name: &[u8], disposition: u32, del: bool, dir: bool, hdr: SMBCommonHdr, - ) -> &mut SMBTransaction { - let mut tx = self.new_tx(); + ) -> Option<&mut SMBTransaction> { + let mut tx = self.new_tx()?; tx.hdr = hdr; tx.type_data = Some(SMBTransactionTypeData::CREATE(SMBTransactionCreate::new( file_name.to_vec(), @@ -1107,8 +1094,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(&mut self, guid: &[u8]) -> (&'static str, bool) { @@ -1551,6 +1537,13 @@ impl SMBState { pub fn parse_tcp_data_ts( &mut self, flow: *mut 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 { @@ -2105,6 +2098,13 @@ impl SMBState { pub fn parse_tcp_data_tc( &mut self, flow: *mut 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 1daa55f17a..38b3eaef4f 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,9 @@ fn smb1_request_record_one( let mut oldname = rd.oldname; oldname.retain(|&i| i != 0x00); - let tx = state.new_rename_tx(Vec::new(), oldname, newname); + let Some(tx) = state.new_rename_tx(Vec::new(), oldname, newname) else { + return; + }; tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_RENAME); @@ -233,12 +235,14 @@ fn smb1_request_record_one( let tx_hdr = SMBCommonHdr::from1(r, SMBHDR_TYPE_GENERICTX); - let tx = state.new_setpathinfo_tx( + let Some(tx) = state.new_setpathinfo_tx( pd.oldname, rd.subcmd, pd.loi, disp.delete, - ); + ) else { + return; + }; tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); @@ -274,7 +278,11 @@ fn smb1_request_record_one( let fid: Vec = Vec::new(); - let tx = state.new_rename_tx(fid, pd.oldname, newname); + let Some(tx) = + state.new_rename_tx(fid, pd.oldname, newname) + else { + return; + }; tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); @@ -339,13 +347,15 @@ fn smb1_request_record_one( Some(n) => n.to_vec(), None => b"".to_vec(), }; - let tx = state.new_setfileinfo_tx( + let Some(tx) = state.new_setfileinfo_tx( filename, pd.fid.to_vec(), rd.subcmd, pd.loi, disp.delete, - ); + ) else { + return; + }; tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); @@ -387,11 +397,13 @@ fn smb1_request_record_one( Some(n) => n.to_vec(), None => b"".to_vec(), }; - let tx = state.new_rename_tx( + let Some(tx) = state.new_rename_tx( pd.fid.to_vec(), oldname, newname, - ); + ) else { + return; + }; tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb1_cmd(SMB1_COMMAND_TRANS2); @@ -498,7 +510,9 @@ fn smb1_request_record_one( None => false, }; if !found { - let tx = state.new_negotiate_tx(1); + let Some(tx) = state.new_negotiate_tx(1) else { + return; + }; if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data { tdn.dialects = dialects; } @@ -530,7 +544,11 @@ fn smb1_request_record_one( 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, cr.disposition, del, dir, tx_hdr); + let Some(tx) = + state.new_create_tx(&cr.file_name, cr.disposition, del, dir, tx_hdr) + else { + return; + }; tx.vercmd.set_smb1_cmd(command); SCLogDebug!("TS CREATE TX {} created", tx.id); true @@ -559,7 +577,9 @@ fn smb1_request_record_one( // 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 Some(tx) = state.new_treeconnect_tx(name_key, name_val) else { + return; + }; if let Some(SMBTransactionTypeData::TREECONNECT(ref mut tdn)) = tx.type_data { tdn.req_service = Some(tr.service.to_vec()); } @@ -625,7 +645,9 @@ fn smb1_request_record_one( }; 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 Some(tx) = state.new_generic_tx(1, command as u16, tx_key) else { + return; + }; SCLogDebug!( "tx {} created for {}/{}", tx.id, @@ -1083,7 +1105,10 @@ pub fn smb1_write_request_record( 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 Some(tx) = state.new_file_tx(&file_fid, &file_name, Direction::ToServer) + else { + 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 { @@ -1196,7 +1221,11 @@ pub fn smb1_read_response_record( None => false, }; if !found { - let tx = state.new_file_tx(&file_fid, &file_name, Direction::ToClient); + let Some(tx) = + state.new_file_tx(&file_fid, &file_name, Direction::ToClient) + else { + 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); @@ -1257,7 +1286,9 @@ pub fn smb1_read_response_record( 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 Some(tx) = state.new_generic_tx(1, r.command as u16, tx_key) else { + return; + }; tx.set_events(events); } } @@ -1276,7 +1307,9 @@ 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 Some(tx) = state.new_generic_tx(1, r.command as u16, tx_key) else { + 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 849b259028..d7105f43c9 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 @@ -71,7 +71,9 @@ pub fn smb1_session_setup_request(state: &mut SMBState, r: &SmbRecord, andx_offs 0, r.multiplex_id as u64, ); - let tx = state.new_sessionsetup_tx(hdr); + let Some(tx) = state.new_sessionsetup_tx(hdr) else { + 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 b8bd6b5720..ba72231360 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 @@ -252,7 +252,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 Some(tx) = state.new_file_tx(&file_guid, &file_name, Direction::ToClient) + else { + 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 if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { @@ -311,7 +314,9 @@ 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 Some(tx) = state.new_generic_tx(2, r.command, tx_key) else { + return; + }; tx.request_done = true; } match parse_smb2_request_write(r.data) { @@ -426,7 +431,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 Some(tx) = state.new_file_tx(&file_guid, &file_name, Direction::ToServer) + else { + 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 if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data { @@ -503,7 +511,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 Some(tx) = state.new_rename_tx(rd.guid.to_vec(), oldname, newname) + else { + return; + }; tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb2_cmd(SMB2_COMMAND_SET_INFO); @@ -528,13 +539,15 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) { } } }; - let tx = state.new_setfileinfo_tx( + let Some(tx) = state.new_setfileinfo_tx( fname, rd.guid.to_vec(), rd.class as u16, rd.infolvl as u16, dis.delete, - ); + ) else { + return; + }; tx.hdr = tx_hdr; tx.request_done = true; tx.vercmd.set_smb2_cmd(SMB2_COMMAND_SET_INFO); @@ -575,7 +588,9 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) { } if state.get_negotiate_tx(2).is_none() { - let tx = state.new_negotiate_tx(2); + let Some(tx) = state.new_negotiate_tx(2) else { + return; + }; if let Some(SMBTransactionTypeData::NEGOTIATE(ref mut tdn)) = tx.type_data { tdn.dialects2 = dialects; tdn.client_guid = Some(rd.client_guid.to_vec()); @@ -601,7 +616,9 @@ 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 Some(tx) = state.new_treeconnect_tx(name_key, name_val) else { + return; + }; tx.request_done = true; tx.vercmd.set_smb2_cmd(SMB2_COMMAND_TREE_CONNECT); true @@ -644,7 +661,10 @@ pub fn smb2_request_record(state: &mut SMBState, r: &Smb2Record) { 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); + let Some(tx) = state.new_create_tx(cr.data, cr.disposition, del, dir, tx_hdr) + else { + return; + }; tx.vercmd.set_smb2_cmd(r.command); SCLogDebug!("TS CREATE TX {} created", tx.id); true @@ -702,7 +722,9 @@ 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 Some(tx) = state.new_generic_tx(2, r.command, tx_key) else { + return; + }; SCLogDebug!( "TS TX {} command {} created with session_id {} tree_id {} message_id {}", tx.id, diff --git a/rust/src/smb/smb2_ioctl.rs b/rust/src/smb/smb2_ioctl.rs index fe11a386ba..668fbdae17 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 @@ -36,8 +36,8 @@ impl SMBTransactionIoctl { } impl SMBState { - pub fn new_ioctl_tx(&mut self, hdr: SMBCommonHdr, func: u32) -> &mut SMBTransaction { - let mut tx = self.new_tx(); + pub fn new_ioctl_tx(&mut self, hdr: SMBCommonHdr, func: u32) -> Option<&mut SMBTransaction> { + let mut tx = self.new_tx()?; tx.hdr = hdr; tx.type_data = Some(SMBTransactionTypeData::IOCTL(SMBTransactionIoctl::new( func, @@ -52,8 +52,7 @@ impl SMBState { &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() } } @@ -78,12 +77,16 @@ pub fn smb2_ioctl_request_record(state: &mut SMBState, r: &Smb2Record) { rd.function, &fsctl_func_to_string(rd.function) ); - let tx = state.new_ioctl_tx(hdr, rd.function); + let Some(tx) = state.new_ioctl_tx(hdr, rd.function) else { + return; + }; tx.vercmd.set_smb2_cmd(SMB2_COMMAND_IOCTL); } } _ => { - let tx = state.new_generic_tx(2, r.command, hdr); + let Some(tx) = state.new_generic_tx(2, r.command, hdr) else { + return; + }; tx.set_event(SMBEvent::MalformedData); } }; diff --git a/rust/src/smb/smb2_session.rs b/rust/src/smb/smb2_session.rs index 89db7d7265..8c32f4dfef 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 @@ -26,7 +26,9 @@ 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 Some(tx) = state.new_sessionsetup_tx(hdr) else { + return; + }; tx.vercmd.set_smb2_cmd(r.command); if let Some(SMBTransactionTypeData::SESSIONSETUP(ref mut td)) = tx.type_data {