changeset 5721:18d7a680ffae HEAD

Added more corruption detection code.
author Timo Sirainen <tss@iki.fi>
date Wed, 13 Jun 2007 21:35:14 +0300
parents 5f4a7e932c4f
children 9c53047d3b2c
files src/lib-index/mail-index-sync-update.c src/lib-index/mail-transaction-log-view.c
diffstat 2 files changed, 54 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-index/mail-index-sync-update.c	Wed Jun 13 21:34:16 2007 +0300
+++ b/src/lib-index/mail-index-sync-update.c	Wed Jun 13 21:35:14 2007 +0300
@@ -593,7 +593,7 @@
 			rec = CONST_PTR_OFFSET(data, i);
 			if (i + sizeof(*rec) + rec->name_size > hdr->size) {
 				mail_index_sync_set_corrupted(ctx,
-					"extension intro: name_size too large");
+					"ext intro: name_size too large");
 				ret = -1;
 				break;
 			}
@@ -610,6 +610,13 @@
 	}
 	case MAIL_TRANSACTION_EXT_RESET: {
 		const struct mail_transaction_ext_reset *rec = data;
+
+		if (hdr->size != sizeof(*rec)) {
+			mail_index_sync_set_corrupted(ctx,
+				"ext reset: invalid record size");
+			ret = -1;
+			break;
+		}
 		ret = mail_index_sync_ext_reset(ctx, rec);
 		break;
 	}
@@ -619,6 +626,15 @@
 
 		for (i = 0; i < hdr->size; ) {
 			rec = CONST_PTR_OFFSET(data, i);
+
+			if (i + sizeof(*rec) > hdr->size ||
+			    i + sizeof(*rec) + rec->size > hdr->size) {
+				mail_index_sync_set_corrupted(ctx,
+					"ext hdr update: invalid record size");
+				ret = -1;
+				break;
+			}
+
 			ret = mail_index_sync_ext_hdr_update(ctx, rec);
 			if (ret <= 0)
 				break;
@@ -630,9 +646,9 @@
 		break;
 	}
 	case MAIL_TRANSACTION_EXT_REC_UPDATE: {
-		const struct mail_transaction_ext_rec_update *rec, *end;
+		const struct mail_transaction_ext_rec_update *rec;
 		const struct mail_index_ext *ext;
-		unsigned int record_size;
+		unsigned int i, record_size;
 
 		if (ctx->cur_ext_id == (uint32_t)-1) {
 			mail_index_sync_set_corrupted(ctx,
@@ -651,14 +667,19 @@
 		/* the record is padded to 32bits in the transaction log */
 		record_size = (sizeof(*rec) + ext->record_size + 3) & ~3;
 
-		rec = data;
-		end = CONST_PTR_OFFSET(data, hdr->size);
-		while (rec < end) {
+		for (i = 0; i < hdr->size; i += record_size) {
+			rec = CONST_PTR_OFFSET(data, i);
+
+			if (i + record_size > hdr->size) {
+				mail_index_sync_set_corrupted(ctx,
+					"ext rec update: invalid record size");
+				ret = -1;
+				break;
+			}
+
 			ret = mail_index_sync_ext_rec_update(ctx, rec);
 			if (ret <= 0)
 				break;
-
-			rec = CONST_PTR_OFFSET(rec, record_size);
 		}
 		break;
 	}
--- a/src/lib-index/mail-transaction-log-view.c	Wed Jun 13 21:34:16 2007 +0300
+++ b/src/lib-index/mail-transaction-log-view.c	Wed Jun 13 21:35:14 2007 +0300
@@ -349,12 +349,25 @@
 		return FALSE;
 	}
 
+	if (rec_size == 0) {
+		mail_transaction_log_file_set_corrupted(file,
+			"Empty record contents (type=0x%x)", rec_type);
+		return FALSE;
+	}
+
 	/* records that are exported by syncing and view syncing will be
 	   checked here so that we don't have to implement the same validation
 	   multiple times. other records are checked internally by
 	   mail_index_sync_record(). */
 	t_push();
 	switch (rec_type) {
+	case MAIL_TRANSACTION_APPEND:
+		if ((rec_size % sizeof(struct mail_index_record)) != 0) {
+			mail_transaction_log_file_set_corrupted(file,
+				"Invalid append record size");
+			ret = FALSE;
+		}
+		break;
 	case MAIL_TRANSACTION_EXPUNGE:
 		uid_buf = buffer_create_const_data(pool_datastack_create(),
 						   data, rec_size);
@@ -375,8 +388,7 @@
 		if ((seqset_offset % 4) != 0)
 			seqset_offset += 4 - (seqset_offset % 4);
 
-		if (seqset_offset >= rec_size ||
-		    ((rec_size - seqset_offset) % (sizeof(uint32_t)*2)) != 0) {
+		if (seqset_offset > rec_size) {
 			mail_transaction_log_file_set_corrupted(file,
 				"Invalid keyword update record size");
 			ret = FALSE;
@@ -403,6 +415,17 @@
 		const struct seq_range *rec, *prev = NULL;
 		unsigned int i, count = array_count(&uids);
 
+		if ((uid_buf->used % uids.arr.element_size) != 0) {
+			mail_transaction_log_file_set_corrupted(file,
+				"Invalid record size (type=0x%x)", rec_type);
+			ret = FALSE;
+			count = 0;
+		} else if (count == 0) {
+			mail_transaction_log_file_set_corrupted(file,
+				"No UID ranges (type=0x%x)", rec_type);
+			ret = FALSE;
+		}
+
 		for (i = 0; i < count; i++, prev = rec) {
 			rec = array_idx(&uids, i);
 			if (rec->seq1 > rec->seq2 || rec->seq1 == 0) {