If using the `max_resolution` setting on an image field in Drupal 8, that image processing appears to break ClamAV functionality. Our file field is configured with the following Maximum Image Resolution (see maxResolution.jpg):
"Images larger than 150x75 pixels will be resized"
With a maximum resolution set, the $file passed into DaemonTCPIP::scan() is actually a resized thumbnail of the original image. However, $file->getSize() reports the original image size not the resized one. (Calling fstat($file_hander) does show the correct number of bytes for the smaller, resized file and not the larger, original size of the original thumbnail).
This incorrect file size behavior leads to a timeout error when communicating with ClamAV. This module basically says "I'm about to send you (original file size) bytes" and then sends the smaller resized image. ClamAV never receives the full payload it's expecting and so it never returns a result - instead, the $response = trim(fgets($scanner_handler)); blocks until the connection times out.
Issue fork clamav-3058018
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 3058018-use-of-max-2.1.x
changes, plain diff MR !21
- 3058018-use-of-max
changes, plain diff MR !4
Comments
Comment #2
chrissnyderComment #3
chrissnyderComment #4
mcdruid commentedIs this a general problem with any image styles?
Is it only daemon mode which is affected?
Comment #5
bandana commentedSeeing the same issue the following changes in DaemonUnixSocket.php seem to work. Can't really say why though.. (have only tried daemon mode over unix socket. The executable mode works without any changes.)
changing line 39
from
fwrite($scanner_handler, pack("N", $bytes));to
fwrite($scanner_handler, pack("N", fstat($file_handler)['size']);OR
changing line 39
from
fwrite($scanner_handler, pack("N", $bytes));to
fwrite($scanner_handler, pack("J", $bytes));and line 43
from
fwrite($scanner_handler, pack("N", 0));to
fwrite($scanner_handler, pack("J", 0));Comment #6
mcdruid commentedComment #7
s3b0un3tI reproduce the same bug (in version 2.0) on my site with uploading an image with a higher resolution than validator constraint.
I tested the 2 propositions of @Bandana, only the first one works.
The ticket was created 2 years ago and the module 1releases no longer exist in version 1, I am switching the ticket to version 2 and submitting a patch.
It would be interesting to apply the same patch in DaemonUnixSocket.php.
Comment #8
s3b0un3tMisprint in my patch, sorry.
Comment #9
thirstysix commentedD9 with Version 2.0.0
J instead of N = unsigned long long (always 64 bit, big endian byte order).
Comment #10
thirstysix commentedStill has the same issue.
I have tried with the two above solutions..
It's throwing the same error.
Comment #11
thirstysix commentedComment #12
thirstysix commentedChanging the status.. to Review.
In my case, it's working fine with Daemon mode (over Unix socket) Socket path: /var/run/clamav/clamd.ctl
But, ClamAV can't get to listen on TCP 3310 (Debian 11). I think there is some issues with my Docker host. Cannot bind to port 3310
Finding the solution with TCP/IP...
Comment #13
sadikyalcin commentedAlso getting a similar error - may be related to file size. However, the file I'm uploading is an audio/mp3.
I can confirm ClamAV is installed and running properly. It occasionally throws such errors with certain files.
Using Daemon mode (over Unix socket) on Ubuntu 20.x and PHP 7.4
Comment #16
o'briatHi,
This MR works on my dev stack, thanks ! I use the official
clamav/clamavdocker image with Daemon mode (over TCP/IP) (port 3310).I use the MR patch : https://git.drupalcode.org/project/clamav/-/merge_requests/4.patch
I don't get any error at the moment.
For the record, here's how I try to debug problem:
The scans seemed to hit a timeout each time I send a image file that was too big ( > 100kB).
I try to analyse the
fgetscall to clamd and get a mysteriousCOMMAND READ TIMED OUThence leading me to thinks about a clamd incorrect setting...I now understand it was not linked to the file size but to its pixel size and image style.
Comment #17
o'briatSo the correct fix should be to send the original file to clamav, no ? It seems like a serious security issue
Comment #18
o'briatThis patch is not working, all files seems to be clean.
To reproduce :
Comment #19
o'briatAfter some debug, I can confirm that "max_resolution" resize the file before
hook_file_validate, but update the correct filesize in the $file object after that.So the quick fix I use is to update size before scanning the file in the clamav_file_validate
I'll will do a bit more testing before submitting a MR
Comment #20
o'briatComment #21
o'briatPlease review the core issue https://www.drupal.org/project/drupal/issues/3292350, if it's merged this issue could be closed (works as designed).
Comment #22
ifcarrionc_globant commentedHi,
I have the same issue. I tried to use the patch about the core issue, but it's throwing the same error. I have a patch with a new proposal, it could be better if we have bytes information of the temp file that it will be the file to scan. I hope it works.
Regards.
Comment #23
o'briat@ifcarrionc_globant. Strange, my core patch works on my website for some months now...
Your patch seems correct (do not trust the file object and reloading the current file size), but could you please test again mine just to check that I didn't miss something.
Thanks
Comment #24
klemendev commentedI can confirm applying patch from #3292350 fixes this issue too
Comment #25
simehttps://www.drupal.org/project/drupal/issues/3292350#comment-15324953 worked for me.
Comment #27
codebymikey commentedUpdated the MR incorporating @ifcarrionc_globant's latest fix, adding support for unix sockets as well.
Reading the filesize from the resource seems like the most stable way to address the issue.
Comment #28
manarth commentedThe switch between "N" (unsigned long (always 32 bit, big endian byte order) and "J" (unsigned long long (always 64 bit, big endian byte order) doesn't appear to fit with the ClamAV docs for INSTREAM.
https://linux.die.net/man/8/clamd
Could this be specific to a particular ClamAV version?
Comment #29
manarth commentedIt looks like the main branch of ClamAV is still using an unsigned 32bit value to calculate the chunk size – https://github.com/Cisco-Talos/clamav/blob/main/clamd/server-th.c#L830
I'd be extremely reluctant to change the pack definition from 32bit to 64bit without a thorough understanding of the root cause.
Comment #30
o'briatThe core patch https://www.drupal.org/project/drupal/issues/3292350 will be included in the next drupal release, it should fix this issue. Can some one check is there is still work on this issue? If so, maybe update the issue name and description or open a new issue?
Comment #31
codebymikey commentedI think you're right @manarth, I just attempted to incorporate the original approach suggested in the original @ThirstySix MR since I thought it was solving a different variation of the issue.
Using the 64bit "J" version lead to broken pipe issues:
And I've swiftly updated the MR as appropriate.
Comment #32
o'briathttps://www.drupal.org/project/drupal/issues/3292350 should fix the problem, is there other use case that prevent to close this issue?
Comment #33
klemendev commentedThis issue is back on ClamAV 2.1.0 that uses the new event instead of validation hook.
It seems resizing happens before that.
With https://www.drupal.org/project/drupal/issues/3292350 applied, uploading works if too big image is uploaded and resized, but in 2.1.0, this is broken again
Comment #34
klemendev commentedComment #35
klemendev commentedAny updates on this? The module does not seem to be usable if images are resized starting with version 2.1.0
Comment #36
o'briatAdd the relation to the new core issue https://www.drupal.org/project/drupal/issues/3522463 with the switch from
hook_file_validatetoFileValidationEvent.Comment #37
o'briatI think that until this core issue is fixed,
$file->getSize();should not be trusted and replaced byfilesize($file->getFileUri())on https://git.drupalcode.org/project/clamav/-/blob/2.1.x/src/Scanner/Daemo...I'll try to provide a patch
Comment #38
klemendev commentedThanks, I will try both this and the branch on the other issue and report back
Comment #39
o'briatIMHO ClamAv should assure its FileImageDimensionsConstraintValidator get the higher priority since it should check original file for virus before any other manipulations (check, resizes, ...).
This is specially true for virus that target image resizing lib such as gd or imagick
Comment #40
o'briatComment #41
klemendev commentedI agree it would make sense to run ClamAV first. During resizing, a carefully crafted payload could already execute malicious code technically.
Anyways, I can confirm this is fixed by changing how the file size is read or by patching core by https://www.drupal.org/project/drupal/issues/3522463.
Attaching a patch for this module.
Comment #42
o'briatCould someone review the last patch ?
I open a feature request for the priority point: https://www.drupal.org/project/clamav/issues/3540722
Comment #43
klemendev commentedI am not sure if it makes to apply this patch to the module, it is more of a workaround. I posted the patch for anyone needed a quick solution rather than as a suggestion to be merged to the module.
The right solution is https://www.drupal.org/project/drupal/issues/3522463
I also agree with #39 that the ClamAV event subscriber should run before the resizing happens. I suggest going back to needs work and changing the order of subscribers, but this is not something I know how to implement.
Comment #46
codebymikey commentedPushed a new PR targetting 2.1.x, there are a bunch of CS stuff that still needs addressing, but that's better left to be handled in a separate issue.
Also introduced a new
DaemonBaseclass since the IP and UNIX daemon scanners have duplicated code.This should make it easier to apply bugfixes for the daemons going forward.