[PECL-CVS] [pecl-mail-mailparse] master: Fix out-of-bounds read in RFC822 group/route-addr address parsing
[email protected] (Ilia Alshanetsky via Remi Collet) Wed, 24 Jun 2026 08:04:51 +0000
| Newsgroups | php.pecl.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: Ilia Alshanetsky (iliaal)
Committer: Remi Collet (remicollet)
Date: 2026-06-24T10:02:08+02:00
Commit: https://github.com/php/pecl-mail-mailparse/commit/c3587d9d3f652ab02059ba6a07596398bc7e1ee1
Raw diff: https://github.com/php/pecl-mail-mailparse/commit/c3587d9d3f652ab02059ba6a07596398bc7e1ee1.diff
Fix out-of-bounds read in RFC822 group/route-addr address parsing
Changed paths:
A tests/rfc822_group_routeaddr_oob.phpt
M php_mailparse_rfc822.c
M php_mailparse_rfc822.re
Diff:
diff --git a/php_mailparse_rfc822.c b/php_mailparse_rfc822.c
index c66d802..357538d 100644
--- a/php_mailparse_rfc822.c
+++ b/php_mailparse_rfc822.c
@@ -485,7 +485,7 @@ static void parse_address_tokens(php_rfc822_tokenized_t *toks,
;
/* the stuff from start_tok to i - 1 is the display name part */
- if (addrs && !in_group && i - start_tok > 0) {
+ if (addrs && !in_group && i - start_tok > 0 && iaddr < addrs->naddrs) {
int j, has_comments = 0, has_strings = 0;
switch(i < toks->ntokens ? toks->tokens[i].token : 0) {
case ';': case ',': case '<':
@@ -561,9 +561,10 @@ static void parse_address_tokens(php_rfc822_tokenized_t *toks,
}
if (addrs && address_value) {
+ int slot_ok = iaddr < addrs->naddrs;
/* if no display name has been given, use the address */
- if (addrs->addrs[iaddr].name == NULL) {
+ if (slot_ok && addrs->addrs[iaddr].name == NULL) {
addrs->addrs[iaddr].name = estrdup(address_value);
}
@@ -572,8 +573,10 @@ static void parse_address_tokens(php_rfc822_tokenized_t *toks,
smart_string_appendl(&group_addrs, ",", 1);
smart_string_appends(&group_addrs, address_value);
efree(address_value);
- } else {
+ } else if (slot_ok) {
addrs->addrs[iaddr].address = address_value;
+ } else {
+ efree(address_value);
}
address_value = NULL;
}
@@ -586,7 +589,7 @@ static void parse_address_tokens(php_rfc822_tokenized_t *toks,
if ((start_tok < toks->ntokens && toks->tokens[start_tok].token == ';') || start_tok == toks->ntokens) {
/* end of group */
- if (addrs) {
+ if (addrs && iaddr < addrs->naddrs) {
smart_string_appendl(&group_addrs, ";", 1);
smart_string_0(&group_addrs);
addrs->addrs[iaddr].address = estrdup(group_addrs.c);
diff --git a/php_mailparse_rfc822.re b/php_mailparse_rfc822.re
index c22dabb..997e662 100644
--- a/php_mailparse_rfc822.re
+++ b/php_mailparse_rfc822.re
@@ -348,7 +348,7 @@ mailbox: /* addr-spec / phrase route-addr */
;
/* the stuff from start_tok to i - 1 is the display name part */
- if (addrs && !in_group && i - start_tok > 0) {
+ if (addrs && !in_group && i - start_tok > 0 && iaddr < addrs->naddrs) {
int j, has_comments = 0, has_strings = 0;
switch(i < toks->ntokens ? toks->tokens[i].token : 0) {
case ';': case ',': case '<':
@@ -424,9 +424,10 @@ mailbox: /* addr-spec / phrase route-addr */
}
if (addrs && address_value) {
+ int slot_ok = iaddr < addrs->naddrs;
/* if no display name has been given, use the address */
- if (addrs->addrs[iaddr].name == NULL) {
+ if (slot_ok && addrs->addrs[iaddr].name == NULL) {
addrs->addrs[iaddr].name = estrdup(address_value);
}
@@ -435,8 +436,10 @@ mailbox: /* addr-spec / phrase route-addr */
smart_string_appendl(&group_addrs, ",", 1);
smart_string_appends(&group_addrs, address_value);
efree(address_value);
- } else {
+ } else if (slot_ok) {
addrs->addrs[iaddr].address = address_value;
+ } else {
+ efree(address_value);
}
address_value = NULL;
}
@@ -449,7 +452,7 @@ mailbox: /* addr-spec / phrase route-addr */
if ((start_tok < toks->ntokens && toks->tokens[start_tok].token == ';') || start_tok == toks->ntokens) {
/* end of group */
- if (addrs) {
+ if (addrs && iaddr < addrs->naddrs) {
smart_string_appendl(&group_addrs, ";", 1);
smart_string_0(&group_addrs);
addrs->addrs[iaddr].address = estrdup(group_addrs.c);
diff --git a/tests/rfc822_group_routeaddr_oob.phpt b/tests/rfc822_group_routeaddr_oob.phpt
new file mode 100644
index 0000000..1151285
--- /dev/null
+++ b/tests/rfc822_group_routeaddr_oob.phpt
@@ -0,0 +1,20 @@
+--TEST--
+A route-addr inside a group does not read past the parsed address array
+--SKIPIF--
+<?php if (!extension_loaded("mailparse")) print "skip"; ?>
+--FILE--
+<?php
+/* A group whose inner mailbox is an unterminated route-addr ("<" with no ">")
+ * used to desync the counting and building passes of the address parser and
+ * index one slot past the end of the allocated address array. */
+foreach (array("<>:<", ":;:<", "a@b,<>:<") as $in) {
+ $r = mailparse_rfc822_parse_addresses($in);
+ var_dump(is_array($r));
+}
+echo "done\n";
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+done