libclamav: cl_scan*_ex() functions provide verdict separate from errors

It is a shortcoming of existing scan APIs that it is not possible
to return an error without masking a verdict.
We presently work around this limitation by counting up detections at
the end and then overriding the error code with `CL_VIRUS`, if necessary.

The `cl_scanfile_ex()`, `cl_scandesc_ex()`, and `cl_scanmap_ex()` functions
should provide the scan verdict separately from the error code.

This introduces a new enum for recording and reporting a verdict:
`cl_verdict_t` with options:

- `CL_VERDICT_NOTHING_FOUND`
- `CL_VERDICT_TRUSTED`
- `CL_VERDICT_STRONG_INDICATOR`
- `CL_VERDICT_POTENTIALLY_UNWANTED`

Notably, the newer scan APIs may set the verdict to `CL_VERDICT_TRUSTED`
if there is a (hash-based) FP signature for a file, or in the cause where
Authenticode or similar certificate-based verification was performed, or
in the case where an application scan callback returned `CL_VERIFIED`.

CLAM-763
CLAM-865
This commit is contained in:
Valerie Snyder 2025-07-27 22:47:29 -04:00 committed by Val S.
parent 9d253673f4
commit 6d9b57eeeb
No known key found for this signature in database
GPG key ID: 3A7D293D8274CA1B
14 changed files with 572 additions and 272 deletions

View file

@ -176,7 +176,8 @@ class TC(testcase.TestCase):
'Data scanned: 948 B',
'Hash: 21495c3a579d537dc63b0df710f63e60a0bfbc74d1c2739a313dbd42dd31e1fa',
'File Type: CL_TYPE_ZIP',
'Return code: Virus(es) detected (1)',
'Verdict: Found Strong Indicator',
'Return Code: CL_SUCCESS (0)',
]
command = '{valgrind} {valgrind_args} {example} -d {database} -f {target} --script {script}'.format(
@ -187,7 +188,8 @@ class TC(testcase.TestCase):
)
output = self.execute_command(command)
assert output.ec == 1 # virus(es) found
# Check for success
assert output.ec == 0
# Custom logic to verify the output making sure that all expected results are found in the output in order.
#
@ -288,7 +290,7 @@ class TC(testcase.TestCase):
'Data scanned: 948 B',
'Hash: 21495c3a579d537dc63b0df710f63e60a0bfbc74d1c2739a313dbd42dd31e1fa',
'File Type: CL_TYPE_ZIP',
'Return code: No viruses detected (0)',
'Return Code: CL_SUCCESS (0)',
]
command = '{valgrind} {valgrind_args} {example} -d {database} -f {target} --script {script}'.format(
@ -299,7 +301,8 @@ class TC(testcase.TestCase):
)
output = self.execute_command(command)
assert output.ec == 0 # no virus(es) found
# Check for success
assert output.ec == 0
# Custom logic to verify the output making sure that all expected results are found in the output in order.
#
@ -336,7 +339,7 @@ class TC(testcase.TestCase):
'Data scanned: 0 B',
'Hash: 21495c3a579d537dc63b0df710f63e60a0bfbc74d1c2739a313dbd42dd31e1fa',
'File Type: CL_TYPE_ZIP',
'Return code: No viruses detected (0)',
'Return Code: CL_SUCCESS (0)',
]
command = '{valgrind} {valgrind_args} {example} -d {database} -f {target} --script {script}'.format(
@ -347,7 +350,8 @@ class TC(testcase.TestCase):
)
output = self.execute_command(command)
assert output.ec == 0 # virus(es) found
# Check for success
assert output.ec == 0
# Custom logic to verify the output making sure that all expected results are found in the output in order.
#
@ -398,7 +402,8 @@ class TC(testcase.TestCase):
'Data scanned: 0 B',
'Hash: 21495c3a579d537dc63b0df710f63e60a0bfbc74d1c2739a313dbd42dd31e1fa',
'File Type: CL_TYPE_ZIP',
'Return code: Virus(es) detected (1)',
'Verdict: Found Strong Indicator',
'Return Code: CL_SUCCESS (0)',
]
command = '{valgrind} {valgrind_args} {example} -d {database} -f {target} --script {script}'.format(
@ -409,7 +414,8 @@ class TC(testcase.TestCase):
)
output = self.execute_command(command)
assert output.ec == 1 # virus(es) found
# Check for success
assert output.ec == 0
# Custom logic to verify the output making sure that all expected results are found in the output in order.
#
@ -526,7 +532,7 @@ class TC(testcase.TestCase):
'Data scanned: 948 B',
'Hash: 21495c3a579d537dc63b0df710f63e60a0bfbc74d1c2739a313dbd42dd31e1fa',
'File Type: CL_TYPE_ZIP',
'Return code: No viruses detected (0)',
'Return Code: CL_SUCCESS (0)',
]
command = '{valgrind} {valgrind_args} {example} -d {database} -f {target} --script {script}'.format(
@ -537,7 +543,8 @@ class TC(testcase.TestCase):
)
output = self.execute_command(command)
assert output.ec == 0 # no virus(es) found
# Check for success
assert output.ec == 0
# Custom logic to verify the output making sure that all expected results are found in the output in order.
#