From a63133a4b6ebe4dc83298f38de50e5c73efe82f0 Mon Sep 17 00:00:00 2001 From: Shivani Bhardwaj Date: Thu, 14 Apr 2022 21:29:32 +0530 Subject: [PATCH] smtp: pre process DATA and BDAT commands 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 | 52 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 11cf419209..355a2431f1 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -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)) -- 2.47.2