Coverage Report

Created: 2021-11-03 07:11

/src/suricata/rust/src/smb/smb2_ioctl.rs
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2018 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
use crate::smb::smb::*;
19
use crate::smb::smb2::*;
20
use crate::smb::smb2_records::*;
21
use crate::smb::dcerpc::*;
22
use crate::smb::events::*;
23
#[cfg(feature = "debug")]
24
use crate::smb::funcs::*;
25
26
0
#[derive(Debug)]
27
pub struct SMBTransactionIoctl {
28
    pub func: u32,
29
}
30
31
impl SMBTransactionIoctl {
32
21.0k
    pub fn new(func: u32) -> Self {
33
21.0k
        return Self {
34
21.0k
            func: func,
35
21.0k
        }
36
21.0k
    }
37
}
38
39
impl SMBState {
40
21.0k
    pub fn new_ioctl_tx(&mut self, hdr: SMBCommonHdr, func: u32)
41
21.0k
        -> &mut SMBTransaction
42
21.0k
    {
43
21.0k
        let mut tx = self.new_tx();
44
21.0k
        tx.hdr = hdr;
45
21.0k
        tx.type_data = Some(SMBTransactionTypeData::IOCTL(
46
21.0k
                    SMBTransactionIoctl::new(func)));
47
21.0k
        tx.request_done = true;
48
21.0k
        tx.response_done = self.tc_trunc; // no response expected if tc is truncated
49
21.0k
50
21.0k
        SCLogDebug!("SMB: TX IOCTL created: ID {} FUNC {:08x}: {}",
51
21.0k
                tx.id, func, &fsctl_func_to_string(func));
52
21.0k
        self.transactions.push(tx);
53
21.0k
        let tx_ref = self.transactions.last_mut();
54
21.0k
        return tx_ref.unwrap();
55
21.0k
    }
56
}
57
58
// IOCTL responses ASYNC don't set the tree id
59
47.3k
pub fn smb2_ioctl_request_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>)
60
47.3k
{
61
47.3k
    let hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER);
62
47.3k
    match parse_smb2_request_ioctl(r.data) {
63
27.7k
        Ok((_, rd)) => {
64
            SCLogDebug!("IOCTL request data: {:?}", rd);
65
27.7k
            let is_dcerpc = if rd.is_pipe {
66
23.2k
                state.get_service_for_guid(rd.guid).1
67
            } else {
68
4.55k
                false
69
            };
70
27.7k
            if is_dcerpc {
71
6.76k
                SCLogDebug!("IOCTL request data is_pipe. Calling smb_write_dcerpc_record");
72
6.76k
                let vercmd = SMBVerCmdStat::new2(SMB2_COMMAND_IOCTL);
73
6.76k
                smb_write_dcerpc_record(state, vercmd, hdr, rd.data);
74
21.0k
            } else {
75
21.0k
                SCLogDebug!("IOCTL {:08x} {}", rd.function, &fsctl_func_to_string(rd.function));
76
21.0k
                let tx = state.new_ioctl_tx(hdr, rd.function);
77
21.0k
                tx.vercmd.set_smb2_cmd(SMB2_COMMAND_IOCTL);
78
21.0k
            }
79
        },
80
19.5k
        _ => {
81
19.5k
            let tx = state.new_generic_tx(2, r.command, hdr);
82
19.5k
            tx.set_event(SMBEvent::MalformedData);
83
19.5k
        },
84
    };
85
47.3k
}
86
87
// IOCTL responses ASYNC don't set the tree id
88
51.6k
pub fn smb2_ioctl_response_record<'b>(state: &mut SMBState, r: &Smb2Record<'b>)
89
51.6k
{
90
51.6k
    let hdr = SMBCommonHdr::from2(r, SMBHDR_TYPE_HEADER);
91
51.6k
    match parse_smb2_response_ioctl(r.data) {
92
29.6k
        Ok((_, rd)) => {
93
            SCLogDebug!("IOCTL response data: {:?}", rd);
94
95
29.6k
            let is_dcerpc = if rd.is_pipe {
96
25.7k
                state.get_service_for_guid(rd.guid).1
97
            } else {
98
3.90k
                false
99
            };
100
29.6k
            if is_dcerpc {
101
7.99k
                SCLogDebug!("IOCTL response data is_pipe. Calling smb_read_dcerpc_record");
102
7.99k
                let vercmd = SMBVerCmdStat::new2_with_ntstatus(SMB2_COMMAND_IOCTL, r.nt_status);
103
7.99k
                SCLogDebug!("TODO passing empty GUID");
104
7.99k
                smb_read_dcerpc_record(state, vercmd, hdr, &[],rd.data);
105
7.99k
            } else {
106
                SCLogDebug!("SMB2_COMMAND_IOCTL/SMB_NTSTATUS_PENDING looking for {:?}", hdr);
107
21.6k
                match state.get_generic_tx(2, SMB2_COMMAND_IOCTL, &hdr) {
108
17.0k
                    Some(tx) => {
109
17.0k
                        tx.set_status(r.nt_status, false);
110
17.0k
                        if r.nt_status != SMB_NTSTATUS_PENDING {
111
16.9k
                            tx.response_done = true;
112
16.9k
                        }
113
                    },
114
4.57k
                    None => { },
115
                }
116
            }
117
        },
118
        _ => {
119
            SCLogDebug!("SMB2_COMMAND_IOCTL/SMB_NTSTATUS_PENDING looking for {:?}", hdr);
120
22.0k
            match state.get_generic_tx(2, SMB2_COMMAND_IOCTL, &hdr) {
121
14.0k
                Some(tx) => {
122
14.0k
                    SCLogDebug!("updated status of tx {}", tx.id);
123
14.0k
                    tx.set_status(r.nt_status, false);
124
14.0k
                    if r.nt_status != SMB_NTSTATUS_PENDING {
125
12.9k
                        tx.response_done = true;
126
12.9k
                    }
127
128
                    // parsing failed for 'SUCCESS' record, set event
129
14.0k
                    if r.nt_status == SMB_NTSTATUS_SUCCESS {
130
2.06k
                        SCLogDebug!("parse fail {:?}", r);
131
2.06k
                        tx.set_event(SMBEvent::MalformedData);
132
11.9k
                    }
133
                },
134
7.98k
                _ => { },
135
            }
136
        },
137
    };
138
51.6k
}