Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions libclamav/matcher.c
Original file line number Diff line number Diff line change
Expand Up @@ -858,12 +858,32 @@ static cl_error_t lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_a
// Logical expression matched.
// Need to check the other conditions, like target description block, icon group, bytecode, etc.

if (ac_lsig->tdb.container && ac_lsig->tdb.container[0] != cli_recursion_stack_get_type(ctx, -2))
// If the lsig requires a specific container type, check if check that it matches
if (ac_lsig->tdb.container &&
ac_lsig->tdb.container[0] != cli_recursion_stack_get_type(ctx, -2)) {
// So far the match is good, but the container type doesn't match.
// Because this may need to match in a different scenario where the
// container does match, we do not want to cache this result.
ctx->fmap->dont_cache_flag = 1;

goto done;
if (ac_lsig->tdb.intermediates && !intermediates_eval(ctx, ac_lsig))
}

// If the lsig has intermediates, check if they match the current recursion stack
if (ac_lsig->tdb.intermediates &&
!intermediates_eval(ctx, ac_lsig)) {
// So far the match is good, but the intermediates type(s) do not match.
// Because this may need to match in a different scenario where the
// intermediates do match, we do not want to cache this result.
ctx->fmap->dont_cache_flag = 1;

goto done;
if (ac_lsig->tdb.filesize && (ac_lsig->tdb.filesize[0] > ctx->fmap->len || ac_lsig->tdb.filesize[1] < ctx->fmap->len))
}

// If the lsig has filesize requirements, check if they match
if (ac_lsig->tdb.filesize && (ac_lsig->tdb.filesize[0] > ctx->fmap->len || ac_lsig->tdb.filesize[1] < ctx->fmap->len)) {
goto done;
}

if (ac_lsig->tdb.ep || ac_lsig->tdb.nos) {
if (!target_info || target_info->status != 1)
Expand Down
83 changes: 83 additions & 0 deletions unit_tests/clamscan/container_sigs_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""

import sys
from zipfile import ZIP_DEFLATED, ZipFile

sys.path.append('../unit_tests')
import testcase
Expand Down Expand Up @@ -79,3 +80,85 @@ def test_intermediates(self):
'v1rusv1rus.7z.zip: 7z_zip_intermediates_bad.UNOFFICIAL FOUND',
]
self.verify_output(output.out, expected=expected_stdout, unexpected=unexpected_stdout)

def test_clamscan_container_cache(self):
self.step_name('Test that near-matches for container sigs are not cached')
# Files should not be cached as "clean" if the container sig is a near-match
# and only fails because the container requirement is not met.
# This is a regression test for a bug where a file was cached as "clean" and
# then later when scanned within a container it was not detected.

not_eicar_file = TC.path_tmp / 'not_eicar'
if not not_eicar_file.exists():
with open(not_eicar_file, 'wb') as f:
f.write(b"CLAMAV-TEST-STRING-NOT-EICAR")

not_eicar_zip = TC.path_tmp / 'not_eicar.zip'
if not not_eicar_zip.exists():
with ZipFile(str(not_eicar_zip), 'w', ZIP_DEFLATED) as zf:
zf.writestr('not-eicar.txt', b"CLAMAV-TEST-STRING-NOT-EICAR")

(TC.path_tmp / 'zip_container.ldb').write_text(
"LDB.Clamav-Unit-Test-Signature-Container;Engine:81-255,Container:CL_TYPE_ZIP,Target:0;0;0:434c414d41562d544553542d535452494e472d4e4f542d4549434152\n"
)

testfiles = '{} {}'.format(not_eicar_file, not_eicar_zip)
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles} --allmatch'.format(
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
path_db=TC.path_tmp / 'zip_container.ldb',
testfiles=testfiles,
)
output = self.execute_command(command)

assert output.ec == 1 # no virus, no failures

expected_stdout = [
'not_eicar: OK',
'not_eicar.zip: LDB.Clamav-Unit-Test-Signature-Container.UNOFFICIAL FOUND',
]
unexpected_stdout = [
'not_eicar: LDB.Clamav-Unit-Test-Signature-Container.UNOFFICIAL FOUND',
'not_eicar.zip: OK',
]
self.verify_output(output.out, expected=expected_stdout, unexpected=unexpected_stdout)

def test_intermediates_cache(self):
self.step_name('Test that near-matches for intermediates sigs are not cached')
# Files should not be cached as "clean" if the intermediates sig is a near-match
# and only fails because the intermediates requirement is not met.
# This is a regression test for a bug where a file was cached as "clean" and
# then later when scanned within a container it was not detected.

not_eicar_file = TC.path_tmp / 'not_eicar'
if not not_eicar_file.exists():
with open(not_eicar_file, 'wb') as f:
f.write(b"CLAMAV-TEST-STRING-NOT-EICAR")

not_eicar_zip = TC.path_tmp / 'not_eicar.zip'
if not not_eicar_zip.exists():
with ZipFile(str(not_eicar_zip), 'w', ZIP_DEFLATED) as zf:
zf.writestr('not-eicar.txt', b"CLAMAV-TEST-STRING-NOT-EICAR")

(TC.path_tmp / 'zip_intermediates.ldb').write_text(
"LDB.Clamav-Unit-Test-Signature-Intermediates;Engine:81-255,Intermediates:CL_TYPE_ZIP,Target:0;0;0:434c414d41562d544553542d535452494e472d4e4f542d4549434152\n"
)

testfiles = '{} {}'.format(not_eicar_file, not_eicar_zip)
command = '{valgrind} {valgrind_args} {clamscan} -d {path_db} {testfiles} --allmatch'.format(
valgrind=TC.valgrind, valgrind_args=TC.valgrind_args, clamscan=TC.clamscan,
path_db=TC.path_tmp / 'zip_intermediates.ldb',
testfiles=testfiles,
)
output = self.execute_command(command)

assert output.ec == 1 # no virus, no failures

expected_stdout = [
'not_eicar: OK',
'not_eicar.zip: LDB.Clamav-Unit-Test-Signature-Intermediates.UNOFFICIAL FOUND',
]
unexpected_stdout = [
'not_eicar: LDB.Clamav-Unit-Test-Signature-Intermediates.UNOFFICIAL FOUND',
'not_eicar.zip: OK',
]
self.verify_output(output.out, expected=expected_stdout, unexpected=unexpected_stdout)
Loading