new file mode 100644
@@ -0,0 +1,90 @@
+From: "Val S." <valsnyde@cisco.com>
+Date: Tue, 16 Jun 2026 19:37:17 -0400
+Subject: Libclamav: fix Aspack-triggered rebuild PE overflow (#49)
+
+A malformed Aspack sample can force cli_rebuildpe_align() to
+sum rebuilt section sizes in a 32-bit accumulator until the total
+wraps. The rebuilder then allocates a destination buffer that is too
+small and later overflows it while copying section contents.
+
+Fix the allocation math by summing rebuilt section sizes in a 64-bit
+temporary and rejecting outputs whose packed section total or final
+allocation would exceed CLI_MAX_ALLOCATION. This is the correct fix
+because the later memcpy() assumes the destination size is valid; the
+real bug is the earlier integer overflow that under-allocates the
+buffer.
+
+Credit: Trail of Bits, in collaboration with Anthropic
+
+CLAM-2965
+
+---
+Upstream: https://github.com/Cisco-Talos/clamav/commit/5ad56a0ccf13f03e482a0d17fe2c6cb96d8af320
+CVE: CVE-2026-20213
+Signed-off-by: Titouan Christophe <titouan.christophe@mind.be>
+---
+ libclamav/rebuildpe.c | 34 ++++++++++++++++++++++++++--------
+ 1 file changed, 26 insertions(+), 8 deletions(-)
+
+diff --git a/libclamav/rebuildpe.c b/libclamav/rebuildpe.c
+index 23f290a990..5692301f15 100644
+--- a/libclamav/rebuildpe.c
++++ b/libclamav/rebuildpe.c
+@@ -50,6 +50,15 @@
+ #define PEALIGN(o, a) (((a)) ? (((o) / (a)) * (a)) : (o))
+ #define PESALIGN(o, a) (((a)) ? (((o) / (a) + ((o) % (a) != 0)) * (a)) : (o))
+
++static uint64_t pesalign_u64(uint64_t offset, uint32_t alignment)
++{
++ if (!alignment) {
++ return offset;
++ }
++
++ return ((offset / alignment) + ((offset % alignment) != 0)) * alignment;
++}
++
+ struct IMAGE_PE_HEADER {
+ uint32_t Signature;
+ /* FILE HEADER */
+@@ -127,6 +136,8 @@ int cli_rebuildpe(char *buffer, struct cli_exe_section *sections, int sects, uin
+ int cli_rebuildpe_align(char *buffer, struct cli_exe_section *sections, int sects, uint32_t base, uint32_t ep, uint32_t ResRva, uint32_t ResSize, int file, uint32_t align)
+ {
+ uint32_t datasize = 0, rawbase = PESALIGN(0x148 + 0x80 + 0x28 * sects, 0x200);
++ uint64_t packed_datasize = 0;
++ uint64_t total_allocation;
+ char *pefile = NULL, *curpe;
+ struct IMAGE_PE_HEADER *fakepe;
+ int i, gotghost = (sections[0].rva > PESALIGN(rawbase, 0x1000));
+@@ -136,17 +147,24 @@ int cli_rebuildpe_align(char *buffer, struct cli_exe_section *sections, int sect
+ if (sects + gotghost > 96)
+ return 0;
+
+- if (!align)
+- for (i = 0; i < sects; i++)
+- datasize += PESALIGN(sections[i].rsz, 0x200);
+- else
+- for (i = 0; i < sects; i++)
+- datasize += PESALIGN(PESALIGN(sections[i].rsz, align), 0x200);
++ if (!align) {
++ for (i = 0; i < sects; i++) {
++ packed_datasize += pesalign_u64(sections[i].rsz, 0x200);
++ }
++ } else {
++ for (i = 0; i < sects; i++) {
++ packed_datasize += pesalign_u64(pesalign_u64(sections[i].rsz, align), 0x200);
++ }
++ }
++
++ if (packed_datasize > CLI_MAX_ALLOCATION)
++ return 0;
+
+- if (datasize > CLI_MAX_ALLOCATION)
++ total_allocation = rawbase + packed_datasize;
++ if (total_allocation > CLI_MAX_ALLOCATION)
+ return 0;
+
+- pefile = (char *)cli_max_calloc(rawbase + datasize, 1);
++ pefile = (char *)cli_max_calloc((size_t)total_allocation, 1);
+ if (!pefile)
+ return 0;
+
@@ -30,6 +30,9 @@ CLAMAV_IGNORE_CVES += CVE-2026-20031
# 0002-libclamav-fix-pespin-cleanup-bitmap-tracking-47.patch
CLAMAV_IGNORE_CVES += CVE-2026-20217
+# 0003-libclamav-fix-aspack-triggered-rebuild-pe-overflow-49.patch
+CLAMAV_IGNORE_CVES += CVE-2026-20213
+
CLAMAV_DEPENDENCIES = \
bzip2 \
host-pkgconf \
Signed-off-by: Titouan Christophe <titouan.christophe@mind.be> --- ...ack-triggered-rebuild-pe-overflow-49.patch | 90 +++++++++++++++++++ package/clamav/clamav.mk | 3 + 2 files changed, 93 insertions(+) create mode 100644 package/clamav/0003-libclamav-fix-aspack-triggered-rebuild-pe-overflow-49.patch