Re: Fwd: report 1/3: buffer under-read in rfc2047.c lwslen()

"Kevin J. McCarthy" <[email protected]> Thu, 18 Jun 2026 11:28:00 +0800
Newsgroups gmane.mail.mutt.devel
Message-ID <[email protected]>
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 (application/pgp-signature, 833 B)
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEiXWpszqjeRA4XFMIre92hIAxa9oFAmozZcAACgkQre92hIAx
a9ojzRAAu7tQmmc3dW0+hdOFPMF/7tMZIAdb0jxxqTpzA6Xcv/StAf5yOL5SPyMX
YnRBo2ZfLr07gxa2hCbYYIomXZ+P86XhSiNmq2eHxYdGLVr+U9gRYuXHbQFRR6bT
37rYhvLbg5MxATlv/Puh6zB01o84g4el/6Y0xgd6VMau+9iy1kkZxCF7ilGHDBuq
fMBy5fA5fAGz81QWfzFiteok22j800OQSh3vMfKCMRquzwjf7W65jry93VtHIBMg
HL7pGgG40pvP9EazI7m+Dpqf23mRxSzE5qGlfwmI8ixM023OopUa+ItYdJV/ijvk
O+wDT0MHOd0ddDDkyy51ay4fcZ/UeQ9UJG99GJtEEoDCVjtsb8FV/5rssCTPmoWi
NmytTNkcVMqrxcKZaWLHVv9ynMxXXxqj9KXtqNfzJbhZGhXIzKknTYBUfjD/gGzk
41CulHhUxocU7gsU+OruzAnGhRdJp0ViPq/vANOKg4BMs2zqkVYxmd6nbv81JW+h
GVNutzjpDN96P43waq1ZhqEmkxe8qiW/MZgPpvpIQx7IHjUu36to2Kcdmc7VVzE6
pkUlKRVpduaBkW/QUQsqU7xAXuF6XbHOzNUHRtyuEiXE7NZdNCwj8bYA8eoQIOlF
O9qOJqledscZEd1BdU+VB40o19sPWsiA/pDHbePO8IMo5P/RJ50=
=4TiL
-----END PGP SIGNATURE-----