From 1b6f4da23ba9bcf1e9e4b8b15f6522979e6bfbec Mon Sep 17 00:00:00 2001 From: Juliana Fajardini Date: Mon, 17 Feb 2025 12:05:09 -0300 Subject: [PATCH] pgsql: add events Events for: - parsing error when parsing pgsql packet length - parsing error for pgsql requests (post length parsing) - parsing error for pgsql responses (post length parsing) - too many transactions Include `pgsql-events.rules` file, and PGSQL events SID range definition Task #5566 --- rules/README.md | 1 + rules/pgsql-events.rules | 8 ++++++++ rust/src/pgsql/pgsql.rs | 32 ++++++++++++++++++++++++-------- 3 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 rules/pgsql-events.rules diff --git a/rules/README.md b/rules/README.md index a2c47f169c..93cee89f11 100644 --- a/rules/README.md +++ b/rules/README.md @@ -29,6 +29,7 @@ signature IDs. | QUIC | 2231000 | 2231999 | | FTP | 2232000 | 2232999 | | DNS | 2240000 | 2240999 | +| PGSQL | 2241000 | 2241999 | | MODBUS | 2250000 | 2250999 | | DNP3 | 2270000 | 2270999 | | HTTP2 | 2290000 | 2290999 | diff --git a/rules/pgsql-events.rules b/rules/pgsql-events.rules new file mode 100644 index 0000000000..c19332033d --- /dev/null +++ b/rules/pgsql-events.rules @@ -0,0 +1,8 @@ +# PGSQL app-layer event rules +# +# SID range start: 2241000 +# SID range end: 2241999 +alert pgsql any any -> any any (msg:"SURICATA PGSQL Too many transactions"; app-layer-event:pgsql.too_many_transactions; sid:2241000; rev:1;) +alert pgsql any any -> any any (msg:"SURICATA PGSQL Malformed request"; app-layer-event:pgsql.malformed_request; flow:to_server; sid:2241001; rev:1;) +alert pgsql any any -> any any (msg:"SURICATA PGSQL Malformed response"; app-layer-event:pgsql.malformed_response; flow:to_client; sid:2241002; rev:1;) +alert pgsql any any -> any any (msg:"SURICATA PGSQL Invalid length"; app-layer-event:pgsql.invalid_length; sid:2241003; rev:1;) diff --git a/rust/src/pgsql/pgsql.rs b/rust/src/pgsql/pgsql.rs index 5b8ad8d88e..513e24cf7e 100644 --- a/rust/src/pgsql/pgsql.rs +++ b/rust/src/pgsql/pgsql.rs @@ -27,10 +27,10 @@ use crate::core::{ALPROTO_FAILED, ALPROTO_UNKNOWN, IPPROTO_TCP, *}; use crate::direction::Direction; use crate::flow::Flow; use nom7::{Err, IResult}; -use suricata_sys::sys::AppProto; use std; use std::collections::VecDeque; use std::ffi::CString; +use suricata_sys::sys::AppProto; pub const PGSQL_CONFIG_DEFAULT_STREAM_DEPTH: u32 = 0; @@ -38,6 +38,14 @@ static mut ALPROTO_PGSQL: AppProto = ALPROTO_UNKNOWN; static mut PGSQL_MAX_TX: usize = 1024; +#[derive(AppLayerEvent, Debug, PartialEq, Eq)] +pub enum PgsqlEvent { + InvalidLength, // Can't parse the length field + MalformedRequest, // Enough data, but unexpected request format + MalformedResponse, // Enough data, but unexpected response format + TooManyTransactions, +} + #[repr(u8)] #[derive(Copy, Clone, PartialOrd, PartialEq, Eq, Debug)] pub enum PgsqlTxProgress { @@ -218,7 +226,9 @@ impl PgsqlState { // when they're parsed, as of now tx_old.tx_req_state = PgsqlTxProgress::TxFlushedOut; tx_old.tx_res_state = PgsqlTxProgress::TxFlushedOut; - //TODO set event + tx_old + .tx_data + .set_event(PgsqlEvent::TooManyTransactions as u8); break; } } @@ -400,15 +410,18 @@ impl PgsqlState { return AppLayerResult::incomplete(consumed as u32, needed_estimation as u32); } Err(Err::Error(err)) => { + let mut tx = self.new_tx(); match err { PgsqlParseError::InvalidLength => { - // TODO set event invalid length event + tx.tx_data.set_event(PgsqlEvent::InvalidLength as u8); + self.transactions.push_back(tx); // If we don't get a valid length, we can't know how to proceed return AppLayerResult::err(); } PgsqlParseError::NomError(_i, error_kind) => { if error_kind == nom7::error::ErrorKind::Switch { - // TODO set event switch / PgsqlEvent::MalformedData // or something like that + tx.tx_data.set_event(PgsqlEvent::MalformedRequest as u8); + self.transactions.push_back(tx); } SCLogDebug!("Parsing error: {:?}", error_kind); } @@ -593,15 +606,18 @@ impl PgsqlState { return AppLayerResult::incomplete(consumed as u32, needed_estimation as u32); } Err(Err::Error(err)) => { + let mut tx = self.new_tx(); match err { PgsqlParseError::InvalidLength => { - // TODO set event invalid length event + tx.tx_data.set_event(PgsqlEvent::InvalidLength as u8); + self.transactions.push_back(tx); // If we don't get a valid length, we can't know how to proceed return AppLayerResult::err(); } PgsqlParseError::NomError(_i, error_kind) => { if error_kind == nom7::error::ErrorKind::Switch { - // TODO set event switch / PgsqlEvent::MalformedData // or something like that + tx.tx_data.set_event(PgsqlEvent::MalformedResponse as u8); + self.transactions.push_back(tx); } SCLogDebug!("Parsing error: {:?}", error_kind); } @@ -830,8 +846,8 @@ pub unsafe extern "C" fn SCRegisterPgsqlParser() { tx_comp_st_ts: PgsqlTxProgress::TxDone as i32, tx_comp_st_tc: PgsqlTxProgress::TxDone as i32, tx_get_progress: tx_get_al_state_progress, - get_eventinfo: None, - get_eventinfo_byid: None, + get_eventinfo: Some(PgsqlEvent::get_event_info), + get_eventinfo_byid: Some(PgsqlEvent::get_event_info_by_id), localstorage_new: None, localstorage_free: None, get_tx_files: None,