From 474ea4e733bdb3378ac9c6b51ed5e8ac4fb8f644 Mon Sep 17 00:00:00 2001 From: Shivani Bhardwaj Date: Tue, 19 Apr 2022 21:03:24 +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 | 51 +++++++++++++++++++++++++++++++++++++++++++- src/app-layer-smtp.h | 3 ++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/app-layer-smtp.c b/src/app-layer-smtp.c index 7d640ff682..21266bb86c 100644 --- a/src/app-layer-smtp.c +++ b/src/app-layer-smtp.c @@ -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); diff --git a/src/app-layer-smtp.h b/src/app-layer-smtp.h index 8851b88d1f..0bc9014aa1 100644 --- a/src/app-layer-smtp.h +++ b/src/app-layer-smtp.h @@ -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; -- 2.47.2