ClamAV Setup and Configuration Tutorial - Fedora 41

2025/02/16

Guide based on this blog post by Daniel Aleksandersen and the ArchLinux Wiki. None of these worked perfectly on their own and some modifications were made to accommodate for that. The setup that this configuration belongs to is:

Fedora has some extra configuration that needs to happen before setting up ClamAV to work properly. The components are:

Install the packages:

1sudo dnf install clamav freshclam clamd

Start by enabling the antivirus scanning option of SELinux:

1sudo setsebool -P antivirus_can_scan_system 1 

freshclam

Start by generating initial configuration for freshclam. Freshclam is ran under the user clamupdate.

1clamconf -g freshclam.conf > freshclam.conf
2sudo mkdir /etc/freshclam.conf
3sudo chown root:root /etc/freshclam.conf
4sudo chmod u=rw,go=r /etc/freshclam.conf

Apply the following diff:

 15,7d4
 2< # Comment out or remove the line below.
 3< Example
 4< 
 514c11
 6< #LogFileMaxSize 5M
 7---
 8> LogFileMaxSize 100M
 918c15
10< #LogTime yes
11---
12> LogTime yes
1345c42
14< #DatabaseDirectory /var/lib/clamav
15---
16> DatabaseDirectory /var/lib/clamav
1762c59
18< #DatabaseOwner clamupdate
19---
20> DatabaseOwner clamupdate
2180c77
22< #DatabaseMirror database.clamav.net
23---
24> DatabaseMirror database.clamav.net
25186c183
26< #Bytecode yes
27---
28> Bytecode yes

Run a virus definition update and additionally enable the freshclam service:

1sudo freshclam
2sudo systemctl enable --now clamav-freshclam.service

Enabling the service will perform periodic updating. This is in contrast to the blog post that used cron for this functionality.

clamd

Start by generating initial configuration for the daemon. The scanning service will be ran under the user clamscan.

1clamconf -g clamd.d/scan.conf > scan.conf
2sudo mkdir /etc/clamd.d/
3sudo chown root:root /etc/clamd.d/scan.conf
4sudo chmod u=rw,go=r /etc/clamd.d/scan.conf

The following options were changed in my file, which are based of the ArchLinux guide’s recommended settings, however, not exact:

  15,7d4
  2< # Comment out or remove the line below.
  3< Example
  4< 
  535c32
  6< #LogFileMaxSize 5M
  7---
  8> LogFileMaxSize 50M
  939c36
 10< #LogTime yes
 11---
 12> LogTime yes
 1348c45
 14< #LogSyslog yes
 15---
 16> LogSyslog yes
 1766c63
 18< #ExtendedDetectionInfo yes
 19---
 20> ExtendedDetectionInfo yes
 2188c85
 22< #LocalSocket /tmp/clamd.socket
 23---
 24> LocalSocket /var/run/clamd.scan/clamd.socket
 2592c89
 26< #LocalSocketGroup virusgroup
 27---
 28> LocalSocketGroup virusgroup
 2996c93
 30< #LocalSocketMode 660
 31---
 32> LocalSocketMode 660
 33100c97
 34< #FixStaleSocket yes
 35---
 36> FixStaleSocket yes
 37135c132
 38< #MaxThreads 20
 39---
 40> MaxThreads 8
 41176c173
 42< #MaxDirectoryRecursion 15
 43---
 44> MaxDirectoryRecursion 20
 45219c216
 46< #VirusEvent /opt/send_virus_alert_sms.sh
 47---
 48> VirusEvent /opt/clamav/virus-event.sh
 49250c247
 50< #User clamav
 51---
 52> User clamscan
 53254c251
 54< #Bytecode yes
 55---
 56> Bytecode yes
 57284c281
 58< #DetectPUA yes
 59---
 60> DetectPUA yes
 61307c304
 62< #ScanPE yes
 63---
 64> ScanPE yes
 65314c311
 66< #ScanELF yes
 67---
 68> ScanELF yes
 69320c317
 70< #ScanMail yes
 71---
 72> ScanMail yes
 73386c383
 74< #ScanHTML yes
 75---
 76> ScanHTML yes
 77393c390
 78< #ScanOLE2 yes
 79---
 80> ScanOLE2 yes
 81398c395
 82< #AlertBrokenExecutables yes
 83---
 84> AlertBrokenExecutables no
 85403c400
 86< #AlertBrokenMedia yes
 87---
 88> AlertBrokenMedia no
 89425c422
 90< #AlertOLE2Macros no
 91---
 92> AlertOLE2Macros yes
 93439c436
 94< #AlertPartitionIntersection yes
 95---
 96> AlertPartitionIntersection yes
 97445c442
 98< #ScanPDF yes
 99---
100> ScanPDF yes
101451c448
102< #ScanSWF yes
103---
104> ScanSWF yes
105457c454
106< #ScanXMLDOCS yes
107---
108> ScanXMLDOCS yes
109463c460
110< #ScanHWP3 yes
111---
112> ScanHWP3 yes
113469c466
114< #ScanArchive yes
115---
116> ScanArchive yes
117634c631,637
118< #OnAccessIncludePath /home
119---
120> OnAccessIncludePath /home
121> OnAccessIncludePath /mnt
122> OnAccessIncludePath /media
123> OnAccessIncludePath /etc
124> OnAccessIncludePath /usr
125> OnAccessIncludePath /opt
126> OnAccessIncludePath /dev
127656c659,660
128< #OnAccessExcludeUname clamuser
129---
130> OnAccessExcludeUname clamupdate
131> OnAccessExcludeUname clamscan
132663c667
133< #OnAccessMaxFileSize 5M
134---
135> OnAccessMaxFileSize 5M
136671c675,676
137< #OnAccessPrevention yes
138---
139> # Warning: Setting to yes can increase package install times by 1000x
140> OnAccessPrevention no
141675c680
142< #OnAccessExtraScanning yes
143---
144> OnAccessExtraScanning yes

VirusEvent

You might have noticed the VirusEvent option that triggers when a virus is found is set to execute /opt/clamav/virus-event.sh. Set it up by running the following commands:

1sudo mkdir /opt/clamav
2sudo nvim /opt/clamav/virus-event.sh

Save the following file contents:

Set permissions:

1sudo chmod u=rwx,go= /opt/clamav/virus-event.sh
2sudo chown clamscan:clamscan /opt/clamav/virus-event.sh

Starting the Daemon

Controlled through SystemD unit files. The daemon has the possibility to freeze your system (a lot of times), so the blog post recommends to set system resource limits by overriding the systemd files.

1sudo systemctl edit clamd@

Add the following overrides:

[Service]
Nice=18
IOSchedulingClass=idle
CPUSchedulingPolicy=idle

Activate the daemon:

1systemctl daemon-reload
2systemctl enable --now clamd@scan
3systemctl status clamd@scan

Enabling OnAccessScan

OnAccessScan allows ClamAV to scan files on demand as the users access them. This is useful to have as it provides constant security at the cost of speed. To enable the service that runs the OnAccessScan, edit the service to add passing file-descriptors instead of paths:

1sudo systemctl edit clamav-clamonacc.service

Add the following overrides (the reason is explained in the ArchLinux guide):

[Service]
ExecStart=
ExecStart=/usr/sbin/clamonacc -F --fdpass --config-file=/etc/clamd.d/scan.conf

Reload and enable:

1sudo systemctl daemon-reload
2sudo systemctl enable --now clamav-clamonacc.service

Testing

This will test if a fake virus is detected. The file in the URL is harmless (it’s a txt file).

Manual

1curl https://secure.eicar.org/eicar.com.txt | clamscan -

Realtime Protection

cd ~/Downloads
wget https://secure.eicar.org/eicar.com.txt
cat eicar.com.txt

Check the logs:

1journalctl -eu clamav-clamonacc.service

If a notification did not appear, then please look at the workaround for VirusEvent below, as you may have encountered a ClamAV bug.

Using clamdscan

With clamd running in the background, we can use clamdscan. It’s like clamscan but uses the config from /etc/clamd.d/scan.conf as it uses the clamd@scan daemon we enabled previously:

