changeset 2631:519b768e5f2f HEAD

Make sure we don't get into infinite loops while reading cache.
author Timo Sirainen <tss@iki.fi>
date Thu, 16 Sep 2004 17:03:00 +0300
parents 1c8410c8f602
children ec5601f71ba0
files src/lib-index/mail-cache-lookup.c
diffstat 1 files changed, 45 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-index/mail-cache-lookup.c	Wed Sep 15 16:23:22 2004 +0300
+++ b/src/lib-index/mail-cache-lookup.c	Thu Sep 16 17:03:00 2004 +0300
@@ -37,7 +37,8 @@
 		cache_rec = CACHE_RECORD(cache, offset);
 	}
 
-	if (offset + cache_rec->size > cache->mmap_length) {
+	if (cache_rec->size > cache->mmap_length ||
+	    offset + cache_rec->size > cache->mmap_length) {
 		mail_cache_set_corrupted(cache, "record points outside file");
 		return NULL;
 	}
@@ -124,9 +125,9 @@
 		}
 
 		next_pos = pos + ((data_size + 3) & ~3);
-		if (next_pos > cache_rec->size) {
+		if (data_size > cache_rec->size || next_pos > cache_rec->size) {
 			mail_cache_set_corrupted(cache,
-				"Record continues outside it's allocated size");
+				"record continues outside it's allocated size");
 			return -1;
 		}
 
@@ -142,10 +143,26 @@
 	return 1;
 }
 
+static int buffer_find_offset(const buffer_t *buffer, uint32_t offset)
+{
+	const uint32_t *offsets;
+	size_t i, size;
+
+	offsets = buffer_get_data(buffer, &size);
+	size /= sizeof(*offsets);
+
+	for (i = 0; i < size; i++) {
+		if (offsets[i] == offset)
+			return TRUE;
+	}
+	return FALSE;
+}
+
 int mail_cache_foreach(struct mail_cache_view *view, uint32_t seq,
                        mail_cache_foreach_callback_t *callback, void *context)
 {
 	uint32_t offset;
+	buffer_t *offsets;
 	int ret;
 
         if (MAIL_CACHE_IS_UNUSABLE(view->cache))
@@ -161,23 +178,40 @@
 		view->cached_offset = offset;
 	}
 
-	while (offset != 0) {
+	t_push();
+	offsets = buffer_create_dynamic(pool_datastack_create(),
+					128, (size_t)-1);
+	ret = 1;
+	while (offset != 0 && ret > 0) {
+		if (buffer_find_offset(offsets, offset)) {
+			mail_cache_set_corrupted(view->cache,
+						 "record list is circular");
+			ret = -1;
+			break;
+		}
+		buffer_append(offsets, &offset, sizeof(offset));
 		ret = mail_cache_foreach_rec(view, &offset,
 					     callback, context);
-		if (ret <= 0)
-			return ret;
 	}
 
-	if (view->trans_seq1 <= seq && view->trans_seq2 >= seq &&
+	if (ret > 0 && view->trans_seq1 <= seq && view->trans_seq2 >= seq &&
 	    mail_cache_transaction_lookup(view->transaction, seq, &offset)) {
-		while (offset != 0) {
+		buffer_set_used_size(offsets, 0);
+		while (offset != 0 && ret > 0) {
+			if (buffer_find_offset(offsets, offset)) {
+				mail_cache_set_corrupted(view->cache,
+					"record list is circular");
+				ret = -1;
+				break;
+			}
+			buffer_append(offsets, &offset, sizeof(offset));
 			ret = mail_cache_foreach_rec(view, &offset,
 						     callback, context);
-			if (ret <= 0)
-				return ret;
 		}
 	}
-	return 1;
+	t_pop();
+
+	return ret;
 }
 
 static int