[PECL-CVS] [pecl-mail-mailparse] master: Fix out-of-bounds read on malformed uuencode "begin" line

[email protected] (Ilia Alshanetsky via Remi Collet) Fri, 12 Jun 2026 13:36:27 +0000
Newsgroups php.pecl.cvs
Message-ID <[email protected]>
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 */