Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion php_mailparse_mime.c
Original file line number Diff line number Diff line change
Expand Up @@ -523,8 +523,18 @@ static int php_mimepart_process_header(php_mimepart *part)

static php_mimepart *alloc_new_child_part(php_mimepart *parentpart, size_t startpos, int inherit)
{
php_mimepart *child = php_mimepart_alloc();
php_mimepart *child;
php_mimepart *ancestor;
zval child_z;
int depth = 0;

for (ancestor = parentpart; ancestor != NULL; ancestor = ancestor->parent) {
if (++depth >= MAXLEVELS) {
return NULL;
}
}

child = php_mimepart_alloc();

parentpart->parsedata.lastpart = child;
child->parent = parentpart;
Expand Down Expand Up @@ -619,6 +629,10 @@ static int php_mimepart_process_line(php_mimepart *workpart)
}

newpart = alloc_new_child_part(workpart, workpart->endpos + origcount, 1);
if (newpart == NULL) {
php_error_docref(NULL, E_WARNING, "MIME message too deeply nested");
return FAILURE;
}
php_mimepart_update_positions(workpart, workpart->endpos + origcount, workpart->endpos + linelen, 1);
if (workpart->mime_version) {
newpart->mime_version = estrdup(workpart->mime_version);
Expand Down Expand Up @@ -716,6 +730,10 @@ static int php_mimepart_process_line(php_mimepart *workpart)

if (CONTENT_TYPE_IS(workpart, "message/rfc822")) {
workpart = alloc_new_child_part(workpart, workpart->bodystart, 0);
if (workpart == NULL) {
php_error_docref(NULL, E_WARNING, "MIME message too deeply nested");
return FAILURE;
}
workpart->parsedata.in_header = 1;
return SUCCESS;

Expand All @@ -724,6 +742,10 @@ static int php_mimepart_process_line(php_mimepart *workpart)
/* create a section for the preamble that precedes the first boundary */
if (workpart->boundary) {
workpart = alloc_new_child_part(workpart, workpart->bodystart, 1);
if (workpart == NULL) {
php_error_docref(NULL, E_WARNING, "MIME message too deeply nested");
return FAILURE;
}
workpart->parsedata.in_header = 0;
workpart->parsedata.is_dummy = 1;
return SUCCESS;
Expand Down
18 changes: 18 additions & 0 deletions tests/mime_nesting_depth.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Deeply nested MIME parts are rejected instead of overflowing the stack
--SKIPIF--
<?php if (!extension_loaded("mailparse")) print "skip"; ?>
--FILE--
<?php
$msg = str_repeat("Content-Type: message/rfc822\n\n", 1000);
$m = mailparse_msg_create();
var_dump(mailparse_msg_parse($m, $msg));
/* walking the (capped) tree must not crash */
mailparse_msg_get_structure($m);
echo "done\n";
mailparse_msg_free($m);
?>
--EXPECTF--
Warning: mailparse_msg_parse(): MIME message too deeply nested in %s on line %d
bool(false)
done
Loading