From: Timo Sirainen Date: Mon, 25 Apr 2016 13:25:46 +0000 (+0300) Subject: lib-mail: istream-header-filter didn't limit memory usage. X-Git-Tag: 2.3.0.rc1~3943 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=76a71915c6452a4bee9a8ae89ddbdf58fa941dee;p=thirdparty%2Fdovecot%2Fcore.git lib-mail: istream-header-filter didn't limit memory usage. A large header was always added to hdr_buf, ignoring any max_buffer_size limits. --- diff --git a/src/lib-mail/istream-header-filter.c b/src/lib-mail/istream-header-filter.c index 2ac1f90a4d..3235a98273 100644 --- a/src/lib-mail/istream-header-filter.c +++ b/src/lib-mail/istream-header-filter.c @@ -143,6 +143,9 @@ static ssize_t hdr_stream_update_pos(struct header_filter_istream *mstream) ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip); i_assert(ret >= 0); mstream->istream.pos = pos; + + if (pos >= mstream->istream.max_buffer_size) + return -2; return ret; } @@ -180,6 +183,9 @@ static ssize_t read_header(struct header_filter_istream *mstream) } } + if (mstream->hdr_buf->used >= mstream->istream.max_buffer_size) + return -2; + while ((hdr_ret = message_parse_header_next(mstream->hdr_ctx, &hdr)) > 0) { mstream->cur_line++; @@ -262,6 +268,8 @@ static ssize_t read_header(struct header_filter_istream *mstream) break; } } + if (mstream->hdr_buf->used >= mstream->istream.max_buffer_size) + break; } if (hdr_ret < 0) { diff --git a/src/lib-mail/test-istream-header-filter.c b/src/lib-mail/test-istream-header-filter.c index e59f875c14..400c44ff39 100644 --- a/src/lib-mail/test-istream-header-filter.c +++ b/src/lib-mail/test-istream-header-filter.c @@ -98,6 +98,93 @@ static void test_istream_filter(void) test_end(); } +static void add_random_text(string_t *dest, unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + str_append_c(dest, rand() % ('z'-'a'+1) + 'a'); +} + +static void ATTR_NULL(3) +filter2_callback(struct header_filter_istream *input ATTR_UNUSED, + struct message_header_line *hdr, + bool *matched, void *context ATTR_UNUSED) +{ + if (hdr != NULL && strcmp(hdr->name, "To") == 0) + *matched = TRUE; +} + +static void test_istream_filter_large_buffer(void) +{ + string_t *input, *output; + struct istream *istream, *filter; + const unsigned char *data; + size_t size, prefix_len; + const char *p; + unsigned int i; + + test_begin("i_stream_create_header_filter(large buffer)"); + + input = str_new(default_pool, 1024*128); + output = str_new(default_pool, 1024*128); + str_append(input, "From: "); + add_random_text(input, 1024*31); + str_append(input, "\nTo: "); + add_random_text(input, 1024*32); + str_append(input, "\nSubject: "); + add_random_text(input, 1024*34); + str_append(input, "\n\nbody\n"); + + istream = test_istream_create_data(str_data(input), str_len(input)); + test_istream_set_max_buffer_size(istream, 8192); + + filter = i_stream_create_header_filter(istream, + HEADER_FILTER_EXCLUDE | + HEADER_FILTER_NO_CR, + NULL, 0, + filter2_callback, + (void *)NULL); + + for (i = 0; i < 2; i++) { + for (;;) { + ssize_t ret = i_stream_read(filter); + i_assert(ret != 0); + if (ret == -1) + break; + if (ret == -2) { + data = i_stream_get_data(filter, &size); + str_append_n(output, data, size); + i_stream_skip(filter, size); + } + } + + data = i_stream_get_data(filter, &size); + test_assert(size <= 8192); + str_append_n(output, data, size); + + p = strstr(str_c(input), "To: "); + i_assert(p != NULL); + prefix_len = p - str_c(input); + test_assert(strncmp(str_c(input), str_c(output), prefix_len) == 0); + + p = strchr(p, '\n'); + i_assert(p != NULL); + test_assert(strcmp(p+1, str_c(output) + prefix_len) == 0); + + /* seek back and retry once with caching */ + i_stream_seek(filter, 0); + str_truncate(output, 0); + } + + str_free(&input); + str_free(&output); + i_stream_unref(&filter); + i_stream_unref(&istream); + + test_end(); +} + static void ATTR_NULL(3) edit_callback(struct header_filter_istream *input, struct message_header_line *hdr, @@ -220,6 +307,7 @@ int main(void) { static void (*test_functions[])(void) = { test_istream_filter, + test_istream_filter_large_buffer, test_istream_edit, test_istream_end_body_with_lf, test_istream_strip_eoh,