]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
pgsql: config limit maximum number of live transactions
authorPhilippe Antoine <pantoine@oisf.net>
Fri, 2 Sep 2022 07:34:27 +0000 (09:34 +0200)
committerVictor Julien <vjulien@oisf.net>
Tue, 20 Sep 2022 12:55:24 +0000 (14:55 +0200)
As is done for other protocols

Ticket: #5527

doc/userguide/configuration/suricata-yaml.rst
rust/src/pgsql/pgsql.rs
suricata.yaml.in

index 831c59e5589e5ca409bb27fcb419160e28a68d78..2bc934213c025e338f0d127b5d12829056e24b7a 100644 (file)
@@ -1721,7 +1721,7 @@ incompatible with ``decode-mime``. If both are enabled,
 Maximum transactions
 ~~~~~~~~~~~~~~~~~~~~
 
-MQTT, FTP, and NFS have each a `max-tx` parameter that can be customized.
+MQTT, FTP, PostgreSQL and NFS have each a `max-tx` parameter that can be customized.
 `max-tx` refers to the maximum number of live transactions for each flow.
 An app-layer event `protocol.too_many_transactions` is triggered when this value is reached.
 The point of this parameter is to find a balance between the completeness of analysis
index 24dd2e1f677536181a3a95514696dca086039a5d..daf61117425cf39e2b2dfa9040955e13a3124a22 100644 (file)
@@ -32,12 +32,15 @@ pub const PGSQL_CONFIG_DEFAULT_STREAM_DEPTH: u32 = 0;
 
 static mut ALPROTO_PGSQL: AppProto = ALPROTO_UNKNOWN;
 
+static mut PGSQL_MAX_TX: usize = 1024;
+
 #[repr(u8)]
 #[derive(Copy, Clone, PartialOrd, PartialEq, Debug)]
 pub enum PgsqlTransactionState {
     Init = 0,
     RequestReceived,
     ResponseDone,
+    FlushedOut,
 }
 
 #[derive(Debug)]
@@ -123,6 +126,7 @@ pub struct PgsqlState {
     backend_secret_key: u32,
     backend_pid: u32,
     state_progress: PgsqlStateProgress,
+    tx_index_completed: usize,
 }
 
 impl State<PgsqlTransaction> for PgsqlState {
@@ -145,6 +149,7 @@ impl PgsqlState {
             backend_secret_key: 0,
             backend_pid: 0,
             state_progress: PgsqlStateProgress::IdleState,
+            tx_index_completed: 0,
         }
     }
 
@@ -162,6 +167,7 @@ impl PgsqlState {
             }
         }
         if found {
+            self.tx_index_completed = 0;
             self.transactions.remove(index);
         }
     }
@@ -180,6 +186,21 @@ impl PgsqlState {
         self.tx_id += 1;
         tx.tx_id = self.tx_id;
         SCLogDebug!("Creating new transaction. tx_id: {}", tx.tx_id);
+        if self.transactions.len() > unsafe { PGSQL_MAX_TX } + self.tx_index_completed {
+            // If there are too many open transactions,
+            // mark the earliest ones as completed, and take care
+            // to avoid quadratic complexity
+            let mut index = self.tx_index_completed;
+            for tx_old in &mut self.transactions.range_mut(self.tx_index_completed..) {
+                index = index + 1;
+                if tx_old.tx_state < PgsqlTransactionState::ResponseDone {
+                    tx_old.tx_state = PgsqlTransactionState::FlushedOut;
+                    //TODO set event
+                    break;
+                }
+            }
+            self.tx_index_completed = index;
+        }
         return tx;
     }
 
@@ -738,6 +759,13 @@ pub unsafe extern "C" fn rs_pgsql_register_parser() {
             }
             AppLayerParserSetStreamDepth(IPPROTO_TCP as u8, ALPROTO_PGSQL, stream_depth)
         }
+        if let Some(val) = conf_get("app-layer.protocols.pgsql.max-tx") {
+            if let Ok(v) = val.parse::<usize>() {
+                PGSQL_MAX_TX = v;
+            } else {
+                SCLogError!("Invalid value for pgsql.max-tx");
+            }
+        }
     } else {
         SCLogDebug!("Protocol detector and parser disabled for PGSQL.");
     }
index bb8712cd200c616f8a10b888b3c7fe41d03a5774..2745fd93af1326c5588b3a2c39f4ff98b219ec9e 100644 (file)
@@ -835,6 +835,8 @@ app-layer:
       enabled: no
       # Stream reassembly size for PostgreSQL. By default, track it completely.
       stream-depth: 0
+      # Maximum number of live PostgreSQL transactions per flow
+      # max-tx: 1024
     dcerpc:
       enabled: yes
     ftp: