Merge pull request #1 from darthmama/master

Added detection and mitigation for CRCR pattern
merge-experiment
darthmama 7 years ago committed by GitHub
commit 5721187397

@ -71,6 +71,9 @@
static int mailmime_charset_parse(const char * message, size_t length,
size_t * indx, char ** charset);
static int detect_CRCR(const char * message, size_t length,
size_t * indx);
enum {
MAILMIME_ENCODING_B,
MAILMIME_ENCODING_Q
@ -124,12 +127,16 @@ int mailmime_encoded_phrase_parse(const char * default_fromcode,
type = TYPE_ERROR; /* XXX - removes a gcc warning */
// Start parsing
while (1) {
int has_fwd;
word = NULL;
// Try to parse this part of the message as mime-encoded
r = mailmime_encoded_word_parse(message, length, &cur_token, &word, &has_fwd, &missing_closing_quote);
if (r == MAILIMF_NO_ERROR) {
// Either it was mime-encoded or there was no error.
if ((!first) && has_fwd) {
if (type != TYPE_ENCODED_WORD) {
if (mmap_string_append_c(gphrase, ' ') == NULL) {
@ -171,6 +178,7 @@ int mailmime_encoded_phrase_parse(const char * default_fromcode,
}
if (wordutf8 != NULL) {
// append the word (converted to the proper charset)
if (mmap_string_append(gphrase, wordutf8) == NULL) {
mailmime_encoded_word_free(word);
free(wordutf8);
@ -183,17 +191,38 @@ int mailmime_encoded_phrase_parse(const char * default_fromcode,
first = FALSE;
}
else if (r == MAILIMF_ERROR_PARSE) {
// Wasn't mime-encoded
/* do nothing */
}
else {
// Some error condition we didn't expect
res = r;
goto free;
}
if (r == MAILIMF_ERROR_PARSE) {
// Not mime-encoded, so parse as if it isn't
char * raw_word;
raw_word = NULL;
// Check for special case of word=^CRCR.
// We need to be sure we advanced the cur_token
// past it. Usually with an empty string.
if (first) {
r = detect_CRCR(message, length, &cur_token);
if (r == MAILIMF_NO_ERROR) {
// We've advanced the token and pretend
// the first CR isn't there. Let the algorithm
// take care of the legit CRLF.
if (mmap_string_append_c(gphrase, ' ') == NULL) {
res = MAILIMF_ERROR_MEMORY;
goto free;
}
first = FALSE;
break;
}
}
r = mailmime_non_encoded_word_parse(message, length,
&cur_token, &raw_word, &has_fwd);
if (r == MAILIMF_NO_ERROR) {
@ -296,17 +325,21 @@ mailmime_non_encoded_word_parse(const char * message, size_t length,
cur_token = * indx;
has_fwd = 0;
// Check to see if it starts with folding whitespace
r = mailimf_fws_parse(message, length, &cur_token);
if (r == MAILIMF_NO_ERROR) {
if (r == MAILIMF_NO_ERROR) { // it does
has_fwd = 1;
}
if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
// legit error
res = r;
goto err;
}
begin = cur_token;
// Get the word up to the next =? or whitespace
state = 0;
end = FALSE;
while (1) {
@ -325,7 +358,7 @@ mailmime_non_encoded_word_parse(const char * message, size_t length,
state = 1;
break;
case '?':
if (state == 1) {
if (state == 1) { // begin of mime-encoding?
cur_token --;
end = TRUE;
}
@ -340,7 +373,7 @@ mailmime_non_encoded_word_parse(const char * message, size_t length,
cur_token ++;
}
if (cur_token - begin == 0) {
if (cur_token - begin == 0) { // we processed nothing, bail
res = MAILIMF_ERROR_PARSE;
goto err;
}
@ -389,14 +422,15 @@ int mailmime_encoded_word_parse(const char * message, size_t length,
missing_closing_quote = 0;
has_fwd = 0;
r = mailimf_fws_parse(message, length, &cur_token);
if (r == MAILIMF_NO_ERROR) {
if (r == MAILIMF_NO_ERROR) { // there was folding whitespace, now consumed
has_fwd = 1;
}
if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { // actual error
res = r;
goto err;
}
// check for opening quote, consume if so
opening_quote = FALSE;
r = mailimf_char_parse(message, length, &cur_token, '\"');
if (r == MAILIMF_NO_ERROR) {
@ -410,42 +444,50 @@ int mailmime_encoded_word_parse(const char * message, size_t length,
goto err;
}
// Check for MIME encoded-word syntax
// =?charset?encoding?encoded text?=
r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "=?");
if (r != MAILIMF_NO_ERROR) {
res = r;
goto err;
}
// get charset
r = mailmime_charset_parse(message, length, &cur_token, &charset);
if (r != MAILIMF_NO_ERROR) {
res = r;
goto err;
}
// charset terminator
r = mailimf_char_parse(message, length, &cur_token, '?');
if (r != MAILIMF_NO_ERROR) {
res = r;
goto free_charset;
}
// get encoding
r = mailmime_encoding_parse(message, length, &cur_token, &encoding);
if (r != MAILIMF_NO_ERROR) {
res = r;
goto free_charset;
}
// encoding terminator
r = mailimf_char_parse(message, length, &cur_token, '?');
if (r != MAILIMF_NO_ERROR) {
res = r;
goto free_charset;
}
// get encoded text
end = FALSE;
end_encoding = cur_token;
while (1) {
if (end_encoding >= length)
break;
// are we done?
if (end_encoding + 1 < length) {
if ((message[end_encoding] == '?') && (message[end_encoding + 1] == '=')) {
end = TRUE;
@ -458,44 +500,49 @@ int mailmime_encoded_word_parse(const char * message, size_t length,
end_encoding ++;
}
// decode text
decoded_len = 0;
decoded = NULL;
switch (encoding) {
case MAILMIME_ENCODING_B:
r = mailmime_base64_body_parse(message, end_encoding,
&cur_token, &decoded,
&decoded_len);
if (r != MAILIMF_NO_ERROR) {
res = r;
goto free_charset;
}
break;
case MAILMIME_ENCODING_Q:
r = mailmime_quoted_printable_body_parse(message, end_encoding,
&cur_token, &decoded,
&decoded_len, TRUE);
if (r != MAILIMF_NO_ERROR) {
res = r;
goto free_charset;
}
break;
case MAILMIME_ENCODING_B:
r = mailmime_base64_body_parse(message, end_encoding,
&cur_token, &decoded,
&decoded_len);
if (r != MAILIMF_NO_ERROR) {
res = r;
goto free_charset;
}
break;
case MAILMIME_ENCODING_Q:
r = mailmime_quoted_printable_body_parse(message, end_encoding,
&cur_token, &decoded,
&decoded_len, TRUE);
if (r != MAILIMF_NO_ERROR) {
res = r;
goto free_charset;
}
break;
}
text = malloc(decoded_len + 1);
if (text == NULL) {
res = MAILIMF_ERROR_MEMORY;
goto free_charset;
}
// Copy decoded text
if (decoded_len > 0)
memcpy(text, decoded, decoded_len);
text[decoded_len] = '\0';
mailmime_decoded_part_free(decoded);
// Detect if we stopped parsing the *encoded* text (before we sent it off to
// be decoded because we hit the terminator, or because we hit the end
// of the specified length
r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "?=");
#if 0
if (r != MAILIMF_NO_ERROR) {
@ -618,3 +665,20 @@ static int mailmime_etoken_parse(const char * message, size_t length,
indx, result,
is_etoken_char);
}
static int detect_CRCR(const char * message, size_t length,
size_t * indx) {
size_t cur_token = *indx;
int r = mailimf_char_parse(message, length, &cur_token, '\r');
if (r == MAILIMF_NO_ERROR) {
r = mailimf_char_parse(message, length, &cur_token, '\r');
if (r == MAILIMF_NO_ERROR) {
// Yup, there was a CRCR here.
// Advance token past the first \r
*indx = (*indx) + 1;
return r;
}
}
// Leave indx alone and move on.
return MAILIMF_ERROR_PARSE; // not actual error. Usual behaviour.
}

Loading…
Cancel
Save