-/* Copyright (C) 2007-2017 Open Information Security Foundation
+/* Copyright (C) 2007-2022 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
#include "util-byte.h"
#include "util-mem.h"
#include "util-misc.h"
+#include "util-validate.h"
#include "rust-ftp-mod-gen.h"
{ FTP_COMMAND_UNKNOWN, NULL, 0}
};
uint64_t ftp_config_memcap = 0;
+uint32_t ftp_max_line_len = 4096;
SC_ATOMIC_DECLARE(uint64_t, ftp_memuse);
SC_ATOMIC_DECLARE(uint64_t, ftp_memcap);
SC_ATOMIC_INIT(ftp_memuse);
SC_ATOMIC_INIT(ftp_memcap);
+
+ if ((ConfGet("app-layer.protocols.ftp.max-line-length", &conf_val)) == 1) {
+ if (ParseSizeStringU32(conf_val, &ftp_max_line_len) < 0) {
+ SCLogError(SC_ERR_SIZE_PARSE, "Error parsing ftp.max-line-length from conf file - %s.",
+ conf_val);
+ }
+ SCLogConfig("FTP max line length: %" PRIu32, ftp_max_line_len);
+ }
}
static void FTPIncrMemuse(uint64_t size)
/* we have seen the lf for the previous line. Clear the parser
* details to parse new line */
line_state->current_line_lf_seen = 0;
+ state->current_line_truncated = false;
if (line_state->current_line_db == 1) {
line_state->current_line_db = 0;
FTPFree(line_state->db, line_state->db_len);
line_state->current_line_db = 1;
memcpy(line_state->db, state->input, state->input_len);
line_state->db_len = state->input_len;
- } else {
- ptmp = FTPRealloc(line_state->db, line_state->db_len,
- (line_state->db_len + state->input_len));
- if (ptmp == NULL) {
- FTPFree(line_state->db, line_state->db_len);
- line_state->db = NULL;
- line_state->db_len = 0;
- return -1;
+ } else if (!state->current_line_truncated) {
+ int32_t input_len = state->input_len;
+ if (line_state->db_len + input_len > ftp_max_line_len) {
+ input_len = ftp_max_line_len - line_state->db_len;
+ DEBUG_VALIDATE_BUG_ON(input_len < 0);
+ state->current_line_truncated = true;
}
- line_state->db = ptmp;
+ if (input_len > 0) {
+ ptmp = FTPRealloc(
+ line_state->db, line_state->db_len, (line_state->db_len + input_len));
+ if (ptmp == NULL) {
+ FTPFree(line_state->db, line_state->db_len);
+ line_state->db = NULL;
+ line_state->db_len = 0;
+ return -1;
+ }
+ line_state->db = ptmp;
- memcpy(line_state->db + line_state->db_len,
- state->input, state->input_len);
- line_state->db_len += state->input_len;
+ memcpy(line_state->db + line_state->db_len, state->input, input_len);
+ line_state->db_len += input_len;
+ }
}
state->input += state->input_len;
state->input_len = 0;
line_state->current_line_lf_seen = 1;
if (line_state->current_line_db == 1) {
- ptmp = FTPRealloc(line_state->db, line_state->db_len,
- (line_state->db_len + (lf_idx + 1 - state->input)));
- if (ptmp == NULL) {
- FTPFree(line_state->db, line_state->db_len);
- line_state->db = NULL;
- line_state->db_len = 0;
- return -1;
- }
- line_state->db = ptmp;
+ if (!state->current_line_truncated) {
+ int32_t input_len = lf_idx + 1 - state->input;
+ if (line_state->db_len + input_len > ftp_max_line_len) {
+ input_len = ftp_max_line_len - line_state->db_len;
+ DEBUG_VALIDATE_BUG_ON(input_len < 0);
+ state->current_line_truncated = true;
+ }
+ if (input_len > 0) {
+ ptmp = FTPRealloc(
+ line_state->db, line_state->db_len, (line_state->db_len + input_len));
+ if (ptmp == NULL) {
+ FTPFree(line_state->db, line_state->db_len);
+ line_state->db = NULL;
+ line_state->db_len = 0;
+ return -1;
+ }
+ line_state->db = ptmp;
- memcpy(line_state->db + line_state->db_len,
- state->input, (lf_idx + 1 - state->input));
- line_state->db_len += (lf_idx + 1 - state->input);
+ memcpy(line_state->db + line_state->db_len, state->input, input_len);
+ line_state->db_len += input_len;
- if (line_state->db_len > 1 &&
- line_state->db[line_state->db_len - 2] == 0x0D) {
- line_state->db_len -= 2;
- state->current_line_delimiter_len = 2;
- } else {
- line_state->db_len -= 1;
- state->current_line_delimiter_len = 1;
+ if (line_state->db_len > 1 && line_state->db[line_state->db_len - 2] == 0x0D) {
+ line_state->db_len -= 2;
+ state->current_line_delimiter_len = 2;
+ } else {
+ line_state->db_len -= 1;
+ state->current_line_delimiter_len = 1;
+ }
+ }
}
state->current_line = line_state->db;
} else {
state->current_line = state->input;
- state->current_line_len = lf_idx - state->input;
+ if (lf_idx - state->input > ftp_max_line_len) {
+ state->current_line_len = ftp_max_line_len;
+ state->current_line_truncated = true;
+ } else {
+ state->current_line_len = lf_idx - state->input;
+ }
if (state->input != lf_idx &&
*(lf_idx - 1) == 0x0D) {
tx->command_descriptor = cmd_descriptor;
tx->request_length = CopyCommandLine(&tx->request, state->current_line, state->current_line_len);
+ tx->request_truncated = state->current_line_truncated;
switch (state->command) {
case FTP_COMMAND_EPRT:
FTPString *response = FTPStringAlloc();
if (likely(response)) {
response->len = CopyCommandLine(&response->str, state->current_line, state->current_line_len);
+ response->truncated = state->current_line_truncated;
TAILQ_INSERT_TAIL(&tx->response_list, response, next);
}
}