From: Timo Sirainen Date: Fri, 12 Mar 2021 00:26:32 +0000 (+0200) Subject: lib-index: Fix crash when cache record size is larger than file size X-Git-Tag: 2.3.15~182 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c6ad2aea84b6a920c1751f28ab9f26d60f7b8f29;p=thirdparty%2Fdovecot%2Fcore.git lib-index: Fix crash when cache record size is larger than file size This shouldn't happen unless the dovecot.index.cache file was corrupted. --- diff --git a/src/lib-index/mail-cache.c b/src/lib-index/mail-cache.c index 07e6238f12..af575e282d 100644 --- a/src/lib-index/mail-cache.c +++ b/src/lib-index/mail-cache.c @@ -405,6 +405,7 @@ mail_cache_map_full(struct mail_cache *cache, size_t offset, size_t size, struct stat st; const void *data; ssize_t ret; + size_t orig_size = size; *corrupted_r = FALSE; @@ -465,6 +466,10 @@ mail_cache_map_full(struct mail_cache *cache, size_t offset, size_t size, /* already mapped */ i_assert(cache->mmap_base != NULL); *data_r = CONST_PTR_OFFSET(cache->mmap_base, offset); + if (orig_size > cache->mmap_length - offset) { + /* requested offset/size points outside file */ + return 0; + } return 1; } @@ -500,7 +505,7 @@ mail_cache_map_full(struct mail_cache *cache, size_t offset, size_t size, } *data_r = offset > cache->mmap_length ? NULL : CONST_PTR_OFFSET(cache->mmap_base, offset); - return mail_cache_map_finish(cache, offset, size, + return mail_cache_map_finish(cache, offset, orig_size, cache->mmap_base, FALSE, corrupted_r); } diff --git a/src/lib-index/test-mail-cache.c b/src/lib-index/test-mail-cache.c index e4e5503f62..14b3fb6206 100644 --- a/src/lib-index/test-mail-cache.c +++ b/src/lib-index/test-mail-cache.c @@ -2,6 +2,7 @@ #include "lib.h" #include "str.h" +#include "write-full.h" #include "test-common.h" #include "test-mail-cache.h" @@ -712,6 +713,38 @@ static void test_mail_cache_in_memory(void) test_end(); } +static void test_mail_cache_size_corruption(void) +{ + struct test_mail_cache_ctx ctx; + struct mail_cache_view *cache_view; + struct mail_cache_lookup_iterate_ctx iter; + struct mail_cache_iterate_field field; + + test_begin("mail cache size corruption"); + + test_mail_cache_init(test_mail_index_init(), &ctx); + test_mail_cache_add_mail(&ctx, ctx.cache_field.idx, "12345678"); + cache_view = mail_cache_view_open(ctx.cache, ctx.view); + + /* lookup the added cache field */ + mail_cache_lookup_iter_init(cache_view, 1, &iter); + test_assert(iter.offset > 0); + + uoff_t size_offset = iter.offset + + offsetof(struct mail_cache_record, size); + uint32_t new_size = 0x10000000; + test_assert(pwrite_full(ctx.cache->fd, &new_size, sizeof(new_size), + size_offset) == 0); + test_expect_error_string("record points outside file"); + test_assert(mail_cache_lookup_iter_next(&iter, &field) == -1); + test_expect_no_more_errors(); + + mail_cache_view_close(&cache_view); + test_mail_cache_deinit(&ctx); + test_mail_index_delete(); + test_end(); +} + int main(void) { static void (*const test_functions[])(void) = { @@ -724,6 +757,7 @@ int main(void) test_mail_cache_lookup_decisions, test_mail_cache_lookup_decisions2, test_mail_cache_in_memory, + test_mail_cache_size_corruption, NULL }; return test_run(test_functions);