Mercurial > dovecot > core-2.2
changeset 22055:4ae88bb10a94
lib: Fix crash when seeking istream-concat to EOF and trying to read it
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Thu, 18 May 2017 22:18:15 +0300 |
parents | 412e15c438bc |
children | 81a4cf22408f |
files | src/lib/istream-concat.c src/lib/test-istream-concat.c |
diffstat | 2 files changed, 30 insertions(+), 10 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib/istream-concat.c Thu May 18 21:10:33 2017 +0300 +++ b/src/lib/istream-concat.c Thu May 18 22:18:15 2017 +0300 @@ -10,6 +10,7 @@ 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 @@ } 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 @@ 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 @@ 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 @@ } /* 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 @@ 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 @@ 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 @@ 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);
--- a/src/lib/test-istream-concat.c Thu May 18 21:10:33 2017 +0300 +++ b/src/lib/test-istream-concat.c Thu May 18 22:18:15 2017 +0300 @@ -117,6 +117,23 @@ 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 @@ } T_END; test_end(); + test_istream_concat_seek_end(); test_istream_concat_early_end(); }