]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
smtp: pre process DATA and BDAT commands
authorShivani Bhardwaj <shivanib134@gmail.com>
Tue, 19 Apr 2022 15:33:24 +0000 (21:03 +0530)
committerVictor Julien <vjulien@oisf.net>
Thu, 21 Apr 2022 05:37:58 +0000 (07:37 +0200)
The input data received in DATA and BDAT command modes can be huge and
could have important data, like a legit huge email. Therefore, exempt
these from the line buffering limits which were introduced to regulate
the size of lines that we buffer at any point in time.

As a part of this patch, anything that comes under DATA or BDAT is
processed early without buffering as and when it arrives. The ways of
processing remain the same as before.

(cherry picked from commit cf749fd450ca41dc001c2a1c10d8d17500dcedce)

src/app-layer-smtp.c
src/app-layer-smtp.h

index 7d640ff682e5242cd9c12bde007663c2b3cdbf1c..21266bb86ce2952211b552b339a76a289563c4dc 100644 (file)
@@ -244,7 +244,7 @@ SCEnumCharMap smtp_reply_map[ ] = {
 SMTPConfig smtp_config = { 0, { 0, 0, 0, 0, 0 }, 0, 0, 0, 0, STREAMING_BUFFER_CONFIG_INITIALIZER};
 
 static SMTPString *SMTPStringAlloc(void);
-
+static int SMTPPreProcessCommands(SMTPState *state, Flow *f, AppLayerParserState *pstate);
 /**
  * \brief Configure SMTP Mime Decoder by parsing out mime section of YAML
  * config file
@@ -1408,6 +1408,42 @@ static int SMTPProcessRequest(SMTPState *state, Flow *f,
     }
 }
 
+static int SMTPPreProcessCommands(SMTPState *state, Flow *f, AppLayerParserState *pstate)
+{
+    // By this time we should have had the command line parsed
+    uint8_t *lf_idx = memchr(state->input + state->consumed, 0x0a, state->input_len);
+    const uint32_t orig_input_len = state->input_len;
+    // Both DATA and BDAT set SMTP_PARSER_STATE_COMMAND_DATA_MODE, so this while
+    // loop should be valid for both
+    while (state->input_len > 0 && (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+        uint8_t delim_len = 0;
+        uint32_t consumed_line = 0;
+        state->current_line = state->input + state->consumed;
+        if (lf_idx == NULL) {
+            state->consumed = state->input_len;
+            consumed_line = state->input_len;
+        } else {
+            ptrdiff_t idx = lf_idx - state->input;
+            state->consumed = idx + 1;
+            consumed_line = lf_idx - state->current_line + 1;
+            if (orig_input_len >= idx && idx > 0 && state->input[idx - 1] == 0x0d) {
+                delim_len = 2;
+            } else if (orig_input_len == 1 ||
+                       (orig_input_len >= idx + 1 && idx > 0 && state->input[idx - 1] != 0x0d)) {
+                delim_len = 1;
+            }
+        }
+        state->current_line_delimiter_len = delim_len;
+        state->current_line_len = consumed_line - delim_len;
+        state->input_len -= (state->current_line_len + delim_len);
+        if (SMTPProcessRequest(state, f, pstate) == -1) {
+            return -1;
+        }
+        lf_idx = memchr(state->input + state->consumed, 0x0a, state->input_len);
+    }
+    return 0;
+}
+
 static int SMTPParse(int direction, Flow *f, SMTPState *state,
                      AppLayerParserState *pstate, const uint8_t *input,
                      uint32_t input_len,
@@ -1423,12 +1459,24 @@ static int SMTPParse(int direction, Flow *f, SMTPState *state,
 
     state->input = input;
     state->input_len = input_len;
+    state->consumed = 0;
     state->direction = direction;
+    if (direction == 0) {
+        if (((state->current_command == SMTP_COMMAND_DATA) ||
+                    (state->current_command == SMTP_COMMAND_BDAT)) &&
+                (state->parser_state & SMTP_PARSER_STATE_COMMAND_DATA_MODE)) {
+            int ret = SMTPPreProcessCommands(state, f, pstate);
+            if (ret == 0 && state->consumed == state->input_len) {
+                return 0;
+            }
+        }
+    }
     int res = SMTPGetLine(state);
 
     /* toserver */
     if (direction == 0) {
         while (res == 0) {
+            BUG_ON(state->discard_till_lf);
             if (!state->discard_till_lf) {
                 if ((state->current_line_len > 0) && (SMTPProcessRequest(state, f, pstate) == -1))
                     SCReturnInt(-1);
@@ -1445,6 +1493,7 @@ static int SMTPParse(int direction, Flow *f, SMTPState *state,
         /* toclient */
     } else {
       while (res == 0) {
+        BUG_ON(state->discard_till_lf);
         if (!state->discard_till_lf) {
           if ((state->current_line_len > 0) && (SMTPProcessReply(state, f, pstate, thread_data) == -1))
             SCReturnInt(-1);
index 8851b88d1feed6f833e23e83ed95aab11a275158..0bc9014aa1fb2ed54cd2ff3085b380e5312d8b48 100644 (file)
@@ -119,7 +119,8 @@ typedef struct SMTPState_ {
     const uint8_t *input;
     int32_t input_len;
     uint8_t direction;
-
+    /* consumed number of bytes. Only used by PreProcessCommands */
+    int32_t consumed;
     /* --parser details-- */
     /** current line extracted by the parser from the call to SMTPGetline() */
     const uint8_t *current_line;