Mercurial > dovecot > original-hg > dovecot-2.1
changeset 14884:99b7be36631b
lib-index: Fixes to handling broken cache records that point outside file.
Especially try to avoid failing by trying to allocate gigabytes of memory.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 22 Jan 2013 16:53:52 +0200 |
parents | 2b76d357a56a |
children | 0b0399f1b6aa |
files | src/lib-index/mail-cache-lookup.c src/lib-index/mail-cache.c |
diffstat | 2 files changed, 23 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- 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; }
--- 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; }