changeset 20696:e390f6e14850

lib-dcrypt: Avoid infinite loop if istream header is too large. We'll return an error now instead. We can't just return -2 here, because nothing was actually being returned to the caller. Attempting to do that would just trigger an assert: Panic: file istream.c: line 182 (i_stream_read): assertion failed: (_stream->skip != _stream->pos)
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Tue, 06 Sep 2016 02:56:39 +0300
parents 56d721e9ee64
children ba9f5ec216cd
files src/lib-dcrypt/istream-decrypt.c src/lib-dcrypt/test-stream.c
diffstat 2 files changed, 23 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-dcrypt/istream-decrypt.c	Thu Aug 25 12:27:51 2016 +0300
+++ b/src/lib-dcrypt/istream-decrypt.c	Tue Sep 06 02:56:39 2016 +0300
@@ -732,6 +732,12 @@
 
 			if (hret == 0) {
 				/* see if we can get more data */
+				if (ret == -2) {
+					stream->istream.stream_errno = EINVAL;
+					io_stream_set_error(&stream->iostream,
+						"Header too large (more than %"PRIuSIZE_T" bytes)", size);
+					return -1;
+				}
 				continue;
 			} else {
 				/* clean up buffer */
--- a/src/lib-dcrypt/test-stream.c	Thu Aug 25 12:27:51 2016 +0300
+++ b/src/lib-dcrypt/test-stream.c	Tue Sep 06 02:56:39 2016 +0300
@@ -497,6 +497,22 @@
 	test_end();
 }
 
+static void test_read_large_header(void)
+{
+	test_begin("test_read_large_header");
+
+	struct istream *is = test_istream_create_data(IOSTREAM_CRYPT_MAGIC, sizeof(IOSTREAM_CRYPT_MAGIC));
+	struct istream *ds = i_stream_create_decrypt_callback(is, no_op_cb, NULL);
+	test_istream_set_allow_eof(is, FALSE);
+	test_istream_set_max_buffer_size(is, sizeof(IOSTREAM_CRYPT_MAGIC));
+
+	test_assert(i_stream_read(ds) == -1);
+	i_stream_unref(&ds);
+	i_stream_unref(&is);
+
+	test_end();
+}
+
 static
 void test_free_keys() {
 	dcrypt_key_unref_private(&test_v1_kp.priv);
@@ -529,6 +545,7 @@
 		test_write_read_v2_empty,
 		test_free_keys,
 		test_read_0_to_400_byte_garbage,
+		test_read_large_header,
 		NULL
 	};