From: Vsevolod Stakhov Date: Wed, 8 Apr 2026 19:27:39 +0000 (+0100) Subject: [Fix] Fix infinite loop and OOB read in archive processing X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=HEAD;p=thirdparty%2Frspamd.git [Fix] Fix infinite loop and OOB read in archive processing - RAR v5 extra area parsing: fix wrong loop boundary (used advanced `p` instead of `ex + extra_sz`), wrong advancement (`cur_sz` alone didn't account for the size vint bytes), and wrong remain calculation for the second vint read. Add bounds validation for `cur_sz`. - 7zip codec ID: validate `p + sz <= end` before reading codec ID bytes to prevent out-of-bounds read with malformed archives. --- diff --git a/src/libmime/archives.c b/src/libmime/archives.c index 983857b503..d63f005256 100644 --- a/src/libmime/archives.c +++ b/src/libmime/archives.c @@ -783,20 +783,27 @@ rspamd_archive_process_rar(struct rspamd_task *task, p + fname_len + extra_sz < end) { /* Try to find encryption record in extra field */ const unsigned char *ex = p + fname_len; + const unsigned char *extra_end = ex + extra_sz; - while (ex < p + extra_sz) { + while (ex < extra_end) { const unsigned char *t; int64_t cur_sz = 0, sec_type = 0; + int vint_len; - r = rspamd_archive_rar_read_vint(ex, extra_sz, &cur_sz); - if (r == -1) { + vint_len = rspamd_archive_rar_read_vint(ex, extra_end - ex, &cur_sz); + if (vint_len == -1) { msg_debug_archive("rar archive is invalid (bad vint)"); return; } - t = ex + r; + if (cur_sz <= 0 || ex + vint_len + cur_sz > extra_end) { + msg_debug_archive("rar archive is invalid (bad extra record size)"); + break; + } + + t = ex + vint_len; - r = rspamd_archive_rar_read_vint(t, extra_sz - r, &sec_type); + r = rspamd_archive_rar_read_vint(t, cur_sz, &sec_type); if (r == -1) { msg_debug_archive("rar archive is invalid (bad vint)"); return; @@ -808,7 +815,7 @@ rspamd_archive_process_rar(struct rspamd_task *task, break; } - ex += cur_sz; + ex += vint_len + cur_sz; } } } @@ -1143,7 +1150,11 @@ rspamd_7zip_read_folder(struct rspamd_task *task, t = *p; SZ_SKIP_BYTES(1); sz = t & 0xF; - /* Codec ID */ + /* Codec ID - validate bounds before reading */ + if (end - p < (goffset) sz) { + msg_debug_archive("7zip archive is invalid (codec id truncated)"); + return NULL; + } tmp = 0; for (j = 0; j < sz; j++) { tmp <<= 8;