dovecot-2.2: lib-index: Fixes to handling broken cache records t...

dovecot at dovecot.org dovecot at dovecot.org
Sat Feb 16 18:57:45 EET 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/99b7be36631b
changeset: 15792:99b7be36631b
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Jan 22 16:53:52 2013 +0200
description:
lib-index: Fixes to handling broken cache records that point outside file.
Especially try to avoid failing by trying to allocate gigabytes of memory.

diffstat:

 src/lib-index/mail-cache-lookup.c |  13 ++++++-------
 src/lib-index/mail-cache.c        |  19 +++++++++++++++++--
 2 files changed, 23 insertions(+), 9 deletions(-)

diffs (76 lines):

diff -r 2b76d357a56a -r 99b7be36631b src/lib-index/mail-cache-lookup.c
--- a/src/lib-index/mail-cache-lookup.c	Tue Jan 22 16:31:17 2013 +0200
+++ b/src/lib-index/mail-cache-lookup.c	Tue Jan 22 16:53:52 2013 +0200
@@ -15,6 +15,7 @@
 {
 	const struct mail_cache_record *rec;
 	const void *data;
+	int ret;
 
 	i_assert(offset != 0);
 
@@ -41,17 +42,15 @@
 	}
 	if (rec->size > CACHE_PREFETCH) {
 		/* larger than we guessed. map the rest of the record. */
-		if (mail_cache_map(cache, offset, rec->size, &data) < 0)
+		if ((ret = mail_cache_map(cache, offset, rec->size, &data)) < 0)
 			return -1;
+		if (ret == 0) {
+			mail_cache_set_corrupted(cache, "record points outside file");
+			return -1;
+		}
 		rec = data;
 	}
 
-	if (rec->size > cache->mmap_length ||
-	    offset + rec->size > cache->mmap_length) {
-		mail_cache_set_corrupted(cache, "record points outside file");
-		return -1;
-	}
-
 	*rec_r = rec;
 	return 0;
 }
diff -r 2b76d357a56a -r 99b7be36631b src/lib-index/mail-cache.c
--- a/src/lib-index/mail-cache.c	Tue Jan 22 16:31:17 2013 +0200
+++ b/src/lib-index/mail-cache.c	Tue Jan 22 16:53:52 2013 +0200
@@ -357,12 +357,28 @@
 int mail_cache_map(struct mail_cache *cache, size_t offset, size_t size,
 		   const void **data_r)
 {
+	struct stat st;
 	const void *data;
 	ssize_t ret;
 
 	if (size == 0)
 		size = sizeof(struct mail_cache_header);
 
+	/* verify offset + size before trying to allocate a huge amount of
+	   memory due to them. note that we may be prefetching more than we
+	   actually need, so don't fail too early. */
+	if (size > cache->mmap_length || offset + size > cache->mmap_length) {
+		if (fstat(cache->fd, &st) < 0) {
+			i_error("fstat(%s) failed: %m", cache->filepath);
+			return -1;
+		}
+		if (offset >= (uoff_t)st.st_size) {
+			*data_r = NULL;
+			return 0;
+		}
+		size = st.st_size - offset;
+	}
+
 	cache->remap_counter++;
 	if (cache->map_with_read)
 		return mail_cache_map_with_read(cache, offset, size, data_r);
@@ -451,8 +467,7 @@
 
 	mail_cache_init_file_cache(cache);
 
-	if (mail_cache_map(cache, 0, sizeof(struct mail_cache_header),
-			   &data) < 0)
+	if (mail_cache_map(cache, 0, 0, &data) < 0)
 		return -1;
 	return 1;
 }


More information about the dovecot-cvs mailing list