summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--handler.c4
-rw-r--r--mime.h5
-rw-r--r--parse.c58
3 files changed, 55 insertions, 12 deletions
diff --git a/handler.c b/handler.c
index 36f4b997..f5a71628 100644
--- a/handler.c
+++ b/handler.c
@@ -1782,10 +1782,10 @@ int mutt_body_handler (BODY *b, STATE *s)
int oflags = s->flags;
- if (recurse_level >= 100)
+ if (recurse_level >= MUTT_MIME_MAX_DEPTH)
{
dprint (1, (debugfile, "mutt_body_handler: recurse level too deep. giving up!\n"));
- return -1;
+ return 1;
}
recurse_level++;
diff --git a/mime.h b/mime.h
index 82125ab3..c162ee2b 100644
--- a/mime.h
+++ b/mime.h
@@ -52,6 +52,11 @@ enum
DISPNONE /* no preferred disposition */
};
+/* Some limits to mitigate stack overflow and denial of service attacks */
+#define MUTT_MIME_MAX_DEPTH 50
+#define MUTT_MIME_MAX_PARTS 5000
+
+
/* MIME encoding/decoding global vars */
#ifndef _SENDLIB_C
diff --git a/parse.c b/parse.c
index 063d8ee1..b05567fd 100644
--- a/parse.c
+++ b/parse.c
@@ -38,6 +38,12 @@
#include <sys/stat.h>
#include <stdlib.h>
+static void _parse_part (FILE *fp, BODY *b, int *counter);
+static BODY *_parse_messageRFC822 (FILE *fp, BODY *parent, int *counter);
+static BODY *_parse_multipart (FILE *fp, const char *boundary, LOFF_T end_off,
+ int digest, int *counter);
+
+
/* Reads an arbitrarily long header field, and looks ahead for continuation
* lines. ``line'' must point to a dynamically allocated string; it is
* increased if more space is required to fit the whole line.
@@ -590,12 +596,12 @@ BODY *mutt_read_mime_header (FILE *fp, int digest)
return (p);
}
-void mutt_parse_part (FILE *fp, BODY *b)
+static void _parse_part (FILE *fp, BODY *b, int *counter)
{
char *bound = 0;
static unsigned short recurse_level = 0;
- if (recurse_level >= 100)
+ if (recurse_level >= MUTT_MIME_MAX_DEPTH)
{
dprint (1, (debugfile, "mutt_parse_part(): recurse level too deep. giving up!\n"));
return;
@@ -613,9 +619,10 @@ void mutt_parse_part (FILE *fp, BODY *b)
bound = mutt_get_parameter ("boundary", b->parameter);
fseeko (fp, b->offset, SEEK_SET);
- b->parts = mutt_parse_multipart (fp, bound,
- b->offset + b->length,
- ascii_strcasecmp ("digest", b->subtype) == 0);
+ b->parts = _parse_multipart (fp, bound,
+ b->offset + b->length,
+ ascii_strcasecmp ("digest", b->subtype) == 0,
+ counter);
break;
case TYPEMESSAGE:
@@ -623,7 +630,7 @@ void mutt_parse_part (FILE *fp, BODY *b)
{
fseeko (fp, b->offset, SEEK_SET);
if (mutt_is_message_type(b->type, b->subtype))
- b->parts = mutt_parse_messageRFC822 (fp, b);
+ b->parts = _parse_messageRFC822 (fp, b, counter);
else if (ascii_strcasecmp (b->subtype, "external-body") == 0)
b->parts = mutt_read_mime_header (fp, 0);
else
@@ -656,7 +663,7 @@ bail:
* NOTE: this assumes that `parent->length' has been set!
*/
-BODY *mutt_parse_messageRFC822 (FILE *fp, BODY *parent)
+static BODY *_parse_messageRFC822 (FILE *fp, BODY *parent, int *counter)
{
BODY *msg;
@@ -674,7 +681,7 @@ BODY *mutt_parse_messageRFC822 (FILE *fp, BODY *parent)
if (msg->length < 0)
msg->length = 0;
- mutt_parse_part(fp, msg);
+ _parse_part(fp, msg, counter);
return (msg);
}
@@ -691,7 +698,8 @@ BODY *mutt_parse_messageRFC822 (FILE *fp, BODY *parent)
* digest 1 if reading a multipart/digest, 0 otherwise
*/
-BODY *mutt_parse_multipart (FILE *fp, const char *boundary, LOFF_T end_off, int digest)
+static BODY *_parse_multipart (FILE *fp, const char *boundary, LOFF_T end_off,
+ int digest, int *counter)
{
#ifdef SUN_ATTACHMENT
int lines;
@@ -769,6 +777,14 @@ BODY *mutt_parse_multipart (FILE *fp, const char *boundary, LOFF_T end_off, int
}
else
last = head = new;
+
+ /* It seems more intuitive to add the counter increment to
+ * _parse_part(), but we want to stop the case where a multipart
+ * contains thousands of tiny parts before the memory and data
+ * structures are allocated.
+ */
+ if (++(*counter) >= MUTT_MIME_MAX_PARTS)
+ break;
}
}
}
@@ -779,11 +795,33 @@ BODY *mutt_parse_multipart (FILE *fp, const char *boundary, LOFF_T end_off, int
/* parse recursive MIME parts */
for (last = head; last; last = last->next)
- mutt_parse_part(fp, last);
+ _parse_part(fp, last, counter);
return (head);
}
+void mutt_parse_part (FILE *fp, BODY *b)
+{
+ int counter = 0;
+
+ _parse_part (fp, b, &counter);
+}
+
+BODY *mutt_parse_messageRFC822 (FILE *fp, BODY *parent)
+{
+ int counter = 0;
+
+ return _parse_messageRFC822 (fp, parent, &counter);
+}
+
+BODY *mutt_parse_multipart (FILE *fp, const char *boundary, LOFF_T end_off, int digest)
+{
+ int counter = 0;
+
+ return _parse_multipart (fp, boundary, end_off, digest, &counter);
+}
+
+
static const char *uncomment_timezone (char *buf, size_t buflen, const char *tz)
{
char *p;