]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-index: Fixes to handling broken cache records that point outside file.
authorTimo Sirainen <tss@iki.fi>
Tue, 22 Jan 2013 14:53:52 +0000 (16:53 +0200)
committerTimo Sirainen <tss@iki.fi>
Tue, 22 Jan 2013 14:53:52 +0000 (16:53 +0200)
Especially try to avoid failing by trying to allocate gigabytes of memory.

src/lib-index/mail-cache-lookup.c
src/lib-index/mail-cache.c

index 1a9f2b1c8ec1619cbf88f0c4091a2cdd47ecd5b5..4b5b75985068b072ad292f6f2314e41cdb5129cf 100644 (file)
@@ -15,6 +15,7 @@ int mail_cache_get_record(struct mail_cache *cache, uint32_t offset,
 {
        const struct mail_cache_record *rec;
        const void *data;
+       int ret;
 
        i_assert(offset != 0);
 
@@ -41,17 +42,15 @@ int mail_cache_get_record(struct mail_cache *cache, uint32_t offset,
        }
        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;
 }
index da40232c49834a44b5ab8a4d9957b838653e1fdb..49b36beddd0e22edeefbfcb354be6e5cde8375a6 100644 (file)
@@ -357,12 +357,28 @@ mail_cache_map_with_read(struct mail_cache *cache, size_t offset, size_t size,
 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 @@ static int mail_cache_try_open(struct mail_cache *cache)
 
        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;
 }