From: Timo Sirainen Date: Thu, 12 Mar 2026 13:43:26 +0000 (+0200) Subject: lib-index: Fix potential crash when handling corrupted cache file header X-Git-Tag: 2.4.3~76 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=adee3a64f015fffcb63c1cfedc349b41dc6b77d7;p=thirdparty%2Fdovecot%2Fcore.git lib-index: Fix potential crash when handling corrupted cache file header Corrupted deleted_record_count could have caused "division by zero" crash. Fix both calculations to avoid integer overflows. --- diff --git a/src/lib-index/mail-cache.c b/src/lib-index/mail-cache.c index 3ae37d7986..e935ac6b4c 100644 --- a/src/lib-index/mail-cache.c +++ b/src/lib-index/mail-cache.c @@ -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(