It looks like the executable mode code was written when clamscan used to provide rich information about errors in its return codes:

  /**
   * clamscan return values (documented from man clamscan)
   *  0 : No virus found.
   *  1 : Virus(es) found.
   * 40: Unknown option passed.
   * 50: Database initialization error.
   * 52: Not supported file type.
   * 53: Can't open directory.
   * 54: Can't open file. (ofm)
   * 55: Error reading file. (ofm)
   * 56: Can't stat input file / directory.
   * 57: Can't get absolute path name of current working directory.
   * 58: I/O error, please check your file system.
   * 62: Can't initialize logger.
   * 63: Can't create temporary files/directories (check permissions).
   * 64: Can't write to temporary directory (please specify another one).
   * 70: Can't allocate memory (calloc).
   * 71: Can't allocate memory (malloc).
   */

...the switch/case based on the return code from the executable is based on the return code being something like the above.

However, it looks like clamscan changed the way it reports errors some time ago:

Looking at the source code for the clamav project itself, the detailed error messages were present in the man page in release 0.95 (from 2009):

https://github.com/vrtadmin/clamav-devel/blob/clamav-0.95/docs/man/clams...

...but they were replaced by the catch-all return code 2 in the next release 0.96 (from 2010):

https://github.com/vrtadmin/clamav-devel/blob/clamav-0.96/docs/man/clams...

The man page now just says this:

RETURN CODES
       0 : No virus found.
       1 : Virus(es) found.
       2 : Some error(s) occured.

Therefore when something goes wrong, the module typically records very little information e.g.

Clamscan reported: [2] - unknown error

The actual output from clamscan is discarded and only the return code is logged:

  // exec:
  // The lines of text output by clamscan are assigned as an array to $output
  // The actual result of clamscan is assigned to $result:
  // 0 = clean
  // 1 = infected
  // x = unchecked
  exec($cmd, $output, $result);

  // ...snip...

      watchdog('clamav', 'Uploaded file %filename could not be scanned.  Clamscan reported: [@error_code] - @error_description', array('%filename' => $filename, '@error_code' => $result, '@error_description' => $description), WATCHDOG_WARNING);

It would probably be useful if the full $output was logged when clamscan returns 2.

It may also be an idea to provide an option to do something like try the scan again with some extra options (--verbose --debug perhaps?) and log the output of that. Alternatively just being able to pass extra options to the executable all the time would be a useful addition.

One or more patches on the way.

Comments

mcdruid’s picture

Patch to add logging of the full output of the clamscan executable when it returns something other than 0 or 1.

Perhaps this could be configurable, but without it the logging is fairly useless (unknown error for everything).

adammalone’s picture

Assigned: Unassigned » adammalone
adammalone’s picture

Status: Active » Needs review
adammalone’s picture

Status: Needs review » Needs work

To ensure we keep the scope of this issue narrow, I've created #2474079: Provide optional parameters to the executable to allow us to continue the discussion about additional parameters there.

Do you have a reliable and repeatable method of triggering one of these errors. Looking at some of the error codes, we could potentially look at corrupting or removing read access from the clam db as one option?

I have executed a quick phpcs over the patch and it's mostly in order with a few nits that I've added in below.

  1. +++ b/clamav.inc
    @@ -204,16 +209,15 @@ function _clamav_scan_via_exec($filepath, $filename) {
    +          array('%filename' => $filename,
    

    The first index in a multi-value array must be on a new line

  2. +++ b/clamav.inc
    @@ -231,11 +235,30 @@ function _clamav_scan_via_exec($filepath, $filename) {
    +          array('%filename' => $filename,
    

    The first index in a multi-value array must be on a new line

  3. +++ b/clamav.inc
    @@ -231,11 +235,30 @@ function _clamav_scan_via_exec($filepath, $filename) {
    + * Sanitise output from clamscan
    

    Function comment short description must end with a full stop

  4. +++ b/clamav.inc
    @@ -231,11 +235,30 @@ function _clamav_scan_via_exec($filepath, $filename) {
    + * @param Array of lines of output from clamscan executable.
    

    Doc comment for var of does not match actual variable name $output at position 1

    Invalid @param data type, expected array but found Array

    Parameter comment must be on the next line at position 1

  5. +++ b/clamav.inc
    @@ -231,11 +235,30 @@ function _clamav_scan_via_exec($filepath, $filename) {
    + * @return String of sanitised output.
    

    Invalid @return data type, expected string but found String

mcdruid’s picture

New patch which hopefully fixes the phpcs issues in the changed code.

As for triggering an error as a test, yes preventing the executable from accessing the virus definition files is a good way of doing this.

For example:

# mv /var/lib/clamav /var/lib/clamav_
# clamscan testfile
LibClamAV Error: cl_load(): No such file or directory: /var/lib/clamav
ERROR: Can't get file status

----------- SCAN SUMMARY -----------
Known viruses: 0
Engine version: 0.98.1
Scanned directories: 0
Scanned files: 0
Infected files: 0
Data scanned: 0.00 MB
Data read: 0.00 MB (ratio 0.00:1)
Time: 0.003 sec (0 m 0 s)

Breaking clamscan like that should work as a test of the new code; without the patch the module will just record a mysterious "unknown error".

Without patch:

$ drush ev 'module_load_include("inc", "clamav"); var_dump(clamav_scan_file("/tmp/example.txt"));'
WD clamav: Uploaded file example.txt could not be scanned.  Clamscan reported: [2] - unknown error   [warning]
int(-1)

With patch:

$ drush ev 'module_load_include("inc", "clamav"); var_dump(clamav_scan_file("/tmp/example.txt"));'
WD clamav: Uploaded file example.txt could not be scanned. Clamscan reported: [2] - Some error(s) occured. Output:LibClamAV Error: cl_load(): No such file or directory: /var/lib/clamavERROR: Can't get file         [warning]
status----------- SCAN SUMMARY -----------Known viruses: 0Engine version: 0.98.1Scanned directories: 0Scanned files: 0Infected files: 0Data scanned: 0.00 MBData read: 0.00 MB (ratio 0.00:1)Time: 0.003 sec (0 m 0 s)
int(-1)

The latter is obviously a bit messy, but actually contains some potentially useful information.

mcdruid’s picture

Status: Needs work » Needs review

  • typhonius committed 814390a on 7.x-1.x authored by mcdruid
    Issue #2441575 by mcdruid: clanscan return codes no longer provide...
adammalone’s picture

Assigned: adammalone » Unassigned
Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.