mirror of
https://gitlab.com/buildroot.org/buildroot.git
synced 2026-09-10 00:04:06 -09:00
package/clamav: add patch for CVE-2026-20244
Signed-off-by: Titouan Christophe <titouan.christophe@mind.be> Signed-off-by: Raphaël Mélotte <raphael.melotte@mind.be>
This commit is contained in:
committed by
Raphaël Mélotte
parent
fa8b0440b9
commit
27bb657e6f
136
package/clamav/0008-fix-32-bit-dmg-mish-size-checks-65.patch
Normal file
136
package/clamav/0008-fix-32-bit-dmg-mish-size-checks-65.patch
Normal file
@@ -0,0 +1,136 @@
|
||||
From: "Val S." <valsnyde@cisco.com>
|
||||
Date: Mon, 22 Jun 2026 10:26:43 -0400
|
||||
Subject: Fix 32-bit DMG mish size checks (#65)
|
||||
|
||||
DMG mish stripe table validation used size_t arithmetic on 32-bit
|
||||
builds, allowing a crafted stripe count to wrap the required decoded
|
||||
byte count and let a short table reach the stripe walker.
|
||||
|
||||
Calculate the required table size in uint64_t before comparing it with
|
||||
the decoded buffer length. Keep related DMG range checks in
|
||||
subtraction form and compare stripe sort keys without truncating a
|
||||
64-bit subtraction.
|
||||
|
||||
Reported-by: Stanley John Tobias
|
||||
|
||||
CLAM-2989
|
||||
|
||||
---
|
||||
Upstream: https://github.com/Cisco-Talos/clamav/commit/2a03a9e14c300dcb534dcdc66c3f39462453c4c4
|
||||
CVE: CVE-2026-20244
|
||||
Signed-off-by: Titouan Christophe <titouan.christophe@mind.be>
|
||||
---
|
||||
libclamav/dmg.c | 57 ++++++++++++++++++++++++++++++++++++++++++-------
|
||||
1 file changed, 49 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/libclamav/dmg.c b/libclamav/dmg.c
|
||||
index e873f623d2..ab0c75abca 100644
|
||||
--- a/libclamav/dmg.c
|
||||
+++ b/libclamav/dmg.c
|
||||
@@ -135,7 +135,13 @@ int cli_scandmg(cli_ctx *ctx)
|
||||
cli_dbgmsg("cli_scandmg: The embedded XML is way larger than necessary, and probably corrupt or tampered with.\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
- if ((hdr.xmlOffset > (uint64_t)maplen) || (hdr.xmlLength > (uint64_t)maplen) || (hdr.xmlOffset + hdr.xmlLength) > (uint64_t)maplen) {
|
||||
+ /*
|
||||
+ * Keep the XML range check in subtraction form. Once offset and length are
|
||||
+ * each known to be no larger than the map, `offset <= maplen - length`
|
||||
+ * proves that the full range is contained without ever forming a possibly
|
||||
+ * overflowing offset + length sum.
|
||||
+ */
|
||||
+ if ((hdr.xmlOffset > (uint64_t)maplen) || (hdr.xmlLength > (uint64_t)maplen) || (hdr.xmlOffset > (uint64_t)maplen - hdr.xmlLength)) {
|
||||
cli_dbgmsg("cli_scandmg: XML out of range for this file\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
@@ -455,6 +461,7 @@ static int dmg_decode_mish(cli_ctx *ctx, unsigned int *mishblocknum, xmlChar *mi
|
||||
size_t base64_len, buff_size, decoded_len;
|
||||
uint8_t *decoded;
|
||||
const uint8_t mish_magic[4] = {0x6d, 0x69, 0x73, 0x68};
|
||||
+ uint64_t expected_len;
|
||||
|
||||
UNUSEDPARAM(ctx);
|
||||
|
||||
@@ -463,7 +470,13 @@ static int dmg_decode_mish(cli_ctx *ctx, unsigned int *mishblocknum, xmlChar *mi
|
||||
dmg_parsemsg("dmg_decode_mish: len of encoded block %u is %lu\n", *mishblocknum, base64_len);
|
||||
|
||||
/* speed vs memory, could walk the encoded data and skip whitespace in calculation */
|
||||
- buff_size = 3 * base64_len / 4 + 4;
|
||||
+ buff_size = (base64_len / 4) * 3 + 4;
|
||||
+ if (base64_len % 4) {
|
||||
+ if (buff_size > SIZE_MAX - 3) {
|
||||
+ return CL_EFORMAT;
|
||||
+ }
|
||||
+ buff_size += 3;
|
||||
+ }
|
||||
dmg_parsemsg("dmg_decode_mish: buffer for mish block %u is %lu\n", *mishblocknum, (unsigned long)buff_size);
|
||||
decoded = cli_max_malloc(buff_size);
|
||||
if (!decoded)
|
||||
@@ -502,13 +515,19 @@ static int dmg_decode_mish(cli_ctx *ctx, unsigned int *mishblocknum, xmlChar *mi
|
||||
mish_set->mish->startSector, mish_set->mish->sectorCount,
|
||||
mish_set->mish->dataOffset, mish_set->mish->blockDataCount);
|
||||
|
||||
- /* decoded length should be mish block + blockDataCount * 40 */
|
||||
- if (decoded_len < (sizeof(struct dmg_mish_block) + mish_set->mish->blockDataCount * sizeof(struct dmg_block_data))) {
|
||||
+ /*
|
||||
+ * The decoded mish block must contain the fixed header followed by one
|
||||
+ * stripe record per blockDataCount. Calculate this requirement in a wide
|
||||
+ * integer domain, then compare decoded_len against that exact byte count.
|
||||
+ */
|
||||
+ expected_len = (uint64_t)sizeof(struct dmg_mish_block) +
|
||||
+ (uint64_t)mish_set->mish->blockDataCount * (uint64_t)sizeof(struct dmg_block_data);
|
||||
+ if ((uint64_t)decoded_len < expected_len) {
|
||||
cli_dbgmsg("dmg_decode_mish: mish block %u too small\n", *mishblocknum);
|
||||
free(decoded);
|
||||
mish_set->mish = NULL;
|
||||
return CL_EFORMAT;
|
||||
- } else if (decoded_len > (sizeof(struct dmg_mish_block) + mish_set->mish->blockDataCount * sizeof(struct dmg_block_data))) {
|
||||
+ } else if ((uint64_t)decoded_len > expected_len) {
|
||||
cli_dbgmsg("dmg_decode_mish: mish block %u bigger than needed, continuing\n", *mishblocknum);
|
||||
}
|
||||
|
||||
@@ -516,11 +535,28 @@ static int dmg_decode_mish(cli_ctx *ctx, unsigned int *mishblocknum, xmlChar *mi
|
||||
return CL_CLEAN;
|
||||
}
|
||||
|
||||
-/* Comparator for stripe sorting */
|
||||
+/**
|
||||
+ * @brief Compare DMG stripe entries by start sector for sorting.
|
||||
+ *
|
||||
+ * The sort only needs the sign of the comparison result, so compare the
|
||||
+ * 64-bit sector numbers directly and return -1, 0, or 1. This preserves the
|
||||
+ * full ordering across the entire uint64_t range: no intermediate subtraction
|
||||
+ * is needed, so there is no unsigned wrap and no truncation to the comparator's
|
||||
+ * int return type.
|
||||
+ *
|
||||
+ * @param stripe_a First DMG stripe entry.
|
||||
+ * @param stripe_b Second DMG stripe entry.
|
||||
+ * @return Negative if `stripe_a` starts first, positive if `stripe_b` starts
|
||||
+ * first, or zero if both start at the same sector.
|
||||
+ */
|
||||
static int cmp_mish_stripes(const void *stripe_a, const void *stripe_b)
|
||||
{
|
||||
const struct dmg_block_data *a = stripe_a, *b = stripe_b;
|
||||
- return a->startSector - b->startSector;
|
||||
+ if (a->startSector < b->startSector)
|
||||
+ return -1;
|
||||
+ if (a->startSector > b->startSector)
|
||||
+ return 1;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/* Safely track sector sizes for output estimate */
|
||||
@@ -969,8 +1005,13 @@ static int dmg_handle_mish(cli_ctx *ctx, unsigned int mishblocknum, char *dir,
|
||||
" count " STDu64 " source " STDu64 " length " STDu64 "\n",
|
||||
mishblocknum, i, blocklist[i].type, blocklist[i].startSector, blocklist[i].sectorCount,
|
||||
blocklist[i].dataOffset, blocklist[i].dataLength);
|
||||
+ /*
|
||||
+ * Stripes must reference data before the embedded XML. Check
|
||||
+ * dataLength against the remaining space before xmlOffset so the range
|
||||
+ * proof does not depend on dataOffset + dataLength wrapping cleanly.
|
||||
+ */
|
||||
if ((blocklist[i].dataOffset > xmlOffset) ||
|
||||
- (blocklist[i].dataOffset + blocklist[i].dataLength > xmlOffset)) {
|
||||
+ (blocklist[i].dataLength > xmlOffset - blocklist[i].dataOffset)) {
|
||||
cli_dbgmsg("dmg_handle_mish: invalid stripe offset and/or length\n");
|
||||
return CL_EFORMAT;
|
||||
}
|
||||
@@ -45,6 +45,9 @@ CLAMAV_IGNORE_CVES += CVE-2026-20243
|
||||
# 0007-libclamav-fix-7z-substream-count-overflow-53.patch
|
||||
CLAMAV_IGNORE_CVES += CVE-2026-20215
|
||||
|
||||
# 0008-fix-32-bit-dmg-mish-size-checks-65.patch
|
||||
CLAMAV_IGNORE_CVES += CVE-2026-20244
|
||||
|
||||
CLAMAV_DEPENDENCIES = \
|
||||
bzip2 \
|
||||
host-pkgconf \
|
||||
|
||||
Reference in New Issue
Block a user