From: Kevin McCarthy Date: Mon, 9 Nov 2015 23:40:42 +0000 (-0800) Subject: Fix possible unintentional '\0' strchr matches. X-Git-Tag: mutt-1-6-rel~78 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e27a9746c943c23be612252d4370ac1b96f390e8;p=mutt Fix possible unintentional '\0' strchr matches. After fixing the ticket 3787 strchr issue, this patch cleans up other potentially incorrect uses of strchr for the '\0' case. In mutt_multi_choice(), mutt_getch() can technically return 0. Although it seems the user would have to try quite hard to do this, it's incorrect to return that index into letters. Change "ch.ch==0" to be considered the same as an abort. is_email_wsp() is used in a couple places where it wasn't obvious whether '\0' was being accounted for, so add an explicit check to the function. Inside eat_date(), if mutt_extract_token() had no input and returned "", the strchr ("<>=", buffer.data[0]) below would return a pointer. In actuality, this is prevented by an empty parameter check inside mutt_pattern_comp(), but it doesn't hurt to make it the same as eat_regexp() and have the check explicitly done here too. rfc2047_encode() was another borderline case for adding a check. The convert_string() sets a length, so it seems highly unlikely that *t could be 0, but doesn't hurt to add the check. The find_encoded_word() fix looks necessary. If the passed in s was something like "=?charset?" (followed by EOS, '\0'), the strchr("BbQq", q[1]) would in fact return a pointer and the following q[2] would read past the end of string. If q[2] happened to be '?', it might even continue reading in the for loop below. Lastly, in parse_mailboxdomain(), the potential overread was already fixed in changeset:a6919571eb59, but although the nonspecial and special strchr() line happens to "work" for the case of '\0', it's pretty fragile to leave as is. It's better to be explicit and just return if we hit EOS without calling next_token(). --- diff --git a/curs_lib.c b/curs_lib.c index d70c327f..e28d88c0 100644 --- a/curs_lib.c +++ b/curs_lib.c @@ -713,7 +713,8 @@ int mutt_multi_choice (char *prompt, char *letters) { mutt_refresh (); ch = mutt_getch (); - if (ch.ch < 0 || CI_is_return (ch.ch)) + /* (ch.ch == 0) is technically possible. Treat the same as < 0 (abort) */ + if (ch.ch <= 0 || CI_is_return (ch.ch)) { choice = -1; break; diff --git a/lib.h b/lib.h index 3c385873..0b7a85b4 100644 --- a/lib.h +++ b/lib.h @@ -112,7 +112,7 @@ static inline char *skip_email_wsp(const char *s) static inline int is_email_wsp(char c) { - return strchr(EMAIL_WSP, c) != NULL; + return c && (strchr(EMAIL_WSP, c) != NULL); } diff --git a/pattern.c b/pattern.c index 7af1c381..6f05b4a5 100644 --- a/pattern.c +++ b/pattern.c @@ -582,6 +582,11 @@ static int eat_date (pattern_t *pat, BUFFER *s, BUFFER *err) strfcpy (err->data, _("error in expression"), err->dsize); return (-1); } + if (!*buffer.data) + { + snprintf (err->data, err->dsize, _("Empty expression")); + return (-1); + } memset (&min, 0, sizeof (min)); /* the `0' time is Jan 1, 1970 UTC, so in order to prevent a negative time diff --git a/rfc2047.c b/rfc2047.c index b5e8704d..a1a6c2e4 100644 --- a/rfc2047.c +++ b/rfc2047.c @@ -438,7 +438,7 @@ static int rfc2047_encode (ICONV_CONST char *d, size_t dlen, int col, if (!t0) t0 = t; t1 = t; } - else if (specials && strchr (specials, *t)) + else if (specials && *t && strchr (specials, *t)) { if (!s0) s0 = t; s1 = t; @@ -740,7 +740,7 @@ static const char *find_encoded_word (const char *s, const char **x) 0x20 < *q && *q < 0x7f && !strchr ("()<>@,;:\"/[]?.=", *q); q++) ; - if (q[0] != '?' || !strchr ("BbQq", q[1]) || q[2] != '?') + if (q[0] != '?' || q[1] == '\0' || !strchr ("BbQq", q[1]) || q[2] != '?') continue; /* non-strict check since many MUAs will not encode spaces and question marks */ for (q = q + 3; 0x20 <= *q && *q < 0x7f && (*q != '?' || q[1] != '='); q++) diff --git a/rfc822.c b/rfc822.c index 80347824..d9aad9e9 100644 --- a/rfc822.c +++ b/rfc822.c @@ -229,6 +229,9 @@ parse_mailboxdomain (const char *s, const char *nonspecial, while (*s) { s = skip_email_wsp(s); + if (! *s) + return s; + if (strchr (nonspecial, *s) == NULL && is_special (*s)) return s;