rust/nfs: implement events

Remove lots of panic statements in favor of setting non-fatal events.

Bug #2175.
pull/2835/head
Victor Julien 8 years ago
parent 3e9b583d47
commit a306ccfd34

@ -9,4 +9,5 @@ modbus-events.rules \
app-layer-events.rules \
files.rules \
dnp3-events.rules \
ntp-events.rules
ntp-events.rules \
nfs-events.rules

@ -0,0 +1,8 @@
# NFS app layer event rules
#
# SID's fall in the 2223000+ range. See https://redmine.openinfosecfoundation.org/projects/suricata/wiki/AppLayer
#
# These sigs fire at most once per connection.
#
alert nfs any any -> any any (msg:"SURICATA NFS malformed request data"; flow:to_server; app-layer-event:nfs.malformed_data; classtype:protocol-command-decode; sid:2223000; rev:1;)
alert nfs any any -> any any (msg:"SURICATA NFS malformed response data"; flow:to_client; app-layer-event:nfs.malformed_data; classtype:protocol-command-decode; sid:2223001; rev:1;)

@ -84,7 +84,9 @@ type_map = {
"DetectEngineState": "DetectEngineState",
"core::DetectEngineState": "DetectEngineState",
"core::AppLayerDecoderEvents": "AppLayerDecoderEvents",
"AppLayerDecoderEvents": "AppLayerDecoderEvents",
"core::AppLayerEventType": "AppLayerEventType",
"AppLayerEventType": "AppLayerEventType",
"CLuaState": "lua_State",
"Store": "Store",
}

