]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
smtp: pre process DATA and BDAT commands
authorShivani Bhardwaj <shivanib134@gmail.com>
Thu, 14 Apr 2022 15:59:32 +0000 (21:29 +0530)
committerShivani Bhardwaj <shivanib134@gmail.com>
Thu, 21 Apr 2022 07:31:56 +0000 (13:01 +0530)
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

index 11cf4192094b3451b73c2fc4c0bc4f8bffa4a6d1..355a2431f16be35b0a2de5cf09223e6e78fbcecb 100644 (file)
@@ -222,6 +222,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
@@ -785,7 +786,8 @@ static int SMTPProcessReply(SMTPState *state, Flow *f,
     SCEnter();
 
     /* Line with just LF */
-    if (state->current_line_len == 0 && state->consumed == 1) {
+    if (state->current_line_len == 0 && state->consumed == 1 &&
+            state->current_line_delimiter_len == 1) {
         return 0; // to continue processing further
     }
 
@@ -1198,6 +1200,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 && 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 AppLayerResult SMTPParse(int direction, Flow *f, SMTPState *state,
                      AppLayerParserState *pstate, const uint8_t *input,
                      uint32_t input_len,
@@ -1218,11 +1256,22 @@ static AppLayerResult SMTPParse(int direction, Flow *f, SMTPState *state,
     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) {
+                SCReturnStruct(APP_LAYER_OK);
+            }
+        }
+    }
     AppLayerResult res = SMTPGetLine(state);
 
     /* toserver */
     if (direction == 0) {
         while (res.status == 0) {
+            BUG_ON(state->discard_till_lf);
             if (!state->discard_till_lf) {
                 if ((state->current_line_len > 0) && (SMTPProcessRequest(state, f, pstate) == -1))
                     SCReturnStruct(APP_LAYER_ERROR);
@@ -1241,6 +1290,7 @@ static AppLayerResult SMTPParse(int direction, Flow *f, SMTPState *state,
         /* toclient */
     } else {
         while (res.status == 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))