From: Timo Sirainen Date: Thu, 18 May 2017 19:18:15 +0000 (+0300) Subject: lib: Fix crash when seeking istream-concat to EOF and trying to read it X-Git-Tag: 2.3.0.rc1~1611 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=16b5dc27e7db42849510403d37e3629aba14de21;p=thirdparty%2Fdovecot%2Fcore.git lib: Fix crash when seeking istream-concat to EOF and trying to read it --- diff --git a/src/lib/istream-concat.c b/src/lib/istream-concat.c index 1131923855..b414f3a8f8 100644 --- a/src/lib/istream-concat.c +++ b/src/lib/istream-concat.c @@ -10,6 +10,7 @@ struct concat_istream { struct istream **input, *cur_input; uoff_t *input_size; + unsigned int input_count; unsigned int cur_idx, unknown_size_idx; size_t prev_stream_left, prev_stream_skip, prev_skip; @@ -29,7 +30,7 @@ static void i_stream_concat_close(struct iostream_private *stream, } if (close_parent) { - for (i = 0; cstream->input[i] != NULL; i++) + for (i = 0; i < cstream->input_count; i++) i_stream_close(cstream->input[i]); } } @@ -39,7 +40,7 @@ static void i_stream_concat_destroy(struct iostream_private *stream) struct concat_istream *cstream = (struct concat_istream *)stream; unsigned int i; - for (i = 0; cstream->input[i] != NULL; i++) + for (i = 0; i < cstream->input_count; i++) i_stream_unref(&cstream->input[i]); i_free(cstream->input); i_free(cstream->input_size); @@ -54,7 +55,7 @@ i_stream_concat_set_max_buffer_size(struct iostream_private *stream, unsigned int i; cstream->istream.max_buffer_size = max_size; - for (i = 0; cstream->input[i] != NULL; i++) + for (i = 0; i < cstream->input_count; i++) i_stream_set_max_buffer_size(cstream->input[i], max_size); } @@ -167,7 +168,7 @@ static ssize_t i_stream_concat_read(struct istream_private *stream) } /* we either read something or we're at EOF */ - last_stream = cstream->input[cstream->cur_idx+1] == NULL; + last_stream = cstream->cur_idx+1 >= cstream->input_count; if (ret == -1 && !last_stream) { if (stream->pos - stream->skip >= i_stream_get_max_buffer_size(&stream->istream)) return -2; @@ -228,7 +229,7 @@ find_v_offset(struct concat_istream *cstream, uoff_t *v_offset, const struct stat *st; unsigned int i; - for (i = 0; cstream->input[i] != NULL; i++) { + for (i = 0; i < cstream->input_count; i++) { if (*v_offset == 0) { /* seek to beginning of this stream */ break; @@ -277,8 +278,9 @@ static void i_stream_concat_seek(struct istream_private *stream, stream->istream.stream_errno = EINVAL; return; } - cstream->cur_input = cstream->input[cstream->cur_idx]; - if (cstream->cur_input == NULL) { + if (cstream->cur_idx < cstream->input_count) + cstream->cur_input = cstream->input[cstream->cur_idx]; + else { /* we allow seeking to EOF, but not past it. */ if (v_offset != 0) { io_stream_set_error(&cstream->istream.iostream, @@ -333,10 +335,10 @@ struct istream *i_stream_create_concat(struct istream *input[]) i_assert(count != 0); cstream = i_new(struct concat_istream, 1); - cstream->input = i_new(struct istream *, count + 1); - cstream->input_size = i_new(uoff_t, count + 1); + cstream->input_count = count; + cstream->input = p_memdup(default_pool, input, sizeof(*input) * count); + cstream->input_size = i_new(uoff_t, count); - memcpy(cstream->input, input, sizeof(*input) * count); cstream->cur_input = cstream->input[0]; i_stream_seek(cstream->cur_input, 0); diff --git a/src/lib/test-istream-concat.c b/src/lib/test-istream-concat.c index e44f80d8ab..7f5b271bde 100644 --- a/src/lib/test-istream-concat.c +++ b/src/lib/test-istream-concat.c @@ -117,6 +117,23 @@ static bool test_istream_concat_random(void) return !test_has_failed(); } +static void test_istream_concat_seek_end(void) +{ + test_begin("istream concat seek end"); + + struct istream *streams[] = { + test_istream_create("s1"), + test_istream_create("s2"), + NULL + }; + struct istream *input = i_stream_create_concat(streams); + i_stream_seek(input, 4); + test_assert(i_stream_read(input) == -1); + i_stream_unref(&input); + + test_end(); +} + static void test_istream_concat_early_end(void) { struct istream *input, *streams[2]; @@ -158,5 +175,6 @@ void test_istream_concat(void) } T_END; test_end(); + test_istream_concat_seek_end(); test_istream_concat_early_end(); }