aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2018-03-12 12:16:04 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2018-03-12 12:16:04 +0000
commit61e347959b684ac1682f09940080355586c106f5 (patch)
tree10a6970e770c9466351800277ecaf0b8244cdc75
parentd27d7084c5e8516a2fa670bf680245f6884adfbb (diff)
downloadrspamd-61e347959b684ac1682f09940080355586c106f5.tar.gz
rspamd-61e347959b684ac1682f09940080355586c106f5.zip
[Fix] Deal with deeply nested messages more aggressively
-rw-r--r--src/libmime/message.c18
-rw-r--r--src/libmime/mime_parser.c86
-rw-r--r--src/libmime/mime_parser.h9
3 files changed, 76 insertions, 37 deletions
diff --git a/src/libmime/message.c b/src/libmime/message.c
index c92a1d26e..5e1118fc2 100644
--- a/src/libmime/message.c
+++ b/src/libmime/message.c
@@ -945,10 +945,14 @@ rspamd_message_parse (struct rspamd_task *task)
rspamd_cryptobox_hash_init (&st, NULL, 0);
if (task->flags & RSPAMD_TASK_FLAG_MIME) {
+ enum rspamd_mime_parse_error ret;
debug_task ("construct mime parser from string length %d",
(gint) task->msg.len);
- if (!rspamd_mime_parse_task (task, &err)) {
+ ret = rspamd_mime_parse_task (task, &err);
+
+ switch (ret) {
+ case RSPAMD_MIME_PARSE_FATAL:
msg_err_task ("cannot construct mime from stream: %e", err);
if (task->cfg && (!task->cfg->allow_raw_input)) {
@@ -963,6 +967,18 @@ rspamd_message_parse (struct rspamd_task *task)
task->flags &= ~RSPAMD_TASK_FLAG_MIME;
rspamd_message_from_data (task, p, len);
}
+ break;
+ case RSPAMD_MIME_PARSE_NESTING:
+ msg_warn_task ("cannot construct full mime from stream: %e", err);
+ task->flags |= RSPAMD_TASK_FLAG_BROKEN_HEADERS;
+ break;
+ case RSPAMD_MIME_PARSE_OK:
+ default:
+ break;
+ }
+
+ if (err) {
+ g_error_free (err);
}
}
else {
diff --git a/src/libmime/mime_parser.c b/src/libmime/mime_parser.c
index 8bcee0c95..d60a3fea2 100644
--- a/src/libmime/mime_parser.c
+++ b/src/libmime/mime_parser.c
@@ -26,9 +26,11 @@ struct rspamd_mime_parser_lib_ctx {
struct rspamd_multipattern *mp_boundary;
guchar hkey[rspamd_cryptobox_SIPKEYBYTES]; /* Key for hashing */
guint key_usages;
-} *lib_ctx = NULL;
+};
+
+struct rspamd_mime_parser_lib_ctx *lib_ctx = NULL;
-static const guint max_nested = 32;
+static const guint max_nested = 64;
static const guint max_key_usages = 10000;
#define msg_debug_mime(...) rspamd_conditional_debug_fast (NULL, task->from_addr, \
@@ -56,19 +58,20 @@ struct rspamd_mime_parser_ctx {
const gchar *pos;
const gchar *end;
struct rspamd_task *task;
+ guint nesting;
};
-static gboolean
+static enum rspamd_mime_parse_error
rspamd_mime_parse_multipart_part (struct rspamd_task *task,
struct rspamd_mime_part *part,
struct rspamd_mime_parser_ctx *st,
GError **err);
-static gboolean
+static enum rspamd_mime_parse_error
rspamd_mime_parse_message (struct rspamd_task *task,
struct rspamd_mime_part *part,
struct rspamd_mime_parser_ctx *st,
GError **err);
-static gboolean
+static enum rspamd_mime_parse_error
rspamd_mime_parse_normal_part (struct rspamd_task *task,
struct rspamd_mime_part *part,
struct rspamd_mime_parser_ctx *st,
@@ -424,7 +427,7 @@ rspamd_mime_parser_calc_digest (struct rspamd_mime_part *part)
}
}
-static gboolean
+static enum rspamd_mime_parse_error
rspamd_mime_parse_normal_part (struct rspamd_task *task,
struct rspamd_mime_part *part,
struct rspamd_mime_parser_ctx *st,
@@ -513,7 +516,7 @@ rspamd_mime_parse_normal_part (struct rspamd_task *task,
part->raw_data.len, rspamd_cte_to_string (part->cte));
rspamd_mime_parser_calc_digest (part);
- return TRUE;
+ return RSPAMD_MIME_PARSE_OK;
}
struct rspamd_mime_multipart_cbdata {
@@ -526,7 +529,7 @@ struct rspamd_mime_multipart_cbdata {
GError **err;
};
-static gboolean
+static enum rspamd_mime_parse_error
rspamd_mime_process_multipart_node (struct rspamd_task *task,
struct rspamd_mime_parser_ctx *st,
struct rspamd_mime_part *multipart,
@@ -540,7 +543,7 @@ rspamd_mime_process_multipart_node (struct rspamd_task *task,
GString str;
goffset hdr_pos, body_pos;
guint i;
- gboolean ret = FALSE;
+ enum rspamd_mime_parse_error ret = RSPAMD_MIME_PARSE_FATAL;
str.str = (gchar *)start;
@@ -626,13 +629,16 @@ rspamd_mime_process_multipart_node (struct rspamd_task *task,
npart->ct = sel;
if (sel->flags & RSPAMD_CONTENT_TYPE_MULTIPART) {
+ st->nesting ++;
g_ptr_array_add (st->stack, npart);
ret = rspamd_mime_parse_multipart_part (task, npart, st, err);
}
else if (sel->flags & RSPAMD_CONTENT_TYPE_MESSAGE) {
+ st->nesting ++;
g_ptr_array_add (st->stack, npart);
- if ((ret = rspamd_mime_parse_normal_part (task, npart, st, err))) {
+ if ((ret = rspamd_mime_parse_normal_part (task, npart, st, err))
+ == RSPAMD_MIME_PARSE_OK) {
ret = rspamd_mime_parse_message (task, npart, st, err);
}
}
@@ -643,7 +649,7 @@ rspamd_mime_process_multipart_node (struct rspamd_task *task,
return ret;
}
-static gboolean
+static enum rspamd_mime_parse_error
rspamd_mime_parse_multipart_cb (struct rspamd_task *task,
struct rspamd_mime_part *multipart,
struct rspamd_mime_parser_ctx *st,
@@ -651,6 +657,7 @@ rspamd_mime_parse_multipart_cb (struct rspamd_task *task,
struct rspamd_mime_boundary *b)
{
const gchar *pos = st->start + b->boundary;
+ enum rspamd_mime_parse_error ret;
task = cb->task;
@@ -666,9 +673,10 @@ rspamd_mime_parse_multipart_cb (struct rspamd_task *task,
g_assert (cb->cur_boundary != NULL);
- if (!rspamd_mime_process_multipart_node (task, cb->st,
- cb->multipart, cb->part_start, pos, cb->err)) {
- return FALSE;
+ if ((ret = rspamd_mime_process_multipart_node (task, cb->st,
+ cb->multipart, cb->part_start, pos, cb->err))
+ != RSPAMD_MIME_PARSE_OK) {
+ return ret;
}
/* Go towards the next part */
@@ -680,10 +688,10 @@ rspamd_mime_parse_multipart_cb (struct rspamd_task *task,
}
}
- return TRUE;
+ return RSPAMD_MIME_PARSE_OK;
}
-static gint
+static enum rspamd_mime_parse_error
rspamd_multipart_boundaries_filter (struct rspamd_task *task,
struct rspamd_mime_part *multipart,
struct rspamd_mime_parser_ctx *st,
@@ -692,6 +700,7 @@ rspamd_multipart_boundaries_filter (struct rspamd_task *task,
struct rspamd_mime_boundary *cur;
goffset last_offset;
guint i, sel = 0;
+ enum rspamd_mime_parse_error ret;
last_offset = (multipart->raw_data.begin - st->start) +
multipart->raw_data.len;
@@ -740,9 +749,9 @@ rspamd_multipart_boundaries_filter (struct rspamd_task *task,
}
if (cur->hash == cb->bhash || cur->closed_hash == cb->bhash) {
- if (!rspamd_mime_parse_multipart_cb (task, multipart, st,
- cb, cur)) {
- return FALSE;
+ if ((ret = rspamd_mime_parse_multipart_cb (task, multipart, st,
+ cb, cur)) != RSPAMD_MIME_PARSE_OK) {
+ return ret;
}
if (cur->closed_hash == cb->bhash) {
@@ -779,31 +788,32 @@ rspamd_multipart_boundaries_filter (struct rspamd_task *task,
fb.boundary = last_offset;
- if (!rspamd_mime_parse_multipart_cb (task, multipart, st,
- cb, &fb)) {
- return FALSE;
+ if ((ret = rspamd_mime_parse_multipart_cb (task, multipart, st,
+ cb, &fb)) != RSPAMD_MIME_PARSE_OK) {
+ return ret;
}
}
- return TRUE;
+ return RSPAMD_MIME_PARSE_OK;
}
-static gboolean
+static enum rspamd_mime_parse_error
rspamd_mime_parse_multipart_part (struct rspamd_task *task,
struct rspamd_mime_part *part,
struct rspamd_mime_parser_ctx *st,
GError **err)
{
struct rspamd_mime_multipart_cbdata cbdata;
- gboolean ret;
+ enum rspamd_mime_parse_error ret;
- if (st->stack->len > max_nested) {
+ if (st->nesting > max_nested) {
g_set_error (err, RSPAMD_MIME_QUARK, E2BIG, "Nesting level is too high: %d",
- st->stack->len);
- return FALSE;
+ st->nesting);
+ return RSPAMD_MIME_PARSE_NESTING;
}
g_ptr_array_add (task->parts, part);
+ st->nesting ++;
rspamd_mime_part_get_cte (task, part->raw_headers, part, FALSE);
st->pos = part->raw_data.begin;
@@ -829,6 +839,7 @@ rspamd_mime_parse_multipart_part (struct rspamd_task *task,
ret = rspamd_multipart_boundaries_filter (task, part, st, &cbdata);
/* Cleanup stack */
+ st->nesting --;
g_ptr_array_remove_index_fast (st->stack, st->stack->len - 1);
return ret;
@@ -1025,7 +1036,7 @@ rspamd_mime_parse_stack_free (struct rspamd_mime_parser_ctx *st)
}
}
-static gboolean
+static enum rspamd_mime_parse_error
rspamd_mime_parse_message (struct rspamd_task *task,
struct rspamd_mime_part *part,
struct rspamd_mime_parser_ctx *st,
@@ -1039,14 +1050,14 @@ rspamd_mime_parse_message (struct rspamd_task *task,
struct rspamd_mime_part *npart;
goffset hdr_pos, body_pos;
guint i;
- gboolean ret = FALSE;
+ enum rspamd_mime_parse_error ret = RSPAMD_MIME_PARSE_OK;
GString str;
struct rspamd_mime_parser_ctx *nst = st;
- if (st->stack->len > max_nested) {
+ if (st->nesting > max_nested) {
g_set_error (err, RSPAMD_MIME_QUARK, E2BIG, "Nesting level is too high: %d",
- st->stack->len);
- return FALSE;
+ st->nesting);
+ return RSPAMD_MIME_PARSE_NESTING;
}
/* Allocate real part */
@@ -1160,6 +1171,8 @@ rspamd_mime_parse_message (struct rspamd_task *task,
nst->end = nst->start + part->parsed_data.len;
nst->pos = nst->start;
nst->task = st->task;
+ nst->nesting = st->nesting;
+ st->nesting ++;
str.str = (gchar *)part->parsed_data.begin;
str.len = part->parsed_data.len;
@@ -1235,10 +1248,12 @@ rspamd_mime_parse_message (struct rspamd_task *task,
if (sel->flags & RSPAMD_CONTENT_TYPE_MULTIPART) {
g_ptr_array_add (nst->stack, npart);
+ nst->nesting ++;
ret = rspamd_mime_parse_multipart_part (task, npart, nst, err);
}
else if (sel->flags & RSPAMD_CONTENT_TYPE_MESSAGE) {
g_ptr_array_add (nst->stack, npart);
+ nst->nesting ++;
ret = rspamd_mime_parse_message (task, npart, nst, err);
}
else {
@@ -1248,6 +1263,7 @@ rspamd_mime_parse_message (struct rspamd_task *task,
if (part) {
/* Remove message part from the parent stack */
g_ptr_array_remove_index_fast (st->stack, st->stack->len - 1);
+ st->nesting --;
}
if (nst != st) {
@@ -1257,11 +1273,11 @@ rspamd_mime_parse_message (struct rspamd_task *task,
return ret;
}
-gboolean
+enum rspamd_mime_parse_error
rspamd_mime_parse_task (struct rspamd_task *task, GError **err)
{
struct rspamd_mime_parser_ctx *st;
- gboolean ret;
+ enum rspamd_mime_parse_error ret = RSPAMD_MIME_PARSE_OK;
if (lib_ctx == NULL) {
rspamd_mime_parser_init_lib ();
diff --git a/src/libmime/mime_parser.h b/src/libmime/mime_parser.h
index f1355d72e..c0b7dec7e 100644
--- a/src/libmime/mime_parser.h
+++ b/src/libmime/mime_parser.h
@@ -20,6 +20,13 @@
struct rspamd_task;
-gboolean rspamd_mime_parse_task (struct rspamd_task *task, GError **err);
+enum rspamd_mime_parse_error {
+ RSPAMD_MIME_PARSE_OK = 0,
+ RSPAMD_MIME_PARSE_FATAL,
+ RSPAMD_MIME_PARSE_NESTING,
+};
+
+enum rspamd_mime_parse_error rspamd_mime_parse_task (struct rspamd_task *task,
+ GError **err);
#endif /* SRC_LIBMIME_MIME_PARSER_H_ */