From 7db13b942b33ced407232b2ea1ce211e851a7678 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Sun, 7 Jun 2026 10:22:55 -0400 Subject: [PATCH] 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 " 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. --- mailparse.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/mailparse.c b/mailparse.c index 371ec9b..df3636d 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 ". 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 ". 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 ". 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 */