Commit d36af7dfc for clamav.net
commit d36af7dfcd316385d0001ba6ab99aa0ea5927ede
Author: Valerie Snyder <valsnyde@cisco.com>
Date: Mon Apr 27 15:42:22 2026 -0400
HFS+: avoid inflateEnd on uninitialized HFS+ cmpf streams
A crafted HFS+ cmpf resource block can take the uncompressed
path without initializing a zlib stream, but the block
cleanup still calls inflateEnd(). On our repro attempts this
produced a parser-local Z_STREAM_ERROR rather than a process
crash.
Initialize the z_stream defensively, track whether
inflateInit2() succeeded, and only call inflateEnd() for
initialized streams.
Credit: Mizu
CLAM-2976
diff --git a/libclamav/hfsplus.c b/libclamav/hfsplus.c
index 57f147310..4a2bd7209 100644
--- a/libclamav/hfsplus.c
+++ b/libclamav/hfsplus.c
@@ -1277,9 +1277,10 @@ static cl_error_t hfsplus_walk_catalog(cli_ctx *ctx, hfsPlusVolumeHeader *volHea
off_t blockOffset = dataOffset + table[curBlock].offset;
size_t curOffset;
size_t readLen;
- z_stream stream;
+ z_stream stream = {0};
int streamBeginning = 1;
int streamCompressed = 0;
+ int streamInitialized = 0;
cli_dbgmsg("Handling block %u of %" PRIu32 " at offset %" PRIi64 " (size %u)\n", curBlock, numBlocks, (int64_t)blockOffset, table[curBlock].length);
@@ -1319,6 +1320,7 @@ static cl_error_t hfsplus_walk_catalog(cli_ctx *ctx, hfsPlusVolumeHeader *volHea
status = CL_EFORMAT;
goto done;
}
+ streamInitialized = 1;
}
}
@@ -1367,10 +1369,12 @@ static cl_error_t hfsplus_walk_catalog(cli_ctx *ctx, hfsPlusVolumeHeader *volHea
streamBeginning = 0;
}
- if (Z_OK != (z_ret = inflateEnd(&stream))) {
- cli_dbgmsg("hfsplus_walk_catalog: inflateEnd failed (%d)\n", z_ret);
- status = CL_EFORMAT;
- goto done;
+ if (streamInitialized) {
+ if (Z_OK != (z_ret = inflateEnd(&stream))) {
+ cli_dbgmsg("hfsplus_walk_catalog: inflateEnd failed (%d)\n", z_ret);
+ status = CL_EFORMAT;
+ goto done;
+ }
}
}