1- /* Copyright (C) 2017-2022 Open Information Security Foundation
1+ /* Copyright (C) 2017-2026 Open Information Security Foundation
22 *
33 * You can copy, redistribute or modify this Program under the terms of
44 * the GNU General Public License version 2 as published by the Free
@@ -358,8 +358,8 @@ impl SMBTransactionSetFilePathInfo {
358358impl SMBState {
359359 pub fn new_setfileinfo_tx (
360360 & mut self , filename : Vec < u8 > , fid : Vec < u8 > , subcmd : u16 , loi : u16 , delete_on_close : bool ,
361- ) -> & mut SMBTransaction {
362- let mut tx = self . new_tx ( ) ;
361+ ) -> Option < & mut SMBTransaction > {
362+ let mut tx = self . new_tx ( ) ? ;
363363
364364 tx. type_data = Some ( SMBTransactionTypeData :: SETFILEPATHINFO (
365365 SMBTransactionSetFilePathInfo :: new ( filename, fid, subcmd, loi, delete_on_close) ,
@@ -369,14 +369,13 @@ impl SMBState {
369369
370370 SCLogDebug ! ( "SMB: TX SETFILEPATHINFO created: ID {}" , tx. id) ;
371371 self . transactions . push_back ( tx) ;
372- let tx_ref = self . transactions . back_mut ( ) ;
373- return tx_ref. unwrap ( ) ;
372+ self . transactions . back_mut ( )
374373 }
375374
376375 pub fn new_setpathinfo_tx (
377376 & mut self , filename : Vec < u8 > , subcmd : u16 , loi : u16 , delete_on_close : bool ,
378- ) -> & mut SMBTransaction {
379- let mut tx = self . new_tx ( ) ;
377+ ) -> Option < & mut SMBTransaction > {
378+ let mut tx = self . new_tx ( ) ? ;
380379
381380 let fid: Vec < u8 > = Vec :: new ( ) ;
382381 tx. type_data = Some ( SMBTransactionTypeData :: SETFILEPATHINFO (
@@ -387,8 +386,7 @@ impl SMBState {
387386
388387 SCLogDebug ! ( "SMB: TX SETFILEPATHINFO created: ID {}" , tx. id) ;
389388 self . transactions . push_back ( tx) ;
390- let tx_ref = self . transactions . back_mut ( ) ;
391- return tx_ref. unwrap ( ) ;
389+ self . transactions . back_mut ( )
392390 }
393391}
394392
@@ -412,8 +410,8 @@ impl SMBTransactionRename {
412410impl SMBState {
413411 pub fn new_rename_tx (
414412 & mut self , fuid : Vec < u8 > , oldname : Vec < u8 > , newname : Vec < u8 > ,
415- ) -> & mut SMBTransaction {
416- let mut tx = self . new_tx ( ) ;
413+ ) -> Option < & mut SMBTransaction > {
414+ let mut tx = self . new_tx ( ) ? ;
417415
418416 tx. type_data = Some ( SMBTransactionTypeData :: RENAME ( SMBTransactionRename :: new (
419417 fuid, oldname, newname,
@@ -423,8 +421,7 @@ impl SMBState {
423421
424422 SCLogDebug ! ( "SMB: TX RENAME created: ID {}" , tx. id) ;
425423 self . transactions . push_back ( tx) ;
426- let tx_ref = self . transactions . back_mut ( ) ;
427- return tx_ref. unwrap ( ) ;
424+ self . transactions . back_mut ( )
428425 }
429426}
430427
@@ -745,7 +742,6 @@ pub struct SMBState {
745742
746743 /// transactions list
747744 pub transactions : VecDeque < SMBTransaction > ,
748- tx_index_completed : usize ,
749745
750746 /// tx counter for assigning incrementing id's to tx's
751747 tx_id : u64 ,
@@ -818,7 +814,6 @@ impl SMBState {
818814 check_post_gap_file_txs : false ,
819815 post_gap_files_checked : false ,
820816 transactions : VecDeque :: new ( ) ,
821- tx_index_completed : 0 ,
822817 tx_id : 0 ,
823818 dialect : 0 ,
824819 dialect_vec : None ,
@@ -834,27 +829,21 @@ impl SMBState {
834829 self . _debug_tx_stats ( ) ;
835830 }
836831
837- pub fn new_tx ( & mut self ) -> SMBTransaction {
832+ pub fn new_tx ( & mut self ) -> Option < SMBTransaction > {
833+ if self . transactions . len ( ) >= unsafe { SMB_MAX_TX } {
834+ // Refuse to create a transaction once the list is at the limit. This
835+ // bounds the number of transactions a single input can create, no
836+ // matter the path (compound records, dcerpc, ...). Callers stop
837+ // using the transaction and the parser puts the flow into an error
838+ // state (see issue 8629).
839+ self . set_event ( SMBEvent :: TooManyTransactions ) ;
840+ return None ;
841+ }
838842 let mut tx = SMBTransaction :: new ( ) ;
839843 self . tx_id += 1 ;
840844 tx. id = self . tx_id ;
841845 SCLogDebug ! ( "TX {} created" , tx. id) ;
842- if self . transactions . len ( ) > unsafe { SMB_MAX_TX } {
843- let mut index = self . tx_index_completed ;
844- for tx_old in & mut self . transactions . range_mut ( self . tx_index_completed ..) {
845- index += 1 ;
846- if !tx_old. request_done || !tx_old. response_done {
847- tx_old. tx_data . 0 . updated_tc = true ;
848- tx_old. tx_data . 0 . updated_ts = true ;
849- tx_old. request_done = true ;
850- tx_old. response_done = true ;
851- tx_old. set_event ( SMBEvent :: TooManyTransactions ) ;
852- break ;
853- }
854- }
855- self . tx_index_completed = index;
856- }
857- return tx;
846+ Some ( tx)
858847 }
859848
860849 pub fn free_tx ( & mut self , tx_id : u64 ) {
@@ -885,7 +874,6 @@ impl SMBState {
885874 self . transactions. len( ) ,
886875 self . tx_id
887876 ) ;
888- self . tx_index_completed = 0 ;
889877 self . transactions . remove ( index) ;
890878 }
891879 }
@@ -942,8 +930,8 @@ impl SMBState {
942930
943931 pub fn new_generic_tx (
944932 & mut self , smb_ver : u8 , smb_cmd : u16 , key : SMBCommonHdr ,
945- ) -> & mut SMBTransaction {
946- let mut tx = self . new_tx ( ) ;
933+ ) -> Option < & mut SMBTransaction > {
934+ let mut tx = self . new_tx ( ) ? ;
947935 if smb_ver == 1 && smb_cmd <= 255 {
948936 tx. vercmd . set_smb1_cmd ( smb_cmd as u8 ) ;
949937 } else if smb_ver == 2 {
@@ -962,8 +950,7 @@ impl SMBState {
962950 & tx
963951 ) ;
964952 self . transactions . push_back ( tx) ;
965- let tx_ref = self . transactions . back_mut ( ) ;
966- return tx_ref. unwrap ( ) ;
953+ self . transactions . back_mut ( )
967954 }
968955
969956 pub fn get_last_tx ( & mut self , smb_ver : u8 , smb_cmd : u16 ) -> Option < & mut SMBTransaction > {
@@ -1017,8 +1004,8 @@ impl SMBState {
10171004 return None ;
10181005 }
10191006
1020- pub fn new_negotiate_tx ( & mut self , smb_ver : u8 ) -> & mut SMBTransaction {
1021- let mut tx = self . new_tx ( ) ;
1007+ pub fn new_negotiate_tx ( & mut self , smb_ver : u8 ) -> Option < & mut SMBTransaction > {
1008+ let mut tx = self . new_tx ( ) ? ;
10221009 if smb_ver == 1 {
10231010 tx. vercmd . set_smb1_cmd ( SMB1_COMMAND_NEGOTIATE_PROTOCOL ) ;
10241011 } else if smb_ver == 2 {
@@ -1037,8 +1024,7 @@ impl SMBState {
10371024 smb_ver
10381025 ) ;
10391026 self . transactions . push_back ( tx) ;
1040- let tx_ref = self . transactions . back_mut ( ) ;
1041- return tx_ref. unwrap ( ) ;
1027+ self . transactions . back_mut ( )
10421028 }
10431029
10441030 pub fn get_negotiate_tx ( & mut self , smb_ver : u8 ) -> Option < & mut SMBTransaction > {
@@ -1056,8 +1042,10 @@ impl SMBState {
10561042 return None ;
10571043 }
10581044
1059- pub fn new_treeconnect_tx ( & mut self , hdr : SMBCommonHdr , name : Vec < u8 > ) -> & mut SMBTransaction {
1060- let mut tx = self . new_tx ( ) ;
1045+ pub fn new_treeconnect_tx (
1046+ & mut self , hdr : SMBCommonHdr , name : Vec < u8 > ,
1047+ ) -> Option < & mut SMBTransaction > {
1048+ let mut tx = self . new_tx ( ) ?;
10611049
10621050 tx. hdr = hdr;
10631051 tx. type_data = Some ( SMBTransactionTypeData :: TREECONNECT (
@@ -1072,8 +1060,7 @@ impl SMBState {
10721060 String :: from_utf8_lossy( & name)
10731061 ) ;
10741062 self . transactions . push_back ( tx) ;
1075- let tx_ref = self . transactions . back_mut ( ) ;
1076- return tx_ref. unwrap ( ) ;
1063+ self . transactions . back_mut ( )
10771064 }
10781065
10791066 pub fn get_treeconnect_tx ( & mut self , hdr : SMBCommonHdr ) -> Option < & mut SMBTransaction > {
@@ -1094,8 +1081,8 @@ impl SMBState {
10941081
10951082 pub fn new_create_tx (
10961083 & mut self , file_name : & [ u8 ] , disposition : u32 , del : bool , dir : bool , hdr : SMBCommonHdr ,
1097- ) -> & mut SMBTransaction {
1098- let mut tx = self . new_tx ( ) ;
1084+ ) -> Option < & mut SMBTransaction > {
1085+ let mut tx = self . new_tx ( ) ? ;
10991086 tx. hdr = hdr;
11001087 tx. type_data = Some ( SMBTransactionTypeData :: CREATE ( SMBTransactionCreate :: new (
11011088 file_name. to_vec ( ) ,
@@ -1107,8 +1094,7 @@ impl SMBState {
11071094 tx. response_done = self . tc_trunc ; // no response expected if tc is truncated
11081095
11091096 self . transactions . push_back ( tx) ;
1110- let tx_ref = self . transactions . back_mut ( ) ;
1111- return tx_ref. unwrap ( ) ;
1097+ self . transactions . back_mut ( )
11121098 }
11131099
11141100 pub fn get_service_for_guid ( & mut self , guid : & [ u8 ] ) -> ( & ' static str , bool ) {
@@ -1551,6 +1537,13 @@ impl SMBState {
15511537 pub fn parse_tcp_data_ts (
15521538 & mut self , flow : * mut Flow , stream_slice : & StreamSlice ,
15531539 ) -> AppLayerResult {
1540+ // The transaction list is full: new_tx() is refusing to create more, so
1541+ // put the flow into an error state and stop processing it (see issue
1542+ // 8629).
1543+ if self . transactions . len ( ) >= unsafe { SMB_MAX_TX } {
1544+ self . set_event ( SMBEvent :: TooManyTransactions ) ;
1545+ return AppLayerResult :: err ( ) ;
1546+ }
15541547 let mut cur_i = stream_slice. as_slice ( ) ;
15551548 let consumed = self . handle_skip ( Direction :: ToServer , cur_i. len ( ) as u32 ) ;
15561549 if consumed > 0 {
@@ -2105,6 +2098,13 @@ impl SMBState {
21052098 pub fn parse_tcp_data_tc (
21062099 & mut self , flow : * mut Flow , stream_slice : & StreamSlice ,
21072100 ) -> AppLayerResult {
2101+ // The transaction list is full: new_tx() is refusing to create more, so
2102+ // put the flow into an error state and stop processing it (see issue
2103+ // 8629).
2104+ if self . transactions . len ( ) >= unsafe { SMB_MAX_TX } {
2105+ self . set_event ( SMBEvent :: TooManyTransactions ) ;
2106+ return AppLayerResult :: err ( ) ;
2107+ }
21082108 let mut cur_i = stream_slice. as_slice ( ) ;
21092109 let consumed = self . handle_skip ( Direction :: ToClient , cur_i. len ( ) as u32 ) ;
21102110 if consumed > 0 {
0 commit comments