Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP1:GA
mutt.30625
nofreeze-c72f740a.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File nofreeze-c72f740a.patch of Package mutt.30625
From c72f740aa7c80c0a79775628e62daa2a43357cd5 Mon Sep 17 00:00:00 2001 From: Kevin McCarthy <kevin@8t8.us> Date: Tue, 19 May 2020 12:26:55 -0700 Subject: [PATCH] Add mitigation against DoS from thousands of parts. A demonstration attack using a million tiny parts will freeze Mutt for several minutes. This is actually better than some other mail software, but can still be a problem at large levels. For now, set it to a very conservative 5000, but this can be adjusted up (or down) if necessary. Declare the previous stack-limit max depth as a constant too, and decrease it down to 50. Change the handler to return non-fatal "1" on reaching the limit. --- handler.c | 9 ++++++++ mime.h | 5 ++++ parse.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 72 insertions(+), 11 deletions(-) --- handler.c +++ handler.c 2020-12-02 13:13:03.692676976 +0000 @@ -1720,8 +1720,16 @@ int mutt_body_handler (BODY *b, STATE *s int plaintext = 0; handler_t handler = NULL; int rc = 0; + static unsigned short recurse_level = 0; int oflags = s->flags; + + if (recurse_level >= MUTT_MIME_MAX_DEPTH) + { + dprint (1, (debugfile, "mutt_body_handler: recurse level too deep. giving up!\n")); + return 1; + } + recurse_level++; /* first determine which handler to use to process this part */ @@ -1836,6 +1844,7 @@ int mutt_body_handler (BODY *b, STATE *s fputs (" --]\n", s->fpout); } + recurse_level--; s->flags = oflags | (s->flags & MUTT_FIRSTDONE); if (rc) { --- mime.h +++ mime.h 2020-12-02 13:11:27.322523653 +0000 @@ -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 --- parse.c +++ parse.c 2020-12-08 09:03:21.076476696 +0000 @@ -34,6 +34,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. @@ -481,9 +487,17 @@ BODY *mutt_read_mime_header (FILE *fp, i 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 >= MUTT_MIME_MAX_DEPTH) + { + dprint (1, (debugfile, "mutt_parse_part(): recurse level too deep. giving up!\n")); + return; + } + recurse_level++; switch (b->type) { @@ -496,9 +510,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: @@ -506,16 +521,16 @@ 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 - return; + goto bail; } break; default: - return; + goto bail; } /* try to recover from parsing error */ @@ -524,6 +539,8 @@ void mutt_parse_part (FILE *fp, BODY *b) b->type = TYPETEXT; mutt_str_replace (&b->subtype, "plain"); } +bail: + recurse_level--; } /* parse a MESSAGE/RFC822 body @@ -537,7 +554,7 @@ void mutt_parse_part (FILE *fp, BODY *b) * 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; @@ -555,7 +572,7 @@ BODY *mutt_parse_messageRFC822 (FILE *fp if (msg->length < 0) msg->length = 0; - mutt_parse_part(fp, msg); + _parse_part(fp, msg, counter); return (msg); } @@ -572,7 +589,8 @@ BODY *mutt_parse_messageRFC822 (FILE *fp * 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; @@ -649,6 +667,14 @@ BODY *mutt_parse_multipart (FILE *fp, co } 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; } } } @@ -659,11 +685,32 @@ BODY *mutt_parse_multipart (FILE *fp, co /* 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;
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor