Tuesday, March 29, 2016

Configuring On-Access Scanning in ClamAV

A Brief History

With the release of ClamAV 0.99, users saw a slew of new features aimed at enhancing ClamAV’s core functionalities. Included in these features were the improvements to ClamAV’s long-neglected on-access scanning capabilities. Ages ago, ClamAV supported on-access scanning via the now-defunct Dazuko kernel module. When development on Dazuko ended in 2011, the ClamAV team began searching for a suitable replacement. The team soon landed on the recently stable fanotify API that first shipped with the 2.6.37 Linux kernel. By November of 2011 a barebones fanotify-based on-access scanner had been completed, but it wouldn’t see public release until ClamAV 0.98.

Fast forward to ClamAV version 0.99four years after the creation of that first prototypeand users found themselves presented with a completely reworked on-access scanning system that now leveraged not only fanotify, but inotify as well. While ClamAV’s documentation had been updated to help navigate users through the transition, a number of people reported problems they were having with ClamAV’s on-access scanner. Almost invariably, these issues came down to either improper configuration or system-level limitations. This guide seeks to provide users interested in ClamAV’s on-access scanning with a definitive resource on the topicstraight from the horse’s mouth, so to speak.

System Requirements

On-access scanning, requires a system running a Linux kernel (version >= 3.8) with fanotify compiled in. Check the kernel configuration for fanotify’s presence by running:
$ cat /boot/config-<kernel_version> | grep FANOTIFY

Results if fanotify is available:

Results if fanotify can prevent malicious file access attempts:

If this is seen:

Then on-access scanning will be constrained to notify-only mode and will be unable to prevent access to malicious files, since fanotify lacks the ability to block events on the system.

To use the dynamic directory determination (DDD) system introduced in 0.99, ensure inotify is configured with enough watchpoints. By default, inotify can watch for changes in 8192 directories at any one time. If more directories than that need protection, run the following commandreplacing <NUM> with the maximum number of directories to be watched:
$ echo <NUM> | sudo tee -a /proc/sys/fs/inotify/max_user_watches

Overview of Configuration Options

The clamd.conf configuration file contains a number of options which modify the behaviour of ClamAV’s on-access scanner. Each configuration option is listed below alongside its intended purpose and any caveats of which users should remain cognizant.

Purpose: Enables on-access scanning under clamd if set to “yes”. If set to ”no”, all other on-access configurations options will be ignored.

Caveats: clamd must be run as root.

Purpose: Watches the entirety of one or more specified mount points and notifies the user of any malicious events caught by fanotify.

Caveats: Users must specify a valid mount point. If this option is enabled, clamd will disable fanotify prevention to keep users from accidentally locking up their system. Enabling this option will also disable the DDD system and all configuration options which rely on that system.

Purpose: Allows the user to stop clamd from scanning files larger than the specified size. If set to “0”, clamd will scan all files regardless of size.

Caveats: On some kernel versions and architectures, fanotify is known to fail when blocking access to files larger than 4GB. ClamAV will alert users if this problem occurs.

Purpose: The files within the any specified path(s) will be monitored for access attempts. If the DDD system is enabled, clamd will watch this path recursively, i.e., the specified directory and all subdirectories will be monitored. If the DDD system is disabled, only the topmost directory will be watched and all subdirectories will be ignored.

Caveats: This option will be ignored if OnAccessMountPath is enabled. As an additional precaution, if DDD is enabled, clamd will prevent users from specifying “/” as an include path.

Purpose: Recursively removes the given directory from the set of directories monitored by clamd.

Caveats: If the DDD system is disabled, this option is ignored.

Purpose: When fanotify catches an event, clamd will check given UIDs against the captured pid. If a match is found, the event is ignored and no scanning is performed.

Caveats: There aren't any known caveats with this option.

Purpose: This option allows users to turn off the DDD system if they prefer the legacy on-access scanning behaviour that was available in 0.98. If DDD is disabled OnAccessIncludePath will not recursively watch paths, making OnAccessExcludePath a redundant option.

Caveats: If OnAccessMountPath is enabled, clamd will act as though DDD is disabled.

Purpose: Flags fanotify to block any triggered events on monitored files, which allows ClamAV to scan affected files to determine if those events should be allowed to proceed.

Caveats: The kernel must be compiled with “CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y” for this option to function. As a precaution, if OnAccessMountPath is enabled, clamd automatically disables this option to stop the user from accidentally locking up their system. Only access and open events can be blocked by fanotify.

Purpose: Provides DDD users with inotify event coverage, which allows for scans on newly created, moved, or renamed files.

Caveats: Since this option relies on the inotify framework maintained by the DDD system, it is ignored if OnAccessDisableDDD is “yes”.

Configuration Examples

This guide ends with a few simple clamd.conf configuration examples which will satisfy a number of general use cases. Though there are only four, these examples can readily be expanded upon or adapted to fit more targeted use cases.

Watch entire filesystem
ScanOnAccess yes
OnAccessMountPath /
OnAccessExcludeUID 0

Details: This will set fanotify to watch the entire filesystem in real-time and trigger ClamAV to run scans on any files opened, accessed, or closed except by the root user. While clamd will report any viruses found during this scanning, fanotify will not perform any blocking or prevention.

Watching select users’ home directories
ScanOnAccess yes
OnAccessIncludePath /home
OnAccessExcludePath /home/user2
OnAccessExcludePath /home/user4
OnAccessExtraScanning yes

Details: Like the previous example, fanotify is not flagged to prevent events which occur on malicious files. However, further scanning coverage is provided thanks to OnAccessExtraScanning leveraging the inotify events caught by the DDD system.

Protecting a directory recursively
ScanOnAccess yes
OnAccessIncludePath /home/user/Downloads
OnAccessPrevention yes
OnAccessExtraScanning yes

Details: Here fanotify will block any triggered events, allowing only clean files to be opened, or otherwise accessed. This configuration will also immediately alert the user if a malicious file is inadvertently downloaded.

Protecting multiple dirs non-recursively
ScanOnAccess yes
OnAccessIncludePath /home/user/dir1
OnAccessIncludePath /home/user/dir2
OnAccessPrevention yes
OnAccessDisableDDD yes

Details: Similarly to legacy behaviour, only the top level of dir1 and dir2 will be protected in this case. The contents of all subdirectories will be ignored and extra scanning via inotify events is not possible since DDD is disabled.