On Thu, Jun 18, 2026 at 08:13:35AM +0800, Kevin J. McCarthy wrote:
On Thu, Jun 18, 2026 at 08:09:01AM +0800, Kevin J. McCarthy wrote:From: Acts1631 <[email protected]> The lwslen() helper calculates the length of linear whitespace at the beginning of a string. It scans until the first non-whitespace character, then evaluates *(p - 1):for (; p < s + n; p++) if (!strchr(" \t\r\n", *p)) { len = (size_t)(p - s); break; } if (strchr("\r\n", *(p-1))) len = (size_t)0;This relies on 1) a invalid rfc2047 encodeed word (because the spec says there must be LWN) and 2) an obscure option being set, which defaults off.However, the bug report is valid. Mutt will under-read the buffer.
I've taken a closer look. It looks like this will not read outside of the buffer "*pd" passed into rfc2047_decode() because the call to lwnlen() is only triggered after an encoded word is found: meaning s > *pd.
Furthermore the underread will simply see the last character in the previous encoded word: '?' and so won't change the logic.
In this case, I think the proposed patch is the best solution:
diff --git a/rfc2047.c b/rfc2047.c
index d72ae997..2bdd8553 100644
--- a/rfc2047.c
+++ b/rfc2047.c
@@ -815,7 +815,7 @@ static size_t lwslen(const char *s, size_t n)
len = (size_t)(p - s);
break;
}
- if (strchr("\r\n", *(p-1))) /* LWS doesn't end with CRLF */
+ if (len > 0 && strchr("\r\n", *(p-1))) /* LWS doesn't end with CRLF */
len = (size_t)0;
return len;
}
I could instead bump p after the faiing strchr inside the loop, but this
is less elegant because the strchr after the loop would run even if len
were 0:
for (; p < s + n; p++)
if (!strchr(" \t\r\n", *p))
{
len = (size_t)(p - s);
+ p++;
break;
}
if (strchr("\r\n", *(p-1))) /* LWS doesn't end with CRLF */
len = (size_t)0;
return len;
However, again, since this is not reading outside of allocated memory, I
will also delay this until after the 2.4.0 release.
-- Kevin J. McCarthy GPG Fingerprint: 8975 A9B3 3AA3 7910 385C 5308 ADEF 7684 8031 6BDA
signature.asc
Description: PGP signature