@ -22,6 +22,7 @@ extern crate libc;
use std;
use std::mem::transmute;
use std::collections::{HashMap};
use std::ffi::CStr;
use nom;
use nom::IResult;
@ -91,6 +92,14 @@ pub static mut SURICATA_NFS3_FILE_CONFIG: Option<&'static SuricataFileContext> =
* Transaction lookup.
*/
#[repr(u32)]
pub enum NFSEvent {
MalformedData = 0,
/* remove 'Padding' when more events are added. Rustc 1.7 won't
* accept a single field enum with repr(u32) */
Padding,
}
#[derive(Debug)]
pub enum NFSTransactionTypeData {
RENAME(Vec<u8>),
@ -305,6 +314,8 @@ pub struct NFSState {
pub nfs_version: u16,
pub events: u16,
/// tx counter for assigning incrementing id's to tx's
tx_id: u64,
@ -336,6 +347,7 @@ impl NFSState {
tc_gap:false,
is_udp:false,
nfs_version:0,
events:0,
tx_id:0,
de_state_count:0,
//ts_txs_updated:false,
@ -407,6 +419,18 @@ impl NFSState {
return None;
}
/// Set an event. The event is set on the most recent transaction.
pub fn set_event(&mut self, event: NFSEvent) {
let len = self.transactions.len();
if len == 0 {
return;
}
let mut tx = &mut self.transactions[len - 1];
sc_app_layer_decoder_events_set_event_raw(&mut tx.events, event as u8);
self.events += 1;
}
// TODO maybe not enough users to justify a func
fn mark_response_tx_done(&mut self, xid: u32, rpc_status: u32, nfs_status: u32, resp_handle: &Vec<u8>)
{
@ -436,7 +460,9 @@ impl NFSState {
SCLogDebug!("LOOKUP {:?}", lookup);
xidmap.file_name = lookup.name_vec;
},
IResult::Incomplete(_) => { panic!("WEIRD: parse_nfs3_request_lookup said: incomplete"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
}
@ -475,7 +501,9 @@ impl NFSState {
xidmap.file_handle = ar.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_GETATTR {
@ -484,7 +512,9 @@ impl NFSState {
xidmap.file_handle = gar.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_READDIRPLUS {
@ -493,7 +523,9 @@ impl NFSState {
xidmap.file_handle = rdp.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_READ {
@ -503,7 +535,9 @@ impl NFSState {
xidmap.file_handle = nfs3_read_record.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_WRITE {
@ -511,7 +545,9 @@ impl NFSState {
IResult::Done(_, w) => {
self.process_write_record(r, &w);
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
}
} else if r.procedure == NFSPROC3_CREATE {
@ -520,7 +556,9 @@ impl NFSState {
xidmap.file_handle = nfs3_create_record.handle.value.to_vec();
xidmap.file_name = nfs3_create_record.name_vec;
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
@ -530,7 +568,9 @@ impl NFSState {
xidmap.file_handle = rr.handle.value.to_vec();
xidmap.file_name = rr.name_vec;
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
@ -541,7 +581,9 @@ impl NFSState {
xidmap.file_name = rr.from_name_vec;
aux_file_name = rr.to_name_vec;
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_MKDIR {
@ -550,7 +592,9 @@ impl NFSState {
xidmap.file_handle = mr.handle.value.to_vec();
xidmap.file_name = mr.name_vec;
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_RMDIR {
@ -559,7 +603,9 @@ impl NFSState {
xidmap.file_handle = rr.handle.value.to_vec();
xidmap.file_name = rr.name_vec;
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_COMMIT {
@ -585,7 +631,9 @@ impl NFSState {
}
//self.ts_txs_updated = true;
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
}
@ -663,7 +711,9 @@ impl NFSState {
xidmap.file_handle = ar.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if r.procedure == NFSPROC3_READ {
@ -673,7 +723,9 @@ impl NFSState {
xidmap.file_handle = read_record.handle.value.to_vec();
self.xidmap_handle2name(&mut xidmap);
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
}
@ -839,7 +891,7 @@ impl NFSState {
}
fn process_reply_record_v3<'b>(&mut self, r: &RpcReplyPacket<'b>, xidmap: &mut NFSRequestXidMap) -> u32 {
let nfs_status;
let mut nfs_status = 0;
let mut resp_handle = Vec::new();
if xidmap.procedure == NFSPROC3_LOOKUP {
@ -854,7 +906,9 @@ impl NFSState {
self.namemap.insert(lookup.handle.value.to_vec(), xidmap.file_name.to_vec());
resp_handle = lookup.handle.value.to_vec();
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if xidmap.procedure == NFSPROC3_CREATE {
@ -875,7 +929,9 @@ impl NFSState {
}
},
IResult::Incomplete(_) => { panic!("WEIRD"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
};
} else if xidmap.procedure == NFSPROC3_READ {
@ -884,7 +940,9 @@ impl NFSState {
self.process_read_record(r, reply, Some(&xidmap));
nfs_status = reply.status;
},
IResult::Incomplete(_) => { panic!("Incomplete!"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
}
} else if xidmap.procedure == NFSPROC3_READDIRPLUS {
@ -919,11 +977,15 @@ impl NFSState {
SCLogDebug!("READDIRPLUS ENTRIES reply {:?}", entries);
},
IResult::Incomplete(_) => { panic!("Incomplete!"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
}
},
IResult::Incomplete(_) => { panic!("Incomplete!"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
}
}
@ -948,7 +1010,7 @@ impl NFSState {
}
fn process_reply_record_v2<'b>(&mut self, r: &RpcReplyPacket<'b>, xidmap: &NFSRequestXidMap) -> u32 {
let nfs_status;
let mut nfs_status = 0;
let resp_handle = Vec::new();
if xidmap.procedure == NFSPROC3_READ {
@ -958,7 +1020,9 @@ impl NFSState {
self.process_read_record(r, reply, Some(&xidmap));
nfs_status = reply.status;
},
IResult::Incomplete(_) => { panic!("Incomplete!"); },
IResult::Incomplete(_) => {
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
}
} else {
@ -1348,7 +1412,7 @@ impl NFSState {
cur_i = remaining; // progress input past parsed record
},
IResult::Incomplete(_) => {
SCLogDebug!("TS WRITE record incomplete");
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
}
@ -1375,11 +1439,15 @@ impl NFSState {
cur_i = &cur_i[rec_size..];
status |= self.process_request_record(rpc_record);
},
IResult::Incomplete(x) => {
// should be unreachable unless our rec_size calc is off
panic!("TS data incomplete while we checked for rec_size? BUG {:?}", x);
//self.tcp_buffer_ts.extend_from_slice(cur_i);
//break;
IResult::Incomplete(_) => {
cur_i = &cur_i[rec_size..]; // progress input past parsed record
// we shouldn't get incomplete as we have the full data
// so if we got incomplete anyway it's the data that is
// bad.
self.set_event(NFSEvent::MalformedData);
status = 1;
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); //break
},
@ -1487,7 +1555,7 @@ impl NFSState {
cur_i = remaining; // progress input past parsed record
},
IResult::Incomplete(_) => {
SCLogDebug!("TS WRITE record incomplete");
self.set_event(NFSEvent::MalformedData);
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); },
}
@ -1512,10 +1580,14 @@ impl NFSState {
status |= self.process_reply_record(rpc_record);
},
IResult::Incomplete(_) => {
cur_i = &cur_i[rec_size..]; // progress input past parsed record
// we shouldn't get incomplete as we have the full data
panic!("TC data incomplete, BUG!");
//self.tcp_buffer_tc.extend_from_slice(cur_i);
//break;
// so if we got incomplete anyway it's the data that is
// bad.
self.set_event(NFSEvent::MalformedData);
status = 1;
},
IResult::Error(e) => { panic!("Parsing failed: {:?}",e); //break
},
@ -1838,6 +1910,55 @@ pub extern "C" fn rs_nfs3_state_get_tx_detect_state(
}
}
#[no_mangle]
pub extern "C" fn rs_nfs_state_has_events(state: &mut NFSState) -> u8 {
if state.events > 0 {
return 1;
}
return 0;
}
#[no_mangle]
pub extern "C" fn rs_nfs_state_get_events(state: &mut NFSState,
tx_id: libc::uint64_t)
-> *mut AppLayerDecoderEvents
{
match state.get_tx_by_id(tx_id) {
Some(tx) => {
return tx.events;
}
_ => {
return std::ptr::null_mut();
}
}
}
#[no_mangle]
pub extern "C" fn rs_nfs_state_get_event_info(event_name: *const libc::c_char,
event_id: *mut libc::c_int,
event_type: *mut AppLayerEventType)
-> i8
{
if event_name == std::ptr::null() {
return -1;
}
let c_event_name: &CStr = unsafe { CStr::from_ptr(event_name) };
let event = match c_event_name.to_str() {
Ok(s) => {
match s {
"malformed_data" => NFSEvent::MalformedData as i32,
_ => -1, // unknown event
}
},
Err(_) => -1, // UTF-8 conversion failed
};
unsafe{
*event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
*event_id = event as libc::c_int;
};
0
}
/// return procedure(s) in the tx. At 0 return the main proc,
/// otherwise get procs from the 'file_additional_procs'.
/// Keep calling until 0 is returned.

@ -95,43 +95,21 @@ static void NFSTCPStateTxFree(void *state, uint64_t tx_id)
rs_nfs3_state_tx_free(state, tx_id);
}
#if 0
static int NFSTCPStateGetEventInfo(const char *event_name, int *event_id,
AppLayerEventType *event_type)
{
*event_id = SCMapEnumNameToValue(event_name, nfs_decoder_event_table);
if (*event_id == -1) {
SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
"nfs enum map table.", event_name);
/* This should be treated as fatal. */
return -1;
return rs_nfs_state_get_event_info(event_name, event_id, event_type);
}
*event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
return 0;
}
static AppLayerDecoderEvents *NFSTCPGetEvents(void *state, uint64_t tx_id)
static int NFSTCPHasEvents(void *state)
{
NFSTCPState *nfs_state = state;
NFSTCPTransaction *tx;
TAILQ_FOREACH(tx, &nfs_state->tx_list, next) {
if (tx->tx_id == tx_id) {
return tx->decoder_events;
}
}
return NULL;
return rs_nfs_state_has_events(state);
}
static int NFSTCPHasEvents(void *state)
static AppLayerDecoderEvents *NFSTCPGetEvents(void *state, uint64_t id)
{
NFSTCPState *echo = state;
return echo->events;
return rs_nfs_state_get_events(state, id);
}
#endif
/**
* \brief Probe the input to see if it looks like echo.
@ -352,17 +330,17 @@ void RegisterNFSTCPParsers(void)
AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_NFS, NFSTCPGetFiles);
/* Application layer event handling. */
// AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_NFS,
// NFSTCPHasEvents);
AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_NFS,
NFSTCPHasEvents);
/* What is this being registered for? */
AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_NFS,
NULL, NFSTCPGetTxDetectState, NFSTCPSetTxDetectState);
// AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_NFS,
// NFSTCPStateGetEventInfo);
// AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_NFS,
// NFSTCPGetEvents);
AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_NFS,
NFSTCPStateGetEventInfo);
AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_NFS,
NFSTCPGetEvents);
/* This parser accepts gaps. */
AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_NFS,

@ -24,6 +24,8 @@
#ifndef __APP_LAYER_NFS_TCP_H__
#define __APP_LAYER_NFS_TCP_H__
#include "app-layer-events.h"
void RegisterNFSTCPParsers(void);
void NFSTCPParserRegisterTests(void);

@ -92,43 +92,21 @@ static void NFSStateTxFree(void *state, uint64_t tx_id)
rs_nfs3_state_tx_free(state, tx_id);
}
#if 0
static int NFSStateGetEventInfo(const char *event_name, int *event_id,
AppLayerEventType *event_type)
{
*event_id = SCMapEnumNameToValue(event_name, nfs_decoder_event_table);
if (*event_id == -1) {
SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
"nfs enum map table.", event_name);
/* This should be treated as fatal. */
return -1;
return rs_nfs_state_get_event_info(event_name, event_id, event_type);
}
*event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
return 0;
}
static AppLayerDecoderEvents *NFSGetEvents(void *state, uint64_t tx_id)
static int NFSHasEvents(void *state)
{
NFSState *nfs_state = state;
NFSTransaction *tx;
TAILQ_FOREACH(tx, &nfs3_state->tx_list, next) {
if (tx->tx_id == tx_id) {
return tx->decoder_events;
}
}
return NULL;
return rs_nfs_state_has_events(state);
}
static int NFSHasEvents(void *state)
static AppLayerDecoderEvents *NFSGetEvents(void *state, uint64_t id)
{
NFSState *echo = state;
return echo->events;
return rs_nfs_state_get_events(state, id);
}
#endif
/**
* \brief Probe the input to see if it looks like echo.
@ -357,17 +335,17 @@ void RegisterNFSUDPParsers(void)
AppLayerParserRegisterGetFilesFunc(IPPROTO_UDP, ALPROTO_NFS, NFSGetFiles);
/* Application layer event handling. */
// AppLayerParserRegisterHasEventsFunc(IPPROTO_UDP, ALPROTO_NFS,
// NFSHasEvents);
AppLayerParserRegisterHasEventsFunc(IPPROTO_UDP, ALPROTO_NFS,
NFSHasEvents);
/* What is this being registered for? */
AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_NFS,
NULL, NFSGetTxDetectState, NFSSetTxDetectState);
// AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_NFS,
// NFSStateGetEventInfo);
// AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_NFS,
// NFSGetEvents);
AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_NFS,
NFSStateGetEventInfo);
AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_NFS,
NFSGetEvents);
}
else {
SCLogNotice("NFS protocol parsing disabled.");

Loading…
Cancel
Save