mirror of
https://gitlab.com/buildroot.org/buildroot.git
synced 2026-10-01 06:21:56 -09:00
package/clamav: add patch for CVE-2026-20347
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
601b3b1ef0
commit
c4a2c7371c
@@ -0,0 +1,149 @@
|
|||||||
|
From: "Val S." <valsnyde@cisco.com>
|
||||||
|
Date: Tue, 28 Jul 2026 09:06:22 -0400
|
||||||
|
Subject: Libclamav: harden Mach-O section validation (#96)
|
||||||
|
|
||||||
|
Mach-O encodes a section's alignment as a base-2 exponent. A malformed
|
||||||
|
exponent can trigger undefined behavior in the signed shift used to
|
||||||
|
compute the alignment, and unchecked rounding can overflow the 32-bit
|
||||||
|
raw-size field.
|
||||||
|
|
||||||
|
Use a shared helper for 32- and 64-bit sections. Reject exponents above
|
||||||
|
31, perform the shift in uint64_t so exponent 31 remains valid, and
|
||||||
|
reject file-backed section sizes or rounded sizes that exceed
|
||||||
|
UINT32_MAX before narrowing them into cli_exe_section.
|
||||||
|
|
||||||
|
Review also identified valid virtual sections that must not be subject
|
||||||
|
to file-backed raw-size limits. Treat S_ZEROFILL, S_GB_ZEROFILL, and
|
||||||
|
S_THREAD_LOCAL_ZEROFILL as occupying no file bytes while continuing to
|
||||||
|
validate their alignment.
|
||||||
|
|
||||||
|
The original alignment issue was reported by Tristan (@TristanInSec).
|
||||||
|
|
||||||
|
CLAM-3002
|
||||||
|
|
||||||
|
---
|
||||||
|
Upstream: https://github.com/Cisco-Talos/clamav/commit/617a2f51b0eddf961766164cba726df0ba574df8
|
||||||
|
CVE: CVE-2026-20347
|
||||||
|
Signed-off-by: Titouan Christophe <titouan.christophe@mind.be>
|
||||||
|
---
|
||||||
|
libclamav/macho.c | 75 ++++++++++++++++++++++++++++++++++++++++++-----
|
||||||
|
1 file changed, 68 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/libclamav/macho.c b/libclamav/macho.c
|
||||||
|
index 25f70554fc..52f56ab43f 100644
|
||||||
|
--- a/libclamav/macho.c
|
||||||
|
+++ b/libclamav/macho.c
|
||||||
|
@@ -46,6 +46,11 @@
|
||||||
|
#define EC32(v, conv) (conv ? cbswap32(v) : v)
|
||||||
|
#define EC64(v, conv) (conv ? cbswap64(v) : v)
|
||||||
|
|
||||||
|
+#define MACHO_SECTION_TYPE_MASK 0x000000ff
|
||||||
|
+#define MACHO_S_ZEROFILL 0x1
|
||||||
|
+#define MACHO_S_GB_ZEROFILL 0xc
|
||||||
|
+#define MACHO_S_THREAD_LOCAL_ZEROFILL 0x12
|
||||||
|
+
|
||||||
|
struct macho_hdr {
|
||||||
|
uint32_t magic;
|
||||||
|
uint32_t cpu_type;
|
||||||
|
@@ -195,6 +200,52 @@ static uint32_t cli_rawaddr(uint32_t vaddr, struct cli_exe_section *sects, uint1
|
||||||
|
return vaddr - sects[i].rva + sects[i].raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/**
|
||||||
|
+ * Calculate the raw section size implied by a Mach-O alignment exponent.
|
||||||
|
+ *
|
||||||
|
+ * Mach-O section alignment is encoded as log2(bytes). Reject malformed
|
||||||
|
+ * exponents and rounded sizes that cannot fit in cli_exe_section.rsz.
|
||||||
|
+ * Zero-fill sections do not occupy file bytes, so they have no raw size.
|
||||||
|
+ */
|
||||||
|
+static bool cli_macho_section_raw_size(uint64_t virtual_size,
|
||||||
|
+ uint32_t align_exponent,
|
||||||
|
+ uint32_t section_flags,
|
||||||
|
+ uint32_t *raw_size)
|
||||||
|
+{
|
||||||
|
+ uint64_t alignment;
|
||||||
|
+ uint64_t remainder;
|
||||||
|
+ uint64_t padding;
|
||||||
|
+ uint64_t rounded_size;
|
||||||
|
+ uint32_t section_type = section_flags & MACHO_SECTION_TYPE_MASK;
|
||||||
|
+
|
||||||
|
+ if (align_exponent > 31) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (section_type == MACHO_S_ZEROFILL ||
|
||||||
|
+ section_type == MACHO_S_GB_ZEROFILL ||
|
||||||
|
+ section_type == MACHO_S_THREAD_LOCAL_ZEROFILL) {
|
||||||
|
+ *raw_size = 0;
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (virtual_size > UINT32_MAX) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ alignment = (uint64_t)1 << align_exponent;
|
||||||
|
+ remainder = virtual_size % alignment;
|
||||||
|
+ padding = (alignment - remainder) % alignment;
|
||||||
|
+ rounded_size = virtual_size + padding;
|
||||||
|
+
|
||||||
|
+ if (rounded_size > UINT32_MAX) {
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ *raw_size = (uint32_t)rounded_size;
|
||||||
|
+ return true;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
cl_error_t cli_scanmacho(cli_ctx *ctx, struct cli_exe_info *fileinfo)
|
||||||
|
{
|
||||||
|
struct macho_hdr hdr;
|
||||||
|
@@ -383,17 +434,26 @@ cl_error_t cli_scanmacho(cli_ctx *ctx, struct cli_exe_info *fileinfo)
|
||||||
|
|
||||||
|
for (j = 0; j < nsects; j++) {
|
||||||
|
if (m64) {
|
||||||
|
+ uint64_t section_size;
|
||||||
|
+
|
||||||
|
if (fmap_readn(map, §ion64, at, sizeof(section64)) != sizeof(section64)) {
|
||||||
|
cli_dbgmsg("cli_scanmacho: Can't read section\n");
|
||||||
|
free(sections);
|
||||||
|
RETURN_BROKEN;
|
||||||
|
}
|
||||||
|
at += sizeof(section64);
|
||||||
|
+ section_size = EC64(section64.size, conv);
|
||||||
|
sections[sect].rva = EC64(section64.addr, conv);
|
||||||
|
- sections[sect].vsz = EC64(section64.size, conv);
|
||||||
|
sections[sect].raw = EC32(section64.offset, conv);
|
||||||
|
- section64.align = 1 << EC32(section64.align, conv);
|
||||||
|
- sections[sect].rsz = sections[sect].vsz + (section64.align - (sections[sect].vsz % section64.align)) % section64.align; /* most likely we can assume it's the same as .vsz */
|
||||||
|
+ if (!cli_macho_section_raw_size(section_size,
|
||||||
|
+ EC32(section64.align, conv),
|
||||||
|
+ EC32(section64.flags, conv),
|
||||||
|
+ §ions[sect].rsz)) {
|
||||||
|
+ cli_dbgmsg("cli_scanmacho: Section alignment or size is malformed\n");
|
||||||
|
+ free(sections);
|
||||||
|
+ RETURN_BROKEN;
|
||||||
|
+ }
|
||||||
|
+ sections[sect].vsz = (uint32_t)section_size;
|
||||||
|
strncpy(name, section64.sectname, sizeof(name));
|
||||||
|
name[sizeof(name) - 1] = '\0';
|
||||||
|
} else {
|
||||||
|
@@ -406,13 +466,14 @@ cl_error_t cli_scanmacho(cli_ctx *ctx, struct cli_exe_info *fileinfo)
|
||||||
|
sections[sect].rva = EC32(section.addr, conv);
|
||||||
|
sections[sect].vsz = EC32(section.size, conv);
|
||||||
|
sections[sect].raw = EC32(section.offset, conv);
|
||||||
|
- if (EC32(section.align, conv) >= 32) {
|
||||||
|
- cli_dbgmsg("cli_scanmacho: Section aligned is malformed\n");
|
||||||
|
+ if (!cli_macho_section_raw_size(sections[sect].vsz,
|
||||||
|
+ EC32(section.align, conv),
|
||||||
|
+ EC32(section.flags, conv),
|
||||||
|
+ §ions[sect].rsz)) {
|
||||||
|
+ cli_dbgmsg("cli_scanmacho: Section alignment or size is malformed\n");
|
||||||
|
free(sections);
|
||||||
|
RETURN_BROKEN;
|
||||||
|
}
|
||||||
|
- section.align = 1 << EC32(section.align, conv);
|
||||||
|
- sections[sect].rsz = sections[sect].vsz + (section.align - (sections[sect].vsz % section.align)) % section.align;
|
||||||
|
strncpy(name, section.sectname, sizeof(name));
|
||||||
|
name[sizeof(name) - 1] = '\0';
|
||||||
|
}
|
||||||
@@ -57,6 +57,9 @@ CLAMAV_IGNORE_CVES += CVE-2026-20339
|
|||||||
# 0012-libclamav-guard-pdf-hex-string-newline-skip-98.patch
|
# 0012-libclamav-guard-pdf-hex-string-newline-skip-98.patch
|
||||||
CLAMAV_IGNORE_CVES += CVE-2026-20346
|
CLAMAV_IGNORE_CVES += CVE-2026-20346
|
||||||
|
|
||||||
|
# 0013-libclamav-harden-mach-o-section-validation-96.patch
|
||||||
|
CLAMAV_IGNORE_CVES += CVE-2026-20347
|
||||||
|
|
||||||
CLAMAV_DEPENDENCIES = \
|
CLAMAV_DEPENDENCIES = \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
host-pkgconf \
|
host-pkgconf \
|
||||||
|
|||||||
Reference in New Issue
Block a user