1clamdscan --multiscan --infected --log clamav.log $HOME

File Permission Issues

You might notice that trying to use clamdscan, gives you a variety of errors:

--------------------------------------
/home/yiannis: File path check failure: Permission denied. ERROR

----------- SCAN SUMMARY -----------
Infected files: 0
Total errors: 1
Time: 0.002 sec (0 m 0 s)
Start Date: 2025:02:17 23:45:20
End Date:   2025:02:17 23:45:20

In order to fix this issue, the parameter --fdpass needs to be included; clamdscan -mil clamav.log --fdpass $HOME. This will make clamscan (ran under the $USER) pass the file descriptor to clamd (ran under clamscan), allowing the clamscan user to bypass the file permissions of the home folder.

LocalSocket Issues

At this point, another error with local socket permissions should appear:

ERROR: Could not connect to clamd on LocalSocket /var/run/clamd.scan/clamd.socket

This is caused because the clamdscan process (ran under $USER) does not have permissions to access the socket; owned by clamscan and part of the virusgroup group. The solution to this:

1sudo usermod -aG virusgroup $USER

Log out and log back in. Now clamdscan should work (don’t forget to pass --fdpass.

VirusEvent Workaround

There’s an issue that ClamAV is facing where VirusEvent is not working. A user suggested a workaround where we deploy an extra script to read the logs and trigger the virus event manually. Keep this while the issue is open. After the issue is resolved, you can delete all the work done in this section.

Notifier Script

Start by creating a script the notifier script:

1sudo nvim /opt/clamav/clamonacc-log-notifier.sh

This script is responsible for scanning the log file and creating the virus events.

Monitor Script

Create the monitor script that will feed the log file to the notifier script.

1sudo nvim /opt/clamav/clamonacc-log-monitor.sh

This script pipes the output of the journal which contains the logs from the OnAccessScan service to the notifier script.

Set appropriate permissions for both scripts:

1sudo chmod --reference=/opt/clamav/virus-event.sh /opt/clamav/clamonacc-log-notifier.sh /opt/clamav/clamonacc-log-monitor.sh
2sudo chown --reference=/opt/clamav/virus-event.sh /opt/clamav/clamonacc-log-notifier.sh /opt/clamav/clamonacc-log-monitor.sh

Service File

Now create a service file to run these two scripts:

1sudo nvim /etc/systemd/system/clamav-clamonacc-notifier.service

This simply waits for all other services to start, then run the script as root:

[Unit]
Description=ClamAV On-Access Notifier (Workaround for VirusEvent being broken in ClamAV)
Requires=clamav-clamonacc.service
After=clamav-clamonacc.service syslog.target network.target
[Service]
Type=simple
User=root
ExecStart=/opt/clamav/clamonacc-log-monitor.sh
Restart=always
[Install]
WantedBy=multi-user.target

Enable the service:

1sudo systemctl daemon-reload
2sudo systemctl enable --now clamav-clamonacc-notifier

Reversing the Workaround

Effort was put to make the VirusEvent workaround changes as minimal as possible. When the issue is fixed, reverse the changes by running the following commands:

1sudo systemctl stop clamav-clamonacc-notifier
2sudo systemctl disable clamav-clamonacc-notifier
3sudo systemctl daemon-reload
4sudo rm /etc/systemd/system/clamav-clamonacc-notifier.service /opt/clamav/clamonacc-log-monitor.sh /opt/clamav/clamonacc-log-notifier.sh

These commands stop and delete the service from the system and delete the remaining scripts that were created.

Install GUI - ClamTK

ClamTK is a GUI front-end for ClamAV. Its main limitation is that it doesn’t allow you to configure ClamAV in any meaningful way. It contains some basic utilities such as scanning files and directories. To install it run the following command:

1sudo dnf install clamtk

I personally don’t find it that useful.

Existing Issues

While my research into this program has resolved most of the issues, I have still am facing the following problems. If you know how to resolve them, please get in touch.

Duplicate Reports in clamav-clamonacc

Running clamdscan

The following problems are produced when running the command:

1clamdscan --quiet -mil clamav.log --fdpass -i $HOME

STDOUT

LOG FILE