]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: istream-seekable - Fix crash if writing to temp file fails
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Sat, 14 Sep 2019 20:53:35 +0000 (23:53 +0300)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Fri, 8 Oct 2021 07:26:42 +0000 (07:26 +0000)
src/lib/istream-seekable.c
src/lib/test-istream-seekable.c

index 00648f164a7b3d1a81e44062949790af8a4e47b8..ef7f2c09a1e87e42b83f926eec290ee83ad7ee52 100644 (file)
@@ -239,15 +239,22 @@ static int i_stream_seekable_write_failed(struct seekable_istream *sstream)
 {
        struct istream_private *stream = &sstream->istream;
        void *data;
+       size_t old_pos = stream->pos;
 
        i_assert(sstream->fd != -1);
+       i_assert(stream->skip == 0);
 
        stream->max_buffer_size = SIZE_MAX;
+       stream->pos = 0;
        data = i_stream_alloc(stream, sstream->write_peak);
+       stream->pos = old_pos;
 
        if (pread_full(sstream->fd, data, sstream->write_peak, 0) < 0) {
-               i_error("istream-seekable: read(%s) failed: %m", sstream->temp_path);
-               memarea_unref(&stream->memarea);
+               sstream->istream.istream.stream_errno = errno;
+               sstream->istream.istream.eof = TRUE;
+               io_stream_set_error(&sstream->istream.iostream,
+                                   "istream-seekable: read(%s) failed: %m",
+                                   sstream->temp_path);
                return -1;
        }
        i_stream_destroy(&sstream->fd_input);
index 7d05347597df56d6f5e4d0ef33991a385902063a..3373f52d6485073dc3f8038608aac2922a0c96de 100644 (file)
@@ -10,6 +10,8 @@
 #include <fcntl.h>
 #include <unistd.h>
 
+static int fd_callback_fd = -1;
+
 static int fd_callback(const char **path_r, void *context ATTR_UNUSED)
 {
        int fd;
@@ -20,6 +22,7 @@ static int fd_callback(const char **path_r, void *context ATTR_UNUSED)
                i_error("creat(%s) failed: %m", *path_r);
        else
                i_unlink(*path_r);
+       fd_callback_fd = fd;
        return fd;
 }
 
@@ -233,6 +236,37 @@ static void test_istream_seekable_get_size(void)
        test_end();
 }
 
+static void test_istream_seekable_failed_writes(void)
+{
+       struct istream *input, *streams[2];
+
+       test_begin("istream seekable failed write");
+       streams[0] = test_istream_create("stream");
+       test_istream_set_size(streams[0], 3);
+       test_istream_set_allow_eof(streams[0], FALSE);
+       streams[0]->seekable = FALSE;
+       streams[1] = NULL;
+
+       input = i_stream_create_seekable(streams, 2, fd_callback, NULL);
+       i_stream_set_name(input, "test seekable");
+       test_assert(i_stream_read(input) == 2);
+       i_stream_skip(input, 2);
+       test_assert(i_stream_read(input) == 1);
+       i_close_fd(&fd_callback_fd);
+       test_istream_set_size(streams[0], 5);
+
+       test_expect_error_string("istream-seekable: write_full(test-lib.tmp) failed: Bad file descriptor");
+       test_assert(i_stream_read(input) == -1);
+       test_expect_no_more_errors();
+
+       test_expect_error_string("file_istream.close((seekable temp-istream for: test seekable)) failed: Bad file descriptor");
+       i_stream_unref(&input);
+       test_expect_no_more_errors();
+
+       i_stream_unref(&streams[0]);
+       test_end();
+}
+
 void test_istream_seekable(void)
 {
        unsigned int i;
@@ -252,4 +286,5 @@ void test_istream_seekable(void)
        test_istream_seekable_early_end();
        test_istream_seekable_invalid_read();
        test_istream_seekable_get_size();
+       test_istream_seekable_failed_writes();
 }