aboutsummaryrefslogtreecommitdiffstats
path: root/meta-networking/recipes-support/dovecot/dovecot/0009-lib-mail-message-parser-Don-t-use-memory-pool-for-pa.patch
blob: aade7dc2b324f8d48ed8a84d1444c05c3a8cd52a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
From d53d83214b1d635446a8cf8ff9438cc530133d62 Mon Sep 17 00:00:00 2001
From: Timo Sirainen <timo.sirainen@open-xchange.com>
Date: Thu, 23 Apr 2020 15:00:57 +0300
Subject: [PATCH 09/13] lib-mail: message-parser - Don't use memory pool for
 parser

This reduces memory usage when parsing many MIME parts where boundaries are
being added and removed constantly.
---
 src/lib-mail/message-parser.c | 48 ++++++++++++++++++++++++++++---------------
 1 file changed, 32 insertions(+), 16 deletions(-)

Signed-off-by: Sana Kazi <Sana.Kazi@kpit.com>

CVE: CVE-2020-12100
Upstream-Status: Backport [http://archive.ubuntu.com/ubuntu/pool/main/d/dovecot/dovecot_2.2.33.2-1ubuntu4.7.debian.tar.xz]
Comment: No change in any hunk

diff --git a/src/lib-mail/message-parser.c b/src/lib-mail/message-parser.c
index 028f74159..8970d8e0e 100644
--- a/src/lib-mail/message-parser.c
+++ b/src/lib-mail/message-parser.c
@@ -17,14 +17,14 @@ struct message_boundary {
 	struct message_boundary *next;
 
 	struct message_part *part;
-	const char *boundary;
+	char *boundary;
 	size_t len;
 
 	unsigned int epilogue_found:1;
 };
 
 struct message_parser_ctx {
-	pool_t parser_pool, part_pool;
+	pool_t part_pool;
 	struct istream *input;
 	struct message_part *parts, *part;
 	const char *broken_reason;
@@ -32,7 +32,7 @@ struct message_parser_ctx {
 	enum message_header_parser_flags hdr_flags;
 	enum message_parser_flags flags;
 
-	const char *last_boundary;
+	char *last_boundary;
 	struct message_boundary *boundaries;
 
 	struct message_part **next_part;
@@ -223,10 +223,24 @@ static void message_part_finish(struct message_parser_ctx *ctx)
 	ctx->part = ctx->part->parent;
 }
 
+static void message_boundary_free(struct message_boundary *b)
+{
+	i_free(b->boundary);
+	i_free(b);
+}
+
 static void
 boundary_remove_until(struct message_parser_ctx *ctx,
 		      struct message_boundary *boundary)
 {
+	while (ctx->boundaries != boundary) {
+		struct message_boundary *cur = ctx->boundaries;
+
+		i_assert(cur != NULL);
+		ctx->boundaries = cur->next;
+		message_boundary_free(cur);
+
+	}
 	ctx->boundaries = boundary;
 }
 
@@ -234,15 +248,14 @@ static void parse_next_body_multipart_init(struct message_parser_ctx *ctx)
 {
 	struct message_boundary *b;
 
-	b = p_new(ctx->parser_pool, struct message_boundary, 1);
+	b = i_new(struct message_boundary, 1);
 	b->part = ctx->part;
 	b->boundary = ctx->last_boundary;
+	ctx->last_boundary = NULL;
 	b->len = strlen(b->boundary);
 
 	b->next = ctx->boundaries;
 	ctx->boundaries = b;
-
-	ctx->last_boundary = NULL;
 }
 
 static int parse_next_body_message_rfc822_init(struct message_parser_ctx *ctx,
@@ -359,6 +372,8 @@ static int parse_part_finish(struct message_parser_ctx *ctx,
 			     struct message_block *block_r, bool first_line)
 {
 	size_t line_size;
+	size_t boundary_len = boundary->len;
+	bool boundary_epilogue_found = boundary->epilogue_found;
 
 	i_assert(ctx->last_boundary == NULL);
 
@@ -391,7 +406,7 @@ static int parse_part_finish(struct message_parser_ctx *ctx,
 		i_assert(block_r->data[0] == '\n');
 		line_size = 1;
 	}
-	line_size += 2 + boundary->len + (boundary->epilogue_found ? 2 : 0);
+	line_size += 2 + boundary_len + (boundary_epilogue_found ? 2 : 0);
 	i_assert(block_r->size >= ctx->skip + line_size);
 	block_r->size = line_size;
 	parse_body_add_block(ctx, block_r);
@@ -553,9 +568,9 @@ static void parse_content_type(struct message_parser_ctx *ctx,
 	for (; *results != NULL; results += 2) {
 		if (strcasecmp(results[0], "boundary") == 0) {
 			/* truncate excessively long boundaries */
+			i_free(ctx->last_boundary);
 			ctx->last_boundary =
-				p_strndup(ctx->parser_pool, results[1],
-					  BOUNDARY_STRING_MAX_LEN);
+				i_strndup(results[1], BOUNDARY_STRING_MAX_LEN);
 			break;
 		}
 	}
@@ -678,7 +693,7 @@ static int parse_next_header(struct message_parser_ctx *ctx,
 		i_assert(!ctx->multipart);
 		part->flags = 0;
 	}
-	ctx->last_boundary = NULL;
+	i_free(ctx->last_boundary);
 
 	if (!ctx->part_seen_content_type ||
 	    (part->flags & MESSAGE_PART_FLAG_IS_MIME) == 0) {
@@ -1081,11 +1096,8 @@ message_parser_init_int(struct istream *input,
 			enum message_parser_flags flags)
 {
 	struct message_parser_ctx *ctx;
-	pool_t pool;
 
-	pool = pool_alloconly_create("Message Parser", 1024);
-	ctx = p_new(pool, struct message_parser_ctx, 1);
-	ctx->parser_pool = pool;
+	ctx = i_new(struct message_parser_ctx, 1);
 	ctx->hdr_flags = hdr_flags;
 	ctx->flags = flags;
 	ctx->input = input;
@@ -1105,7 +1117,7 @@ message_parser_init(pool_t part_pool, struct istream *input,
 	ctx->parts = ctx->part = p_new(part_pool, struct message_part, 1);
 	ctx->next_part = &ctx->part->children;
 	ctx->parse_next_block = parse_next_header_init;
-	p_array_init(&ctx->next_part_stack, ctx->parser_pool, 4);
+	i_array_init(&ctx->next_part_stack, 4);
 	return ctx;
 }
 
@@ -1146,8 +1158,12 @@ int message_parser_deinit_from_parts(struct message_parser_ctx **_ctx,
 
 	if (ctx->hdr_parser_ctx != NULL)
 		message_parse_header_deinit(&ctx->hdr_parser_ctx);
+	boundary_remove_until(ctx, NULL);
 	i_stream_unref(&ctx->input);
-	pool_unref(&ctx->parser_pool);
+	if (array_is_created(&ctx->next_part_stack))
+		array_free(&ctx->next_part_stack);
+	i_free(ctx->last_boundary);
+	i_free(ctx);
 	i_assert(ret < 0 || *parts_r != NULL);
 	return ret;
 }
-- 
2.11.0