]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-index: Fix potential crash when handling corrupted cache file header
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 12 Mar 2026 13:43:26 +0000 (15:43 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Fri, 13 Mar 2026 06:13:06 +0000 (06:13 +0000)
Corrupted deleted_record_count could have caused "division by zero" crash.
Fix both calculations to avoid integer overflows.

src/lib-index/mail-cache.c

index 3ae37d7986231bcdd9937ae9c7d0a13af176dc62..e935ac6b4cbc307b953e67c41f37e8b68a44ac8e 100644 (file)
@@ -246,7 +246,11 @@ static void mail_cache_update_need_purge(struct mail_cache *cache)
                records_count = hdr->record_count;
        }
 
-       cont_percentage = hdr->continued_record_count * 100 / records_count;
+       /* Check if purge_continued_percentage is reached. Note that 100% means
+          there's a continuation record for every message. But there can be
+          more than one continuation, so the percentage can grow over 100% */
+       cont_percentage = hdr->continued_record_count >= (UINT_MAX / 100) ?
+               UINT_MAX : (hdr->continued_record_count * 100 / records_count);
        if (cont_percentage >= set->purge_continued_percentage) {
                /* too many continued rows, purge */
                want_purge_reason = t_strdup_printf(
@@ -254,8 +258,13 @@ static void mail_cache_update_need_purge(struct mail_cache *cache)
                        hdr->continued_record_count, records_count);
        }
 
-       delete_percentage = hdr->deleted_record_count * 100 /
-               (records_count + hdr->deleted_record_count);
+       /* Check if purge_delete_percentage is reached. deleted_record_count is
+          the number of messages already expunged, so the total number of
+          records in cache file is deleted_record_count + records_count.
+          These calculations ignore continuation records. */
+       delete_percentage = hdr->deleted_record_count >= (UINT_MAX / 100) ?
+               UINT_MAX : (hdr->deleted_record_count * 100 /
+                           (records_count + hdr->deleted_record_count));
        if (delete_percentage >= set->purge_delete_percentage) {
                /* too many deleted records, purge */
                want_purge_reason = t_strdup_printf(