Commit 83c3d6880 for clamav.net
commit 83c3d68805bc397633582a64cd85d2008b85468f
Author: Val S. <valsnyde@cisco.com>
Date: Wed May 20 20:10:24 2026 -0400
Libclamav: harden XLM drawing group length checks (#1707)
The XLM drawing group parser grew a size_t length with BIFF record
sizes before reallocating and copying the new chunk. That pattern
looked like an integer overflow candidate, but the reported heap
overflow is not reachable in practice because every growth step is
immediately bounded by cli_max_realloc() and the BIFF record length
cap, so the accumulated length cannot approach SIZE_MAX before the
allocation limit stops processing.
Add explicit pre-addition overflow checks at the two drawing group
growth sites anyway. This keeps the existing control flow while
making the arithmetic safety guarantee explicit and easier to audit.
Credit: rinto
CLAM-2935
diff --git a/libclamav/xlm_extract.c b/libclamav/xlm_extract.c
index 71f660602..f424184a4 100644
--- a/libclamav/xlm_extract.c
+++ b/libclamav/xlm_extract.c
@@ -29,6 +29,7 @@
#include <fcntl.h>
#include <stdbool.h>
+#include <stdint.h>
#include "fmap.h"
#include "entconv.h"
@@ -4791,6 +4792,11 @@ cl_error_t cli_extract_xlm_macros_and_images(const char *dir, cli_ctx *ctx, char
} else {
/* already found the beginning of a drawing group, extract the remaining chunks */
+ if (drawinggroup_len > SIZE_MAX - biff_header.length) {
+ cli_dbgmsg("[cli_extract_xlm_macros_and_images] Drawing group length overflow\n");
+ status = CL_EFORMAT;
+ goto done;
+ }
drawinggroup_len += biff_header.length;
CLI_MAX_REALLOC_OR_GOTO_DONE(drawinggroup, drawinggroup_len, status = CL_EMEM);
memcpy(drawinggroup + (drawinggroup_len - biff_header.length), data, biff_header.length);
@@ -4802,6 +4808,11 @@ cl_error_t cli_extract_xlm_macros_and_images(const char *dir, cli_ctx *ctx, char
if ((OPC_MSODRAWINGGROUP == previous_biff8_opcode) &&
(NULL != drawinggroup)) {
/* already found the beginning of an image, extract the remaining chunks */
+ if (drawinggroup_len > SIZE_MAX - biff_header.length) {
+ cli_dbgmsg("[cli_extract_xlm_macros_and_images] Drawing group length overflow\n");
+ status = CL_EFORMAT;
+ goto done;
+ }
drawinggroup_len += biff_header.length;
CLI_MAX_REALLOC_OR_GOTO_DONE(drawinggroup, drawinggroup_len, status = CL_EMEM);
memcpy(drawinggroup + (drawinggroup_len - biff_header.length), data, biff_header.length);