[pecl-mail-mailparse] master: Fix out-of-bounds read on malformed uuencode "begin" line
| From: | Ilia Alshanetsky via Remi Collet | Date: | Fri, 12 Jun 2026 13:36:27 +0000 |
| Subject: | [pecl-mail-mailparse] master: Fix out-of-bounds read on malformed uuencode "begin" line | ||
| Groups: | php.pecl.cvs | ||
| Request: | Send a blank email to pecl-cvs+get-28572@lists.php.net to get a copy of this message | ||
Author: Ilia Alshanetsky (iliaal)
Committer: Remi Collet (remicollet)
Date: 2026-06-12T15:36:13+02:00
Commit: https://github.com/php/pecl-mail-mailparse/commit/4587bbf7a8062f9fb572a9f4d2e8da0e0b00341f
Raw diff: https://github.com/php/pecl-mail-mailparse/commit/4587bbf7a8062f9fb572a9f4d2e8da0e0b00341f.diff
Fix out-of-bounds read on malformed uuencode "begin" line
The three uudecode loops (mailparse_msg_extract_uue, _enum_uue and
mailparse_uudecode_all) matched a "begin " prefix (6 bytes) and then
unconditionally read the filename at buffer[10], assuming the
"begin <mode> <name>" layout. A short line such as "begin 644\n"
(strlen 10) put buffer[10] at or past the NUL terminator, reading
into stack/heap garbage. The subsequent trailing-whitespace trim
(
while (isspace(origfilename[len-1]))) could also underflow to
origfilename[-1] when the filename was empty.
Clamp the filename offset to the actual line length and guard the trim
loop with len > 0. Also cast the isspace() argument to unsigned char to
avoid UB on bytes with the high bit set.
Changed paths:
M mailparse.c
Diff:
diff --git a/mailparse.c b/mailparse.c
index 1e23ebd..7d8d218 100644
--- a/mailparse.c
+++ b/mailparse.c
@@ -528,10 +528,14 @@ PHP_METHOD(mimemessage, extract_uue)
/* parse out the file name.
* The next 4 bytes are an octal number for perms; ignore it */
- origfilename = &buffer[10];
+ /* The filename starts after "begin <mode> ". Guard against
+ * a short "begin" line so we don't index past the NUL
+ * terminator into stack garbage. */
+ len = strlen(buffer);
+ origfilename = &buffer[len > 10 ? 10 : len];
/* NUL terminate the filename */
len = strlen(origfilename);
- while(isspace(origfilename[len-1]))
+ while (len > 0 && isspace((unsigned char)origfilename[len-1]))
origfilename[--len] = '\0';
/* make the return an array */
@@ -618,10 +622,14 @@ PHP_METHOD(mimemessage, enum_uue)
/* parse out the file name.
* The next 4 bytes are an octal number for perms; ignore it */
- origfilename = &buffer[10];
+ /* The filename starts after "begin <mode> ". Guard against
+ * a short "begin" line so we don't index past the NUL
+ * terminator into stack garbage. */
+ len = strlen(buffer);
+ origfilename = &buffer[len > 10 ? 10 : len];
/* NUL terminate the filename */
len = strlen(origfilename);
- while(isspace(origfilename[len-1]))
+ while (len > 0 && isspace((unsigned char)origfilename[len-1]))
origfilename[--len] = '\0';
/* make the return an array */
@@ -812,10 +820,14 @@ PHP_FUNCTION(mailparse_uudecode_all)
/* parse out the file name.
* The next 4 bytes are an octal number for perms; ignore it */
- origfilename = &buffer[10];
+ /* The filename starts after "begin <mode> ". Guard against
+ * a short "begin" line so we don't index past the NUL
+ * terminator into stack garbage. */
+ len = strlen(buffer);
+ origfilename = &buffer[len > 10 ? 10 : len];
/* NUL terminate the filename */
len = strlen(origfilename);
- while(isspace(origfilename[len-1]))
+ while (len > 0 && isspace((unsigned char)origfilename[len-1]))
origfilename[--len] = '\0';
/* make the return an array */