Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backports 602/b3/v1 #5915

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion rust/src/applayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,8 @@ extern {
}

// Defined in app-layer-parser.h
pub const APP_LAYER_PARSER_EOF : u8 = 0b0;
pub const APP_LAYER_PARSER_EOF_TS : u8 = 0b0101;
pub const APP_LAYER_PARSER_EOF_TC : u8 = 0b0110;
pub const APP_LAYER_PARSER_NO_INSPECTION : u8 = 0b1;
pub const APP_LAYER_PARSER_NO_REASSEMBLY : u8 = 0b10;
pub const APP_LAYER_PARSER_NO_INSPECTION_PAYLOAD : u8 = 0b100;
Expand Down
4 changes: 2 additions & 2 deletions rust/src/applayertemplate/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ pub extern "C" fn rs_template_parse_request(
_flags: u8,
) -> AppLayerResult {
let eof = unsafe {
if AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF) > 0 {
if AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TS) > 0 {
true
} else {
false
Expand Down Expand Up @@ -352,7 +352,7 @@ pub extern "C" fn rs_template_parse_response(
_flags: u8,
) -> AppLayerResult {
let _eof = unsafe {
if AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF) > 0 {
if AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF_TC) > 0 {
true
} else {
false
Expand Down
12 changes: 12 additions & 0 deletions rust/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ pub type SCLogMessageFunc =
pub type DetectEngineStateFreeFunc =
extern "C" fn(state: *mut DetectEngineState);

pub type AppLayerParserTriggerRawStreamReassemblyFunc =
extern "C" fn (flow: *const Flow, direction: i32);
pub type AppLayerDecoderEventsSetEventRawFunc =
extern "C" fn (events: *mut *mut AppLayerDecoderEvents,
event: u8);
Expand Down Expand Up @@ -129,6 +131,7 @@ pub struct SuricataContext {
DetectEngineStateFree: DetectEngineStateFreeFunc,
AppLayerDecoderEventsSetEventRaw: AppLayerDecoderEventsSetEventRawFunc,
AppLayerDecoderEventsFreeEvents: AppLayerDecoderEventsFreeEventsFunc,
pub AppLayerParserTriggerRawStreamReassembly: AppLayerParserTriggerRawStreamReassemblyFunc,

pub FileOpenFile: SCFileOpenFileWithId,
pub FileCloseFile: SCFileCloseFileById,
Expand Down Expand Up @@ -176,6 +179,15 @@ pub fn sc_detect_engine_state_free(state: *mut DetectEngineState)
}
}

/// AppLayerParserTriggerRawStreamReassembly wrapper
pub fn sc_app_layer_parser_trigger_raw_stream_reassembly(flow: *const Flow, direction: i32) {
unsafe {
if let Some(c) = SC {
(c.AppLayerParserTriggerRawStreamReassembly)(flow, direction);
}
}
}

/// AppLayerDecoderEventsSetEventRaw wrapper.
pub fn sc_app_layer_decoder_events_set_event_raw(
events: *mut *mut AppLayerDecoderEvents, event: u8)
Expand Down
76 changes: 72 additions & 4 deletions rust/src/dcerpc/dcerpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
*/

use std::mem::transmute;
use crate::applayer::{AppLayerResult, AppLayerTxData};
use crate::core::{self, sc_detect_engine_state_free};
use crate::applayer::*;
use crate::core::{self, *};
use crate::dcerpc::parser;
use nom::error::ErrorKind;
use nom::number::Endianness;
Expand Down Expand Up @@ -350,6 +350,7 @@ pub struct DCERPCState {
pub tc_ssn_gap: bool,
pub ts_ssn_trunc: bool, /// true if Truncated in this direction
pub tc_ssn_trunc: bool,
pub flow: Option<*const core::Flow>,
}

impl DCERPCState {
Expand All @@ -376,6 +377,7 @@ impl DCERPCState {
tc_ssn_gap: false,
ts_ssn_trunc: false,
tc_ssn_trunc: false,
flow: None,
};
}

Expand Down Expand Up @@ -618,6 +620,9 @@ impl DCERPCState {
tx.req_lost = true;
}
tx.req_done = true;
if let Some(flow) = self.flow {
sc_app_layer_parser_trigger_raw_stream_reassembly(flow, dir.into());
}
}
} else if self.tc_ssn_gap && dir == core::STREAM_TOCLIENT {
for tx in &mut self.transactions {
Expand All @@ -633,6 +638,9 @@ impl DCERPCState {
}
tx.req_done = true;
tx.resp_done = true;
if let Some(flow) = self.flow {
sc_app_layer_parser_trigger_raw_stream_reassembly(flow, dir.into());
}
}
}
}
Expand Down Expand Up @@ -745,6 +753,9 @@ impl DCERPCState {
let mut tx = self.create_tx(call_id);
tx.req_cmd = self.get_hdr_type().unwrap_or(0);
tx.req_done = true;
if let Some(flow) = self.flow {
sc_app_layer_parser_trigger_raw_stream_reassembly(flow, core::STREAM_TOSERVER.into());
}
tx.frag_cnt_ts = 1;
self.transactions.push(tx);
// Bytes parsed with `parse_dcerpc_bind` + (bytes parsed per bindctxitem [44] * number
Expand Down Expand Up @@ -827,6 +838,9 @@ impl DCERPCState {
);
tx.req_done = true;
tx.frag_cnt_ts = 1;
if let Some(flow) = self.flow {
sc_app_layer_parser_trigger_raw_stream_reassembly(flow, core::STREAM_TOSERVER.into());
}
}
DCERPC_TYPE_RESPONSE => {
retval = evaluate_stub_params(
Expand All @@ -839,6 +853,9 @@ impl DCERPCState {
);
tx.resp_done = true;
tx.frag_cnt_tc = 1;
if let Some(flow) = self.flow {
sc_app_layer_parser_trigger_raw_stream_reassembly(flow, core::STREAM_TOCLIENT.into());
}
}
_ => {
SCLogDebug!("Unrecognized packet type");
Expand Down Expand Up @@ -1069,6 +1086,9 @@ impl DCERPCState {
};
tx.resp_done = true;
tx.frag_cnt_tc = 1;
if let Some(flow) = self.flow {
sc_app_layer_parser_trigger_raw_stream_reassembly(flow, core::STREAM_TOCLIENT.into());
}
self.handle_bind_cache(current_call_id, false);
}
DCERPC_TYPE_REQUEST => {
Expand Down Expand Up @@ -1163,7 +1183,7 @@ pub extern "C" fn rs_parse_dcerpc_response_gap(

#[no_mangle]
pub extern "C" fn rs_dcerpc_parse_request(
_flow: *mut core::Flow, state: &mut DCERPCState, _pstate: *mut std::os::raw::c_void,
flow: *mut core::Flow, state: &mut DCERPCState, _pstate: *mut std::os::raw::c_void,
input: *const u8, input_len: u32, _data: *mut std::os::raw::c_void, flags: u8,
) -> AppLayerResult {
SCLogDebug!("Handling request: input {:p} input_len {} flags {:x} EOF {}",
Expand All @@ -1177,14 +1197,15 @@ pub extern "C" fn rs_dcerpc_parse_request(
}
if input_len > 0 && input != std::ptr::null_mut() {
let buf = build_slice!(input, input_len as usize);
state.flow = Some(flow);
return state.handle_input_data(buf, core::STREAM_TOSERVER);
}
AppLayerResult::err()
}

#[no_mangle]
pub extern "C" fn rs_dcerpc_parse_response(
_flow: *mut core::Flow, state: &mut DCERPCState, _pstate: *mut std::os::raw::c_void,
flow: *mut core::Flow, state: &mut DCERPCState, _pstate: *mut std::os::raw::c_void,
input: *const u8, input_len: u32, _data: *mut std::os::raw::c_void, flags: u8,
) -> AppLayerResult {
if flags & core::STREAM_EOF != 0 && input_len == 0 {
Expand All @@ -1197,6 +1218,7 @@ pub extern "C" fn rs_dcerpc_parse_response(
if input_len > 0 {
if input != std::ptr::null_mut() {
let buf = build_slice!(input, input_len as usize);
state.flow = Some(flow);
return state.handle_input_data(buf, core::STREAM_TOCLIENT);
}
}
Expand Down Expand Up @@ -1229,12 +1251,18 @@ pub extern "C" fn rs_dcerpc_state_trunc(state: *mut std::os::raw::c_void, direct
dce_state.ts_ssn_trunc = true;
for tx in &mut dce_state.transactions {
tx.req_done = true;
if let Some(flow) = dce_state.flow {
sc_app_layer_parser_trigger_raw_stream_reassembly(flow, core::STREAM_TOSERVER.into());
}
}
SCLogDebug!("dce_state.ts_ssn_trunc = true; txs {}", dce_state.transactions.len());
} else if direction & core::STREAM_TOCLIENT != 0 {
dce_state.tc_ssn_trunc = true;
for tx in &mut dce_state.transactions {
tx.resp_done = true;
if let Some(flow) = dce_state.flow {
sc_app_layer_parser_trigger_raw_stream_reassembly(flow, core::STREAM_TOCLIENT.into());
}
}
SCLogDebug!("dce_state.tc_ssn_trunc = true; txs {}", dce_state.transactions.len());
}
Expand Down Expand Up @@ -1323,6 +1351,46 @@ pub unsafe extern "C" fn rs_dcerpc_get_stub_data(
*endianness = tx.get_endianness();
}

/// Probe input to see if it looks like DCERPC.
fn probe(input: &[u8]) -> (bool, bool) {
match parser::parse_dcerpc_header(input) {
Ok((_, hdr)) => {
let is_request = hdr.hdrtype == 0x00;
let is_dcerpc = hdr.rpc_vers == 0x05 && hdr.rpc_vers_minor == 0x00;
return (is_dcerpc, is_request);
},
Err(_) => (false, false),
}
}

#[no_mangle]
pub extern "C" fn rs_dcerpc_probe_tcp(direction: u8, input: *const u8,
len: u32, rdir: *mut u8) -> i32
{
SCLogDebug!("Probing packet for DCERPC");
if len == 0 {
return core::ALPROTO_UNKNOWN;
}
let slice: &[u8] = unsafe {
std::slice::from_raw_parts(input as *mut u8, len as usize)
};
//is_incomplete is checked by caller
let (is_dcerpc, is_request, ) = probe(slice);
if is_dcerpc {
let dir = if is_request {
core::STREAM_TOSERVER
} else {
core::STREAM_TOCLIENT
};
if direction & (core::STREAM_TOSERVER|core::STREAM_TOCLIENT) != dir {
unsafe { *rdir = dir };
}
return 1;
}
return 0;

}

#[cfg(test)]
mod tests {
use crate::applayer::AppLayerResult;
Expand Down
46 changes: 45 additions & 1 deletion rust/src/dcerpc/dcerpc_udp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ pub extern "C" fn rs_dcerpc_udp_get_tx(
let dce_state = cast_pointer!(state, DCERPCUDPState);
match dce_state.get_tx(tx_id) {
Some(tx) => {
return unsafe{transmute(tx)};
return unsafe{&mut *(tx as *mut DCERPCTransaction)};
},
None => {
return std::ptr::null_mut();
Expand All @@ -289,6 +289,50 @@ pub extern "C" fn rs_dcerpc_udp_get_tx_cnt(vtx: *mut std::os::raw::c_void) -> u6
dce_state.tx_id
}

/// Probe input to see if it looks like DCERPC.
fn probe(input: &[u8]) -> (bool, bool) {
match parser::parse_dcerpc_udp_header(input) {
Ok((_, hdr)) => {
let is_request = hdr.pkt_type == 0x00;
let is_dcerpc = hdr.rpc_vers == 0x04 &&
(hdr.flags2 & 0xfc == 0) &&
(hdr.drep[0] & 0xee == 0) &&
(hdr.drep[1] <= 3);
return (is_dcerpc, is_request);
},
Err(_) => (false, false),
}
}

#[no_mangle]
pub extern "C" fn rs_dcerpc_probe_udp(direction: u8, input: *const u8,
len: u32, rdir: *mut u8) -> i32
{
SCLogDebug!("Probing the packet for DCERPC/UDP");
if len == 0 {
return core::ALPROTO_UNKNOWN;
}
let slice: &[u8] = unsafe {
std::slice::from_raw_parts(input as *mut u8, len as usize)
};
//is_incomplete is checked by caller
let (is_dcerpc, is_request) = probe(slice);
if is_dcerpc {
let dir = if is_request {
core::STREAM_TOSERVER
} else {
core::STREAM_TOCLIENT
};
if direction & (core::STREAM_TOSERVER|core::STREAM_TOCLIENT) != dir {
unsafe { *rdir = dir };
}
return 1;
}
return 0;

}


#[cfg(test)]
mod tests {
use crate::applayer::AppLayerResult;
Expand Down
22 changes: 19 additions & 3 deletions src/app-layer-dcerpc-udp.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,27 @@ static int RustDCERPCUDPGetAlstateProgress(void *tx, uint8_t direction)
return rs_dcerpc_get_alstate_progress(tx, direction);
}

static uint16_t DCERPCUDPProbe(
Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir)
{
SCLogDebug("DCERPCUDPProbe");

const int r = rs_dcerpc_probe_udp(direction, input, len, rdir);
switch (r) {
case 1:
return ALPROTO_DCERPC;
case 0:
return ALPROTO_UNKNOWN;
case -1:
default:
return ALPROTO_FAILED;
}
}

static int DCERPCUDPRegisterPatternsForProtocolDetection(void)
{
if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_UDP, ALPROTO_DCERPC,
"|04 00|", 2, 0, STREAM_TOSERVER) < 0)
{
if (AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_UDP, ALPROTO_DCERPC, "|04 00|", 2, 0,
STREAM_TOSERVER, DCERPCUDPProbe, 0, 0) < 0) {
return -1;
}

Expand Down
27 changes: 21 additions & 6 deletions src/app-layer-dcerpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,16 +126,31 @@ static int DCERPCGetAlstateProgress(void *tx, uint8_t direction)
return rs_dcerpc_get_alstate_progress(tx, direction);
}

static uint16_t DCERPCTCPProbe(
Flow *f, uint8_t direction, const uint8_t *input, uint32_t len, uint8_t *rdir)
{
SCLogDebug("DCERPCTCPProbe");

const int r = rs_dcerpc_probe_tcp(direction, input, len, rdir);
switch (r) {
case 1:
return ALPROTO_DCERPC;
case 0:
return ALPROTO_UNKNOWN;
case -1:
default:
return ALPROTO_FAILED;
}
}

static int DCERPCRegisterPatternsForProtocolDetection(void)
{
if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_DCERPC,
"|05 00|", 2, 0, STREAM_TOSERVER) < 0)
{
if (AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_DCERPC, "|05 00|", 2, 0,
STREAM_TOSERVER, DCERPCTCPProbe, 0, 0) < 0) {
return -1;
}
if (AppLayerProtoDetectPMRegisterPatternCS(IPPROTO_TCP, ALPROTO_DCERPC,
"|05 00|", 2, 0, STREAM_TOCLIENT) < 0)
{
if (AppLayerProtoDetectPMRegisterPatternCSwPP(IPPROTO_TCP, ALPROTO_DCERPC, "|05 00|", 2, 0,
STREAM_TOCLIENT, DCERPCTCPProbe, 0, 0) < 0) {
return -1;
}

Expand Down
1 change: 1 addition & 0 deletions src/rust-context.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ typedef struct SuricataContext_ {
void (*AppLayerDecoderEventsSetEventRaw)(AppLayerDecoderEvents **,
uint8_t);
void (*AppLayerDecoderEventsFreeEvents)(AppLayerDecoderEvents **);
void (*AppLayerParserTriggerRawStreamReassembly)(Flow *, int direction);

int (*FileOpenFileWithId)(FileContainer *, const StreamingBufferConfig *,
uint32_t track_id, const uint8_t *name, uint16_t name_len,
Expand Down
2 changes: 2 additions & 0 deletions src/suricata.c
Original file line number Diff line number Diff line change
Expand Up @@ -2678,6 +2678,8 @@ int InitGlobal(void) {
suricata_context.DetectEngineStateFree = DetectEngineStateFree;
suricata_context.AppLayerDecoderEventsSetEventRaw = AppLayerDecoderEventsSetEventRaw;
suricata_context.AppLayerDecoderEventsFreeEvents = AppLayerDecoderEventsFreeEvents;
suricata_context.AppLayerParserTriggerRawStreamReassembly =
AppLayerParserTriggerRawStreamReassembly;

suricata_context.FileOpenFileWithId = FileOpenFileWithId;
suricata_context.FileCloseFileById = FileCloseFileById;
Expand Down