[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 */