if (!mail_index_hdr_check_indexid(index, hdr))
return -1;
- rec_map->mmap_used_size = hdr->header_size +
- hdr->messages_count * hdr->record_size;
+ /* header_size was checked by mail_index_check_header_compat() */
+ i_assert(hdr->header_size <= rec_map->mmap_size);
+ rec_map->records_count = (rec_map->mmap_size - hdr->header_size) /
+ hdr->record_size;
- if (rec_map->mmap_used_size <= rec_map->mmap_size)
+ if (hdr->messages_count <= rec_map->records_count)
rec_map->records_count = hdr->messages_count;
else {
- rec_map->records_count =
- (rec_map->mmap_size - hdr->header_size) /
- hdr->record_size;
- rec_map->mmap_used_size = hdr->header_size +
- rec_map->records_count * hdr->record_size;
mail_index_set_error(index, "Corrupted index file %s: "
"messages_count too large (%u > %u)",
index->filepath, hdr->messages_count,
test_end();
}
+static void test_mail_index_corruption_message_count(void)
+{
+ struct mail_index *index;
+ struct mail_index_view *view;
+ struct mail_index_transaction *trans;
+
+ test_begin("mail index corruption: message count");
+ index = test_mail_index_init(TRUE);
+
+ /* make dovecot.index at least MAIL_INDEX_MMAP_MIN_SIZE bytes */
+ view = mail_index_view_open(index);
+ trans = mail_index_transaction_begin(view,
+ MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL);
+
+ uint32_t uid_validity = 1234;
+ mail_index_update_header(trans,
+ offsetof(struct mail_index_header, uid_validity),
+ &uid_validity, sizeof(uid_validity), TRUE);
+
+ uint32_t seq;
+ for (uint32_t uid = 1; uid <= 10000; uid++)
+ mail_index_append(trans, uid, &seq);
+ test_assert(mail_index_transaction_commit(&trans) == 0);
+ mail_index_view_close(&view);
+
+ /* write dovecot.index */
+ struct mail_index_sync_ctx *sync_ctx;
+ test_assert(mail_index_sync_begin(index, &sync_ctx, &view, &trans, 0) > 0);
+ mail_index_write(index, FALSE, "test");
+ test_assert(mail_index_sync_commit(&sync_ctx) == 0);
+
+ test_mail_index_close(&index);
+
+ /* write a corrupted messages_count */
+ const char *path = t_strconcat(test_mail_index_get_dir(),
+ "/test.dovecot.index", NULL);
+ int fd = open(path, O_RDWR);
+ if (fd == -1)
+ i_fatal("open(%s) failed: %m", path);
+
+ uint32_t messages_count = 0x80000000;
+ test_assert(pwrite(fd, &messages_count, sizeof(messages_count),
+ offsetof(struct mail_index_header, messages_count)) ==
+ sizeof(messages_count));
+ i_close_fd(&fd);
+
+ test_expect_error_string_n_times("test.dovecot.index", 3);
+ index = test_mail_index_open(FALSE);
+ test_expect_no_more_errors();
+ test_mail_index_deinit(&index);
+
+ test_end();
+}
+
int main(void)
{
static void (*const test_functions[])(void) = {
test_mail_index_rotate,
test_mail_index_new_extension,
+ test_mail_index_corruption_message_count,
NULL
};
test_dir_init("mail-index");