diff --git a/rust/src/dcerpc/dcerpc.rs b/rust/src/dcerpc/dcerpc.rs index 5469b736b0..7297ff82ed 100644 --- a/rust/src/dcerpc/dcerpc.rs +++ b/rust/src/dcerpc/dcerpc.rs @@ -25,7 +25,9 @@ use std; use std::cmp; use std::ffi::CString; use std::collections::VecDeque; -use crate::conf::conf_get; +use crate::conf::{conf_get, get_memval}; + +pub static mut DCERPC_MAX_STUB_SIZE: u32 = 1048576; // Constant DCERPC UDP Header length pub const DCERPC_HDR_LEN: u16 = 16; @@ -163,6 +165,11 @@ pub fn get_req_type_for_resp(t: u8) -> u8 { _ => DCERPC_TYPE_UNKNOWN, } } +#[inline(always)] +pub fn cfg_max_stub_size() -> u32 { + unsafe { DCERPC_MAX_STUB_SIZE } +} + #[derive(Default, Debug)] pub struct DCERPCTransaction { @@ -1096,7 +1103,12 @@ fn evaluate_stub_params( } let input_slice = &input[..stub_len as usize]; - stub_data_buffer.extend_from_slice(input_slice); + let max_size = cfg_max_stub_size() as usize; + if (stub_data_buffer.len() + input_slice.len()) < max_size { + stub_data_buffer.extend_from_slice(input_slice); + } else if stub_data_buffer.len() < max_size { + stub_data_buffer.extend_from_slice(&input_slice[..max_size - stub_data_buffer.len()]); + } stub_len } @@ -1396,6 +1408,21 @@ pub unsafe extern "C" fn rs_dcerpc_register_parser() { } } SCLogDebug!("Rust DCERPC parser registered."); + let retval = conf_get("app-layer.protocols.dcerpc.max-stub-size"); + if let Some(val) = retval { + match get_memval(val) { + Ok(retval) => { + if retval > 0 { + DCERPC_MAX_STUB_SIZE = retval as u32; + } else { + SCLogError!("Invalid max-stub-size value"); + } + } + Err(_) => { + SCLogError!("Invalid max-stub-size value"); + } + } + } } else { SCLogDebug!("Protocol detector and parser disabled for DCERPC."); } diff --git a/rust/src/dcerpc/dcerpc_udp.rs b/rust/src/dcerpc/dcerpc_udp.rs index d70ca1b531..0a6213a870 100644 --- a/rust/src/dcerpc/dcerpc_udp.rs +++ b/rust/src/dcerpc/dcerpc_udp.rs @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 Open Information Security Foundation +/* Copyright (C) 2020-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 @@ -19,7 +19,7 @@ use crate::applayer::{self, *}; use crate::core::{self, Direction, DIR_BOTH}; use crate::dcerpc::dcerpc::{ DCERPCTransaction, DCERPC_MAX_TX, DCERPC_TYPE_REQUEST, DCERPC_TYPE_RESPONSE, PFCL1_FRAG, PFCL1_LASTFRAG, - rs_dcerpc_get_alstate_progress, ALPROTO_DCERPC, PARSER_NAME, + rs_dcerpc_get_alstate_progress, ALPROTO_DCERPC, PARSER_NAME, cfg_max_stub_size, }; use nom7::Err; use std; @@ -169,18 +169,27 @@ impl DCERPCUDPState { tx.tx_data.updated_ts = true; let done = (hdr.flags1 & PFCL1_FRAG) == 0 || (hdr.flags1 & PFCL1_LASTFRAG) != 0; + let max_size = cfg_max_stub_size() as usize; match hdr.pkt_type { DCERPC_TYPE_REQUEST => { - tx.stub_data_buffer_ts.extend_from_slice(input); tx.frag_cnt_ts += 1; + if input.len() + tx.stub_data_buffer_ts.len() < max_size { + tx.stub_data_buffer_ts.extend_from_slice(input); + } else if tx.stub_data_buffer_ts.len() < max_size { + tx.stub_data_buffer_ts.extend_from_slice(&input[..max_size - tx.stub_data_buffer_ts.len()]); + } if done { tx.req_done = true; } return true; } DCERPC_TYPE_RESPONSE => { - tx.stub_data_buffer_tc.extend_from_slice(input); tx.frag_cnt_tc += 1; + if input.len() + tx.stub_data_buffer_tc.len() < max_size { + tx.stub_data_buffer_tc.extend_from_slice(input); + } else if tx.stub_data_buffer_tc.len() < max_size { + tx.stub_data_buffer_tc.extend_from_slice(&input[..max_size - tx.stub_data_buffer_tc.len()]); + } if done { tx.resp_done = true; } @@ -397,7 +406,6 @@ pub unsafe extern "C" fn rs_dcerpc_udp_register_parser() { } } - #[cfg(test)] mod tests { use crate::applayer::AppLayerResult; diff --git a/rust/src/smb/dcerpc.rs b/rust/src/smb/dcerpc.rs index 6c2a2f9345..1e62241bb2 100644 --- a/rust/src/smb/dcerpc.rs +++ b/rust/src/smb/dcerpc.rs @@ -18,7 +18,7 @@ // written by Victor Julien use uuid; -use crate::smb::smb::*; +use crate::smb::smb::{cfg_max_stub_size, *}; use crate::smb::smb2::*; use crate::smb::dcerpc_records::*; use crate::smb::events::*; @@ -205,10 +205,15 @@ pub fn smb_write_dcerpc_record(state: &mut SMBState, SCLogDebug!("previous CMD {} found at tx {} => {:?}", dcer.packet_type, tx.id, tx); if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { - SCLogDebug!("additional frag of size {}", recr.data.len()); - tdn.stub_data_ts.extend_from_slice(recr.data); tdn.frag_cnt_ts += 1; - SCLogDebug!("stub_data now {}", tdn.stub_data_ts.len()); + let max_size = cfg_max_stub_size() as usize; + if recr.data.len() + tdn.stub_data_ts.len() < max_size { + SCLogDebug!("additional frag of size {}", recr.data.len()); + tdn.stub_data_ts.extend_from_slice(recr.data); + SCLogDebug!("stub_data now {}", tdn.stub_data_ts.len()); + } else if tdn.stub_data_ts.len() < max_size { + tdn.stub_data_ts.extend_from_slice(&recr.data[..max_size - tdn.stub_data_ts.len()]); + } } if dcer.last_frag { SCLogDebug!("last frag set, so request side of DCERPC closed"); @@ -240,12 +245,17 @@ pub fn smb_write_dcerpc_record(state: &mut SMBState, SCLogDebug!("DCERPC: REQUEST {:?}", recr); if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { SCLogDebug!("first frag size {}", recr.data.len()); - tdn.stub_data_ts.extend_from_slice(recr.data); tdn.opnum = recr.opnum; tdn.context_id = recr.context_id; tdn.frag_cnt_ts += 1; - SCLogDebug!("DCERPC: REQUEST opnum {} stub data len {}", - tdn.opnum, tdn.stub_data_ts.len()); + let max_size = cfg_max_stub_size() as usize; + if tdn.stub_data_ts.len() + recr.data.len() < max_size { + tdn.stub_data_ts.extend_from_slice(recr.data); + SCLogDebug!("DCERPC: REQUEST opnum {} stub data len {}", + tdn.opnum, tdn.stub_data_ts.len()); + } else if tdn.stub_data_ts.len() < max_size { + tdn.stub_data_ts.extend_from_slice(&recr.data[..max_size - tdn.stub_data_ts.len()]); + } } if dcer.last_frag { tx.request_done = true; @@ -407,8 +417,13 @@ fn dcerpc_response_handle(tx: &mut SMBTransaction, if let Some(SMBTransactionTypeData::DCERPC(ref mut tdn)) = tx.type_data { SCLogDebug!("CMD 11 found at tx {}", tx.id); tdn.set_result(DCERPC_TYPE_RESPONSE); - tdn.stub_data_tc.extend_from_slice(respr.data); + let max_size = cfg_max_stub_size() as usize; tdn.frag_cnt_tc += 1; + if tdn.stub_data_tc.len() + respr.data.len() < max_size { + tdn.stub_data_tc.extend_from_slice(respr.data); + } else if tdn.stub_data_tc.len() < max_size { + tdn.stub_data_tc.extend_from_slice(&respr.data[..max_size - tdn.stub_data_tc.len()]); + } } tx.vercmd.set_ntstatus(ntstatus); tx.response_done = dcer.last_frag; diff --git a/rust/src/smb/smb.rs b/rust/src/smb/smb.rs index c22bc9fc97..0a0fc10824 100644 --- a/rust/src/smb/smb.rs +++ b/rust/src/smb/smb.rs @@ -81,6 +81,8 @@ pub static mut SMB_CFG_MAX_WRITE_SIZE: u32 = 16777216; pub static mut SMB_CFG_MAX_WRITE_QUEUE_SIZE: u32 = 67108864; pub static mut SMB_CFG_MAX_WRITE_QUEUE_CNT: u32 = 64; +pub static mut SMB_DCERPC_MAX_STUB_SIZE: u32 = 1048576; + static mut ALPROTO_SMB: AppProto = ALPROTO_UNKNOWN; static mut SMB_MAX_TX: usize = 1024; @@ -2438,6 +2440,21 @@ pub unsafe extern "C" fn rs_smb_register_parser() { SCLogError!("Invalid value for smb.max-tx"); } } + let retval = conf_get("app-layer.protocols.smb.dcerpc.max-stub-size"); + if let Some(val) = retval { + match get_memval(val) { + Ok(retval) => { + if retval > 0 { + SMB_DCERPC_MAX_STUB_SIZE = retval as u32; + } else { + SCLogError!("Invalid max-stub-size value"); + } + } + Err(_) => { + SCLogError!("Invalid max-stub-size value"); + } + } + } SCLogConfig!("read: max record size: {}, max queued chunks {}, max queued size {}", SMB_CFG_MAX_READ_SIZE, SMB_CFG_MAX_READ_QUEUE_CNT, SMB_CFG_MAX_READ_QUEUE_SIZE); SCLogConfig!("write: max record size: {}, max queued chunks {}, max queued size {}", @@ -2446,3 +2463,9 @@ pub unsafe extern "C" fn rs_smb_register_parser() { SCLogDebug!("Protocol detector and parser disabled for SMB."); } } + +#[inline(always)] +pub fn cfg_max_stub_size() -> u32 { + unsafe { SMB_DCERPC_MAX_STUB_SIZE } +} + diff --git a/suricata.yaml.in b/suricata.yaml.in index 7640f2b62f..eab6ca5005 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -951,6 +951,8 @@ app-layer: enabled: yes # Maximum number of live DCERPC transactions per flow # max-tx: 1024 + #max-stub-size: 1MiB + ftp: enabled: yes # memcap: 64mb @@ -1015,6 +1017,8 @@ app-layer: # Stream reassembly size for SMB streams. By default track it completely. #stream-depth: 0 + #dcerpc: + # max-stub-size: 1MiB nfs: enabled: yes