]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
smb: fix file reopening issue
authorVictor Julien <vjulien@oisf.net>
Wed, 30 Nov 2022 05:44:40 +0000 (06:44 +0100)
committerVictor Julien <vjulien@oisf.net>
Thu, 1 Dec 2022 10:46:31 +0000 (11:46 +0100)
Fuzzing highlighted an issue where a command sequence on the same file
id triggered a logging issue:

file data for id N
close id N
file data for id N

If this happened in a single blob of data passed to the parser, the
existing file tx would be reused, the file "reopened", confusing the
file logging logic. This would trigger a debug assert.

This patch makes sure a new file tx is created for the file data
coming in after the first file tx is closed.

Bug: #5567.
(cherry picked from commit 45eb038e63604766de2828f6f25d145fea040424)

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

index 0cfb61bff1a3f29ef56304e3d0d1cb328c609b40..e2aa64033813402eb17e86cff9a1d54e1ff24153 100644 (file)
@@ -117,7 +117,32 @@ impl SMBState {
         return (tx_ref.unwrap(), files, flags)
     }
 
-    pub fn get_file_tx_by_fuid(&mut self, fuid: &Vec<u8>, direction: u8)
+    /// get file tx for a open file. Returns None if a file for the fuid exists,
+    /// but has already been closed.
+    pub fn get_file_tx_by_fuid_with_open_file(&mut self, fuid: &[u8], direction: u8)
+        -> Option<(&mut SMBTransaction, &mut FileContainer, u16)>
+    {
+        let f = fuid.to_vec();
+        for tx in &mut self.transactions {
+            let found = match tx.type_data {
+                Some(SMBTransactionTypeData::FILE(ref mut d)) => {
+                    direction == d.direction && f == d.fuid && !d.file_tracker.is_done()
+                },
+                _ => { false },
+            };
+
+            if found {
+                SCLogDebug!("SMB: Found SMB file TX with ID {}", tx.id);
+                let (files, flags) = self.files.get(direction);
+                return Some((tx, files, flags));
+            }
+        }
+        SCLogDebug!("SMB: Failed to find SMB TX with FUID {:?}", fuid);
+        return None;
+    }
+
+    /// get file tx for a fuid. File may already have been closed.
+    pub fn get_file_tx_by_fuid(&mut self, fuid: &[u8], direction: u8)
         -> Option<(&mut SMBTransaction, &mut FileContainer, u16)>
     {
         let f = fuid.to_vec();
index 2505c03707cedf2070fc9125ddc37077d5cc8013..f018a3858cb3ebc1e2f87e97ff592453e1bcc1e5 100644 (file)
@@ -897,7 +897,7 @@ pub fn smb1_write_request_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
                 None => b"<unknown>".to_vec(),
             };
             let mut set_event_fileoverlap = false;
-            let found = match state.get_file_tx_by_fuid(&file_fid, STREAM_TOSERVER) {
+            let found = match state.get_file_tx_by_fuid_with_open_file(&file_fid, STREAM_TOSERVER) {
                 Some((tx, files, flags)) => {
                     let file_id : u32 = tx.id as u32;
                     if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
@@ -990,7 +990,7 @@ pub fn smb1_read_response_record<'b>(state: &mut SMBState, r: &SmbRecord<'b>)
                         None => Vec::new(),
                     };
                     let mut set_event_fileoverlap = false;
-                    let found = match state.get_file_tx_by_fuid(&file_fid, STREAM_TOCLIENT) {
+                    let found = match state.get_file_tx_by_fuid_with_open_file(&file_fid, STREAM_TOCLIENT) {
                         Some((tx, files, flags)) => {
                             if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
                                 let file_id : u32 = tx.id as u32;
index 82f24f00849adac0136900523e6945e053b3310f..84d8978cd6a945fa80b7ca74003eb316172cf071 100644 (file)
@@ -156,7 +156,7 @@ pub fn smb2_read_response_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>)
 
             let mut set_event_fileoverlap = false;
             // look up existing tracker and if we have it update it
-            let found = match state.get_file_tx_by_fuid(&file_guid, STREAM_TOCLIENT) {
+            let found = match state.get_file_tx_by_fuid_with_open_file(&file_guid, STREAM_TOCLIENT) {
                 Some((tx, files, flags)) => {
                     if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
                         let file_id : u32 = tx.id as u32;
@@ -297,7 +297,7 @@ pub fn smb2_write_request_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>)
             };
 
             let mut set_event_fileoverlap = false;
-            let found = match state.get_file_tx_by_fuid(&file_guid, STREAM_TOSERVER) {
+            let found = match state.get_file_tx_by_fuid_with_open_file(&file_guid, STREAM_TOSERVER) {
                 Some((tx, files, flags)) => {
                     if let Some(SMBTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
                         let file_id : u32 = tx.id as u32;