The repeated-prefix selector ranked candidate windows by occurrences of
the original repeated byte. A signature such as ffffff000000 could
therefore replace an ff trie head with an all-zero trie head and recreate
the low-selectivity behavior this optimization is intended to avoid.
Require shifted windows to contain at least two distinct bytes. Add a
matcher regression that verifies the transition window is selected and
that the complete signature still matches.
Validation:
- make -j12 check_clamav
- CK_RUN_CASE=matchers ./build/unit_tests/check_clamav
- git clang-format --diff HEAD -- libclamav/matcher-ac.c
unit_tests/check_matchers.c
Some ClamAV hex patterns begin a sub-pattern with a long run of the same exact byte. When that byte is common in the scanned input, such as space bytes in document text or zero bytes in binary data, the AC trie head produces a large number of candidate branches and scan time can grow dramatically. A real main.ldb sample spent minutes in this path for Valyria signatures with repeated leading spaces.
Extend the existing poor-prefix shifting logic, which already handles wildcard and all-zero trie heads, to also detect repeated exact-byte prefixes. The matcher now selects a later exact static window with fewer occurrences of the repeated byte, stores the skipped bytes as the backwards-checked prefix, and keeps normal match semantics unchanged.
Benchmarks on c72ca7651909b7bd89bc05dbd18be88fe8a22c4cbff0b837d016ea1be9caf277:
- five-signature Valyria repro: 5.846s main to 2.134s branch
- full main.ldb repro: 262.176s main to 3.302s branch
Validation:
- make -j12
- ctest -V -R '^libclamav$'
- ctest -V -R '^clamscan$'
FreshClam's non-daemon update path passes OnOutdatedExecute to the database update helper when the outdated-version hook is enabled. The daemon update loop checked the OnOutdatedExecute option but accidentally passed the OnUpdateExecute command string instead.
This could cause daemon-mode outdated-version events to run the update hook, or to run no hook when only OnOutdatedExecute was configured. Pass the OnOutdatedExecute command string in the daemon path so both update modes use the same hook selection.
Credit: Nir Yehoshua, Cipher Security Labs
CLAM-3025
* Adapt Valgrind file descriptor checks
Valgrind 3.23 changed --track-fds=yes so descriptors left open at process exit count as real errors and trigger --error-exitcode. This caused the clamd and freshclam Valgrind tests to fail on intentional process-lifetime descriptors rather than memory defects.
Select the fd tracking mode from the installed Valgrind version. Preserve the original yes mode before 3.23, disable fd tracking on 3.23 through 3.25, and use the new bad mode on 3.26 and later so invalid descriptor use is still detected without reporting descriptors closed by process exit.
* Make clean scan assertions path-safe
The clamscan and clamd tests used the unanchored regular expression OK to decide whether a clean result appeared. Randomized temporary paths containing those letters caused virus-detection tests to fail even though the scanner output was correct.
Match the complete ': OK' result marker through the line ending and use the shared expression for every bare clean-result assertion. Also activate the LHA test's existing negative assertion so it checks the behavior it documents.
* Wait for clamd test readiness
The shared clamd startup helper returned immediately after creating the process. Tests then used inconsistent short ping windows, so slow startup under Valgrind could fail the first tests even while the daemon was still loading its databases.
Wait for clamdscan to receive PONG from the daemon using the selected configuration, allowing up to 60 attempts. Report early daemon exits and readiness timeouts at the startup boundary, and honor custom configurations in the non-Valgrind path.
Detached .sign files and cdiff/script commands are database-side inputs that should be trusted only after basic format validation. A malformed .sign header could reach a split/unwrap path and abort the process instead of returning a verification error. Several adjacent .sign certificate/signature metadata paths and cdiff command argument paths had similar panic-on-malformed-input assumptions.
Validate the .sign file header explicitly, report malformed digital-signature metadata and certificate common-name failures as verification errors, and reject truncated cdiff/script commands with MissingParameter errors. Add focused Rust unit tests for the malformed header and command cases.
These changes are hardening only. ClamAV database and update artifacts are expected to be provided by administrators or trusted update infrastructure, so we are not treating this as a vulnerability fix.
Credit: Owais Lone (TheSecGuy)
CLAM-2996
* Support safe quarantine removal on FreeBSD
The CLAM-2959 quarantine hardening requires an atomic way to prove that a
pathname still identifies the source retained during scanning before removing
it. FreeBSD lacks the no-replace rename primitive used by the generic POSIX
capture path on supported releases, causing --move and --remove to fail with
ENOTSUP.
Detect funlinkat() and use it with the retained scan descriptor after securely
traversing to the source parent. FreeBSD atomically checks that the basename
still names the retained descriptor before unlinking it. Normalize EDEADLK to
EAGAIN so replacement races follow the existing action-failure behavior.
Resolve descriptor paths through F_KINFO so FreeBSD symlink submissions retain
the real scanned source path. Other platform implementations and the
conservative unsupported-POSIX fallback remain unchanged.
Reported-by: Hiroki Imai from Ricerca Security, Inc.
CLAM-2959
* Preserve resolved quarantine source paths
FreeBSD F_KINFO resolves a vnode through the name cache and may return a
different hard-link name from the path used to open the scanned file. Using
that result for a path-based quarantine action could remove another link and
leave the submitted path in place.
Retain the already-resolved path supplied to path-based action sources and use
descriptor path resolution only when no authoritative path is available. Guard
F_KINFO use so FreeBSD releases without that command fall back cleanly instead
of failing to compile. Add hard-link regression coverage for move and remove
actions.
CLAM-2959
* Fix macOS quarantine test result matching
On macOS, /tmp is reported as its canonical /private/tmp path. The quarantine
directory replacement tests compared the complete clamscan success message
against paths created from the noncanonical temporary directory. A successful
copy or move could therefore be misclassified as an action failure.
Match the stable copy and move action markers instead. Existing filesystem
assertions continue to verify that the payload reached the pinned quarantine
directory and was not redirected through a replaced path.
CLAM-2959
fc_cleanup() frees g_signVerifier but does not set it to NULL.
When fc_initialize() fails, fc_cleanup() is called internally
and then again by freshclam at exit, causing a double free
that results in a segmentation fault.
Set g_signVerifier to NULL after freeing it, matching the
pattern used by other pointers in fc_cleanup().
Triggered when freshclam cannot write to the database directory.
Co-authored-by: caimengci <[email protected]>
A database archive whose MD5 starts with 00 cannot be verified by ClamAV 1.1 through 1.4. The existing immediate retry can rebuild the same archive when both attempts use the same timestamp.
Retry this specific compatibility failure up to ten times, waiting one second for the build timestamp to change between attempts. Preserve immediate failures for all other errors and keep the test limited to one sigtool invocation.
CLAM-3048
On macOS, /tmp is reported as its canonical /private/tmp path. The quarantine
directory replacement tests compared the complete clamscan success message
against paths created from the noncanonical temporary directory. A successful
copy or move could therefore be misclassified as an action failure.
Match the stable copy and move action markers instead. Existing filesystem
assertions continue to verify that the payload reached the pinned quarantine
directory and was not redirected through a replaced path.
CLAM-2959
FreeBSD F_KINFO resolves a vnode through the name cache and may return a
different hard-link name from the path used to open the scanned file. Using
that result for a path-based quarantine action could remove another link and
leave the submitted path in place.
Retain the already-resolved path supplied to path-based action sources and use
descriptor path resolution only when no authoritative path is available. Guard
F_KINFO use so FreeBSD releases without that command fall back cleanly instead
of failing to compile. Add hard-link regression coverage for move and remove
actions.
CLAM-2959
The CLAM-2959 quarantine hardening requires an atomic way to prove that a
pathname still identifies the source retained during scanning before removing
it. FreeBSD lacks the no-replace rename primitive used by the generic POSIX
capture path on supported releases, causing --move and --remove to fail with
ENOTSUP.
Detect funlinkat() and use it with the retained scan descriptor after securely
traversing to the source parent. FreeBSD atomically checks that the basename
still names the retained descriptor before unlinking it. Normalize EDEADLK to
EAGAIN so replacement races follow the existing action-failure behavior.
Resolve descriptor paths through F_KINFO so FreeBSD symlink submissions retain
the real scanned source path. Other platform implementations and the
conservative unsupported-POSIX fallback remain unchanged.
Reported-by: Hiroki Imai from Ricerca Security, Inc.
CLAM-2959
Jenkinsfile-defined job properties are unavailable when Jenkins queues the first build of a newly discovered multibranch job. Use the runtime throttle step around agent allocation so first builds also observe the global clamav category.
Refs: https://github.com/jenkinsci/throttle-concurrent-builds-plugin/issues/448
Portable UnRAR releases before 7.13 allow Windows NTFS alternate
data stream names to contain path separators. When ClamAV extracts
a crafted RAR archive for scanning, such a stream name can escape
the temporary scan directory and create or overwrite a file writable
by the scanner process.
Reject forward and backward slashes in both the RAR2/4 and RAR5
stream handlers, matching the upstream fix for CVE-2025-8088.
Reported by Yazdan Soltani as affecting ClamAV.
CLAM-3035
The ZIP local-header indexing helper can append to the same temporary
catalogue across multiple bounded scans. It tracked allocation capacity
with a local value derived from the current record count, so later calls
could lose the true allocated size and append past the catalogue.
Keep the catalogue block count as caller-owned state and grow the
catalogue before parsing into the next record slot.
Reported-by: Kevin Stubbings
CLAM-2995
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
The PDF hex-string reader skips newlines immediately after the opening
angle bracket. A malformed string can consume the remaining bounded input
before the parser searches for the closing bracket.
Return early when the bounded length is exhausted so the parser does not
pass an underflowed length to memchr().
Reported-by: Tristan (@TristanInSec)
CLAM-3002
The ZIP local-header indexing path merges records from the central
directory with records found by scanning local file headers. The merge used
shallow struct copies, so the combined catalogue and source catalogues could
share the same original_filename pointer.
If overlap detection failed after the merge copied entries, cleanup could
free the source catalogue names and then free the same pointers again from
the combined catalogue.
Add a small zip_record_move() helper and use it for the merge so ownership
of original_filename transfers to the combined catalogue before any later
cleanup.
CLAM-3003
The PESpin unpacker accumulated rebuilt section sizes in a signed int
before allocating the intermediate rebuilt image buffer. A crafted PE with
many sections could wrap the total to a small value and then copy full
section contents into that undersized allocation.
Track the rebuilt size in a 64-bit accumulator and reject additions that
would exceed CLI_MAX_ALLOCATION before allocating. Also avoid related
undefined behavior in the PESpin checksum and resource bitmap paths, and
share bitmap-based cleanup through one helper.
Reported-by: Feng Xue
CLAM-3008
The GPT partition parser converted the UTF-16 partition name with the outer
partition loop index instead of the inner name loop index. A GPT with enough
partition entries could read and write past the end of the stack-allocated
partition entry while scanning disk images.
Use the name loop index so each UTF-16 code unit is converted in bounds.
Credit: Atuin - Automated Vulnerability Discovery Engine, Tianchu Chen of
Tencent Xuanwu Lab.
CLAM-2999
Do not artificially shrink the receive buffer in the slow-client
test. Linux TCP flow control can otherwise delay the intentionally
large response long enough for mdprintf() to time out after only a
partial write.
Keeping the sender buffer limited and nonblocking preserves the
partial-write and slow-client coverage while allowing the reader to
drain the complete STATS response.
CLAM-3052
Remove obsolete bookkeeping for expected send failures in the FILDES stress test. The test has verified daemon responsiveness with a fresh PING connection since the flag's assertion was removed.
Protect thread-pool counters and queue traversal with the pool
mutex while STATS captures its response. Preserve the
pools_lock-to-pool_mutex lock order during worker initialization
and pool destruction.
Make worker retirement recheck queued work before decrementing
the live-thread count so dispatch cannot leave work stranded in
the retirement window. Retain engine references while collecting
memory-pool statistics instead of racing on the reference count.
Add regression coverage for queue churn and work dispatched while
a worker is retiring.
CLAM-3052
After a partial socket write, mdprintf advances its output buffer but continued passing the original formatted length to send(). A nonblocking client could therefore make send() read beyond the allocated buffer.
Pass only the remaining byte count. Make the clamd STATS slow-client test use a production-like nonblocking socket, prove the writer remains blocked while pool work proceeds, and validate the complete response.
CLAM-3052
The thread manager stores active task filenames supplied by scan
handlers. Some callers pass stack-backed strings, while the STATS
command reads task descriptors from another worker. A delayed STATS
response can therefore read caller storage after it has been reused
and disclose process address bytes.
Give each task descriptor an owned filename and protect its mutable
state with a per-task mutex. Build an immutable STATS response while
pool and task state is protected, then release all daemon bookkeeping
locks before writing to the client. Retain engine references needed by
the response so database reloads remain safe.
Add deterministic tests for caller-storage reuse and for a
non-reading STATS client that must not block pool registration.
CLAM-3052
Add a valid ptgStr regression case and use a signature matching its
disassembled output to verify detection through clamscan and scan-map.
Flush the extracted XLM stream before scanning so buffered formula output
is visible to the scanner.
CLAM-3011
The last user has been removed in commit fa15aa98c7 ("bb11594 - allow
for compilation against openssl 1.1.0"). This function is only exported
under CLAMAV_PRIVATE to be used within clamav, not by external users.
Removing the function will not cause an ABI break since it was not part
of the officially exported ABI. As a side effect it will compile against
OpenSSL 4.0 where the ASN1_TIME type has been made opaque.
Remove cl_ASN1_GetTimeT().
Signed-off-by: Sebastian Andrzej Siewior <[email protected]>
Validate XLM formula record sizes before parsing and honor the declared
token-stream length instead of parsing all trailing record data.
Correct the FORMULA record accounting and add bounds checks for token
operands, strings, attributes, function arguments, and cell references.
Malformed or truncated tokens now terminate parsing without consuming
data beyond the declared formula buffer.
Add unit and clamscan regression tests covering boundary-length records,
truncated tokens, malformed strings, and scan-map edge cases.
Reported by Alessandro Greco (GitHub user 'aleff-github').
CLAM-3011
Inflate XAR table-of-contents data incrementally and enforce scan and
allocation limits against the actual output instead of the declared
header length. Require the compressed stream to finish before parsing.
Add regression coverage for mismatched TOC lengths, oversized actual
output, and incomplete compressed streams.
CLAM-3010
Validate the declared decompressed TOC size against scan limits and
internal allocation bounds before allocating its buffer. Reject unsafe
lengths as malformed, including when configured scan limits are disabled.
Add regression coverage for scan limits, the allocation ceiling, and
integer overflow.
Credit: leduckhuong
CLAM-3010
VirusEvent executes the configured command through /bin/sh -c. It previously expanded %v by appending the detection name directly into that command string, matching the older behavior for virus-name substitution.
Loaded signature names are treated as trusted database content rather than attacker-controlled scanned-file input, so this change is intended as hardening. Still, replacing the shell interpolation avoids a footgun for deployments that load custom signatures and use VirusEvent.
Match the existing %f behavior by replacing %v with a disabled-feature message instead of the virus name. The virus name remains available to VirusEvent scripts through CLAM_VIRUSEVENT_VIRUSNAME.
Update the clamd configuration help, sample config, manpage source, and VirusEvent unit test to cover the environment-variable path.
Credit: Yazdan Soltani
Credit: Nir Yehoshua
CLAM-2992
Newer Rust builds may render the Cursor type in the PNG decoder stack as core::io::cursor::Cursor rather than std::io::cursor::Cursor. The existing fuzzy image hash suppression only matched the std::io spelling, so Debian 11 arm64 Valgrind jobs reported a known third-party PNG decoder warning instead of suppressing it.
Use a wildcard for the leading module path so the suppression covers both symbol spellings while still requiring the fuzzy_hash_calculate_image stack.
The freshclam tests start a local HTTP server in a child process and wait
for a readiness message before running freshclam. On newer macOS runners,
the standard HTTPServer startup can stall while resolving the bound loopback
address to a fully-qualified name, so the child process never reports
readiness and the tests time out before freshclam is exercised.
Use a test-only HTTPServer subclass that binds through
TCPServer.server_bind() and records the bound address directly. The mock
mirror does not need reverse DNS, and avoiding it keeps startup dependent
only on the local socket bind.
Compressed HFS+ resource parsing accumulated resource instance counts
with int arithmetic before seeking to the selected reference entry. A
crafted resource map could overflow the index or produce an unchecked
seek target.
Track the instance index and reference-entry offset in uint64_t,
reject offsets outside the resource fork, and widen catalog key
padding before it feeds record bounds checks.
CLAM-2989
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
Fix ALZ parsing and scanning behavior for malformed archives and scan-limit
edge cases.
The ALZ parser previously mixed archive traversal, metadata callbacks, and
extraction in ways that could stop scanning too early or account scan limits
inconsistently. A malformed member could prevent already extracted or later
members from being scanned, unsupported or malformed entries could bypass
metadata checks, and claimed ALZ sizes could steer MaxFiles, MaxFileSize,
and MaxScanSize handling away from the behavior used by the normal nested
scan path.
Refactor ALZ traversal so per-member errors, unsupported entries, directories,
and limit decisions are handled intentionally. Metadata scans now use 1-based
file positions, preserve hard metadata errors, stop promptly on fatal or
timeout conditions, and avoid passing unrepresentable ALZ sizes through the
size_t metadata interface. Extraction now preserves decoded output produced
before deflate or bzip2 tail errors, validates payload bounds before skipping
unsupported entries, applies file-count and size-budget decisions before doing
unnecessary decompression, and keeps parser-side budgeting aligned with small
buffers that ClamAV does not count as scanned files.
Add ALZ regression coverage for malformed headers, partial compressed output,
metadata matching, scan-limit accounting, unsupported entries, directory-heavy
archives, and small-member edge cases. Also update supporting Rust FFI
exports needed by shared-library builds.
Credit: Yazdan Soltani
CLAM-2988
Quarantine actions previously validated a source path or destination
directory, scanned through that path, and then reopened pathnames later to
copy, move, or remove infected files. A local attacker who could replace a
source path, symlink, or quarantine directory between those steps could cause
ClamAV to copy, move, or delete an object different from the one that produced
the detection, or redirect the quarantined output.
This change makes quarantine actions operate on objects that were opened and
validated before the scan. The shared action_source_t records the user-facing
display path, the action path, the scan descriptor, stable file metadata, and
Windows handle state. clamscan, clamdscan, clamonacc, clamd, and scanmem pass
that source object from scan setup through the quarantine callback so action
code does not have to trust mutable pathnames after a detection.
On POSIX, destination setup opens and retains the validated quarantine
directory, then creates the per-run lock file and destination files relative to
that directory. Source opens use no-follow traversal for resolved action paths.
Copy reads from the opened scan descriptor. Move is copy plus a verified
unlink, and remove captures the final path component into a private directory
before deleting it. Device and inode metadata from the scanned file are checked
before unlinking. Copy and move revalidate that the configured quarantine path
still names the retained destination directory before reporting success.
Mismatched private captures are restored only when the platform supports
no-replace rename. That conservative behavior avoids hiding a replacement
object when a writable directory races the action path.
On Windows, destination setup retains an opened directory handle and actions
operate through normalized long-path names or retained handles. Move and remove
try to keep DELETE access on the scanned source handle; if that access is not
available, scanning still proceeds and the action reopens the path at action
time, validating the reopened object against the scanned file before deleting.
Windows copy preserves alternate data streams, basic file times and attributes,
and security metadata where available.
File metadata preservation now follows the platform capabilities. Linux copies
mode, ownership when permitted, timestamps, and extended attributes from the
scanned source. macOS uses fcopyfile() with COPYFILE_ALL. Windows copies named
streams, basic metadata, and security descriptors. Metadata failures that are
not required for a safe detection do not suppress the detection.
The client paths now keep reporting stable for users while separating display
paths from action paths. clamd and clamdscan still print the submitted path,
but clamd resolves callback paths before opening them so a symlinked parent
component cannot change the object scanned after cli_ftw() checks. VirusEvent
and quarantine actions receive the resolved scan target. clamdscan and
clamonacc use client-opened FILDES or INSTREAM scans when quarantine actions
are enabled so clamd does not need to reopen mutable source names. For local
quarantine-action directory walks, clamdscan applies clamd CrossFilesystems=no
policy to avoid crossing mount points that daemon-side scans would skip.
clamdscan --memory applies clamd ExcludePath to each module before direct or
packed-module scans. When quarantine actions are enabled, scanmem resolves
memory module action sources with the same sharing policy used by action
source opens, filters both the submitted module path and resolved path, and
uses the resolved path for direct module scanning and quarantine action setup.
scanmem avoids caching infected module results while actions are enabled so
move or remove can be retried after unload or action failure.
The regression coverage exercises destination replacement, source symlink and
replacement races, relative source paths, clamdscan scan modes, quarantine lock
creation through the validated directory, Windows move and delete behavior, and
metadata preservation paths.
Reported-by: Hiroki Imai from Ricerca Security, Inc.
CLAM-2959
A multi-chunk InstallShield payload could bypass the intended file
size limits because the extractor checked zlib's per-stream total_out
instead of the cumulative bytes written across all chunks. The
extraction path also collapsed timeout and maxfiles limit hits to
CL_BREAK, and the header parser trusted declared sizes that can be
forged to skip scanning a small payload entirely.
Fix this by enforcing maxfilesize and maxscansize against the
cumulative output written while inflating and by propagating hard-stop
limit errors out of is_extract_cab(). Keep the parser preflight, but
only use cli_checklimits() for non-size checks before extraction so
size decisions are based on actual inflated output instead of
attacker-controlled metadata.
Thanks to Mizu for reporting this issue.
CLAM-2956
A malformed 7z archive can force SzReadSubStreamsInfo() to sum
folder substream counts in a UInt32 accumulator until the total
wraps. The parser then allocates arrays using the wrapped smaller
count and later writes past the end of those buffers while filling
substream size metadata.
Fix the parser by rejecting archives whose total unpack-stream
count would overflow UInt32 before the count is accumulated. This
preserves the existing parsing flow while preventing the
under-allocation that leads to the heap overflow.
Credit: Trail of Bits, in collaboration with Anthropic
CLAM-2967
A malformed FSG sample can leave the recovered section count at
zero in the v1.31 unpacker path. The code then allocates space for
one section entry but initializes recovered RVAs with a loop bound
that underflows, causing an out-of-bounds write past the end of the
sections array.
Fix the loop bound by iterating while t is strictly less than the
section count. This preserves the intended behavior for valid
nonzero counts and correctly performs zero iterations when no
original sections were recovered.
Credit: Trail of Bits, in collaboration with Anthropic
CLAM-2966
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
The PESpin unpacker mixes heap-owned section buffers with pointers
back into the original PE image. Its final cleanup loop is supposed
to walk a copy of the ownership bitmap and free only the entries
that were allocated by the unpacker.
That loop checked bitmap but shifted bitman instead. When the low
bit was set, bitmap never changed and the loop could free every
entry in sects, including pointers into the input buffer. A crafted
sample can drive this path after an allocation failure and crash in
free() with an invalid pointer.
Shift bitmap in the cleanup loop so the free decision advances one
section at a time using the same working bitmap that the condition
already tests. This matches the existing intent of saving bitmap as
a disposable free bitmap copy and avoids touching the original
bitman state.
Credit: Atuin - Automated Vulnerability Discovery Engine, Tianchu Chen of Tencent Xuanwu Lab.
CLAM-2961