All Articles

ClamAV をソースコードからビルドして OnAccessScan をセットアップするまでのまとめ

2024 年は大きめのプロダクトのソースコードをじっくり読み込みたく、一番興味のある AntiVirus をやっていきたいと思っています。

しかし、非常に残念なことに一般にソースコードが公開されている AntiVirus Software はほぼ存在しません。

そんな中で、ほぼ唯一オープンソースで開発を行っている AntiVirus Software が、主にメールゲートウェイを対象とするプロダクトの ClamAV です。

ClamAV は Linux 環境限定ではありますが、昨今の Linux 用 AntiVirus の多くが利用している fanotify を利用した OnAccesScan(リアルタイムスキャン) の機能もあり、非常に参考になりそうなプロダクトです。 (Windows 端末でも、オンデマンドスキャナとしての ClamAV を利用できます。)

今回は ClamAV のソースコードを読み解く足掛かりとして、ClamAV 1.2.0 のビルドと一通りのセットアップ手順をまとめてみました。

もくじ

事前準備

ビルド & インストール

Ubuntu 20.04 に ClamAV をインストールするためには以下のコマンドを使用しました。

# Run with root user in Ubuntu 20.04
apt-get update && apt-get install -y gcc make pkg-config python3 python3-pip python3-pytest valgrind cmake check libbz2-dev libcurl4-openssl-dev libjson-c-dev libmilter-dev libncurses5-dev libpcre2-dev libssl-dev libxml2-dev zlib1g-dev cargo rustc -y

# Install rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Build and install
git clone https://github.com/Cisco-Talos/clamav.git
cd clamav && mkdir -p build && cd build
cmake ..
cmake --build . --target install

# Check install version
clamav-config --version

参考:Unix from source (v0.104+) - ClamAV Documentation

ルートディレクトリにある CMakeLists.txt は CMake でビルドプロセスを管理するためのビルド設定を定義しているファイルです。

ClamAV 1.2.0 の場合はおよそ 1300 行ほどありますが、ざっと見ていくとどのようなファイルをビルドに使用しているかの大枠を把握できます。

参考:clamav/CMakeLists.txt at clamav-1.2.0 · Cisco-Talos/clamav

以下では、ルート直下の cmake ディレクトリを CMAKE_MODULE_PATH としてセットし、バージョン情報を include していることがわかります。

set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
include(Version)

set(PACKAGE_NAME      "${PROJECT_NAME}")
set(PACKAGE_VERSION   "${PROJECT_VERSION}")
set(PACKAGE_STRING    "${PROJECT_NAME} ${PROJECT_VERSION}${VERSION_SUFFIX}")
set(PACKAGE_BUGREPORT "https://github.com/Cisco-Talos/clamav/issues")
set(PACKAGE_URL       "https://www.clamav.net/")
HexVersion(PACKAGE_VERSION_NUM ${PROJECT_VERSION_MAJOR} ${PROJECT_VERSION_MINOR} ${PROJECT_VERSION_PATCH})

Version.cmake の中には HexVersion と NumberToHex という 2 つの関数が定義されています。

それぞれ名前の通り、バージョン情報の値を 16 進数文字列に変換する用途で使用されているようです。

参考:clamav/cmake/Version.cmake at clamav-1.2.0 · Cisco-Talos/clamav

以下では、ビルド対象のプラットフォームが Linux または Unix か macOS であるかを識別しています。

Linux の場合は C_LINUX にフラグを立てます。

# Define C_LINUX and C_BSD because CMake only defines UNIX, APPLE, WIN32, MSVC
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
    set(C_LINUX 1)
elseif(APPLE OR CMAKE_SYSTEM_NAME MATCHES "BSD")
    set(C_BSD 1)
endif()

以下では、 デフォルトオプションをいくつか定義しています。

前述のコードで C_LINUX にフラグが立っている場合は、ENABLE_CLAMONACC_DEFAULT が ON に設定されます。

# CMake Option default values:
set(MAINTAINER_MODE_DEFAULT         OFF)
set(ENABLE_APP_DEFAULT              ON)
if(WIN32 OR APPLE)
    set(ENABLE_MILTER_DEFAULT       OFF)
else()
    set(ENABLE_MILTER_DEFAULT       ON)
endif()
if(C_LINUX)
    set(ENABLE_CLAMONACC_DEFAULT    ON)
else()
    set(ENABLE_CLAMONACC_DEFAULT    OFF)
endif()
set(ENABLE_EXAMPLES_DEFAULT         OFF)
set(ENABLE_TESTS_DEFAULT            ON)
if(WIN32)
    set(ENABLE_MAN_PAGES_DEFAULT    OFF)
else()
    set(ENABLE_MAN_PAGES_DEFAULT    ON)
endif()
set(ENABLE_DOXYGEN_DEFAULT          OFF)
set(ENABLE_UNRAR_DEFAULT            ON)
set(ENABLE_SYSTEMD_DEFAULT          ON)

また、ルート直下の CMakeOptions.cmake で定義したオプション設定もここでロードします。

# See CMakeOptions.cmake for additional options.
include(CMakeOptions.cmake)

参考:clamav/CMakeOptions.cmake at clamav-1.2.0 · Cisco-Talos/clamav

続く以下の行では、CMake のビルドタイプが指定されているかをチェックします。

ビルドタイプが指定されていない場合はデフォルトで RelWithDebInfo(ビルド時の最適化あり、デバッグ情報あり、asset なし) が選択されます。

その他、Debug を設定した場合はビルド時の最適化が行われず、デバッグ情報の付与や assert の有効化が行われます。

# Set build type to RelWithDebInfo if not specified.
# This must be done before pulling in the Rust module
# or else the default build will be Debug for Rust stuffs.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
    set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the build type" FORCE)

    # Include "None" as option to disable any additional (optimization) flags,
    # relying on just CMAKE_C_FLAGS and CMAKE_CXX_FLAGS (which are empty by
    # default). These strings are presented in cmake-gui.
    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
        "None" "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

参考:ClamAV Documentation

テストに関するオプションなどを飛ばして読み進めると以下の箇所が見つかります。

ここでは、cmake の find_package を使用していくつかの依存関係パッケージの存在確認を行っています。

# Including CPack must be the very last CPack thing we do.
include(CPack)

# libclamav efficacy dependencies
find_package(OpenSSL REQUIRED)
if(OPENSSL_FOUND)
    set(HAVE_LIBSSL 1)
endif()

find_package(ZLIB REQUIRED)
if(ZLIB_FOUND)
    set(HAVE_ZLIB_H 1)
    set(HAVE_LIBZ 1)
endif()

find_package(BZip2 REQUIRED)
if(BZIP2_FOUND)
    set(HAVE_BZLIB_H 1)
endif()

# Disable CMAKE_FIND_PACKAGE_PREFER_CONFIG, temporarily, because
# we don't presently support the using libxml2's Config.cmake
set(PACKAGE_PREFER_CONFIG_BAK ${CMAKE_FIND_PACKAGE_PREFER_CONFIG})
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG FALSE)

find_package(LibXml2 REQUIRED)
if(LibXml2_FOUND)
    set(HAVE_LIBXML2 1)
endif()
# Restore the requested CMAKE_FIND_PACKAGE_PREFER_CONFIG setting
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ${PACKAGE_PREFER_CONFIG_BAK})

find_package(PCRE2 REQUIRED)
if(PCRE2_FOUND)
    set(HAVE_PCRE 1)
    set(USING_PCRE2 1)
endif()

# libclamav feature dependencies
if(NOT WIN32)
    find_package(Iconv REQUIRED)
    # Set variable required by libclamav to use iconv
    set(HAVE_ICONV 1)
endif()

参考:find_package — CMake 3.28.1 Documentation

また、check_include_file によりヘッダファイルのチェックも実施しています。

# Checks for header files.
include(CheckIncludeFile)
check_include_file("arpa/inet.h"        HAVE_ARPA_INET_H)
check_include_file("fcntl.h"            HAVE_FCNTL_H)
check_include_file("grp.h"              HAVE_GRP_H)
check_include_file("limits.h"           HAVE_LIMITS_H)
check_include_file("malloc.h"           HAVE_MALLOC_H)
check_include_file("netdb.h"            HAVE_NETDB_H)
check_include_file("netinet/in.h"       HAVE_NETINET_IN_H)
check_include_file("poll.h"             HAVE_POLL_H)
check_include_file("pwd.h"              HAVE_PWD_H)
check_include_file("stdbool.h"          HAVE_STDBOOL_H)
check_include_file("stdlib.h"           HAVE_STDLIB_H)
check_include_file("string.h"           HAVE_STRING_H)
check_include_file("strings.h"          HAVE_STRINGS_H)
check_include_file("sys/cdefs.h"        HAVE_SYS_CDEFS_H)
check_include_file("sys/dl.h"           HAVE_SYS_DL_H)
check_include_file("sys/fileio.h"       HAVE_SYS_FILIO_H)
check_include_file("sys/mman.h"         HAVE_SYS_MMAN_H)
check_include_file("sys/param.h"        HAVE_SYS_PARAM_H)
check_include_file("sys/queue.h"        HAVE_SYS_QUEUE_H)
check_include_file("sys/select.h"       HAVE_SYS_SELECT_H)
check_include_file("sys/socket.h"       HAVE_SYS_SOCKET_H)
check_include_file("sys/stat.h"         HAVE_SYS_STAT_H)
check_include_file("sys/time.h"         HAVE_SYS_TIME_H)
check_include_file("sys/times.h"        HAVE_SYS_TIMES_H)
check_include_file("sys/uio.h"          HAVE_SYS_UIO_H)
check_include_file("syslog.h"           USE_SYSLOG)
check_include_file("termios.h"          HAVE_TERMIOS_H)
check_include_file("time.h"             HAVE_TIME_H)
check_include_file("unistd.h"           HAVE_UNISTD_H)
check_include_file("sys/fanotify.h"     HAVE_SYS_FANOTIFY_H)
**
# int-types variants
check_include_file("inttypes.h"         HAVE_INTTYPES_H)
check_include_file("sys/inttypes.h"     HAVE_SYS_INTTYPES_H)
check_include_file("sys/int_types.h"    HAVE_SYS_INT_TYPES_H)
check_include_file("stdint.h"           HAVE_STDINT_H)

最後に、テストやビルドなどの処理を定義しています。

この時、CMAKE_INSTALL_PREFIXCLAMAV_USER などのオプションによって、ClamAV のインストール先や ClamAV ユーザなどが決定されます。

# autotools-compatible names
# Sphinx expects relative paths in the .rst files. Use the fact that the files
# below are all one directory level deep.
file(RELATIVE_PATH top_srcdir   "${CMAKE_CURRENT_BINARY_DIR}/dir" "${CMAKE_CURRENT_SOURCE_DIR}")
file(RELATIVE_PATH top_builddir "${CMAKE_CURRENT_BINARY_DIR}/dir" "${CMAKE_CURRENT_BINARY_DIR}")
set(abs_top_srcdir   "${CMAKE_CURRENT_SOURCE_DIR}")
set(abs_top_builddir "${CMAKE_CURRENT_BINARY_DIR}")
# libclamav.pc (pkg-config file)
set(prefix      "${CMAKE_INSTALL_PREFIX}")
set(exec_prefix "${CMAKE_INSTALL_PREFIX}")
set(bindir      "${CMAKE_INSTALL_FULL_BINDIR}")
set(sbindir     "${CMAKE_INSTALL_FULL_SBINDIR}")
set(libdir      "${CMAKE_INSTALL_FULL_LIBDIR}")
set(includedir  "${CMAKE_INSTALL_FULL_INCLUDEDIR}")
set(VERSION     "${PACKAGE_VERSION}")

セットアップ

ClamAV のビルドとインストールが完了したら、とりあえず ClamAV のシグネチャの更新とリアルタイム保護(オンアクセススキャン)、そしてオンデマンドスキャンによって最低限 Malware を検出できるところまでセットアップを進めていきます。

インストールモジュール

セットアップの前に、ClamAV の動作に関わる主要なコンポーネントをチェックしていきます。

  • clamd:これは、libclamav を使用してファイルスキャンを行うためのマルチスレッドデーモンです。スキャンの動作は clamd.conf にて変更が可能です。
  • clamdscan:clamd のクライアントモジュールです。clamd のソケット(または TCP)に対してコマンド実行を要求したり、スキャン結果をレポートしたりすることができます。clamdscan によりスキャンを実行するためには clamd デーモンが稼働している必要があります。
  • clamscan:clamdscan と名称が似ていますがこちらは単体の手動スキャン(Onetime Scan)を実行するためのコマンドラインツールです。clamdscan とは異なり、スキャンを実行するために clamd デーモンの稼働を必要としません。
  • freshclam:ClamAV のシグネチャデータベース(.cvd)を更新するために使用するモジュールです。構成ファイル freshclam.conf にて管理されます。
  • clamonacc:Linux システムにリアルタイム保護(オンアクセススキャン)を提供するモジュールです。これによって、ファイルアクセス時にリアルタイムに clamd によるファイルスキャンを行うことができるようになります。

    リアルタイム保護では、スキャン結果に基づいて Malware へのアクセスをブロックできますが、既定では監査のみを行う設定になっています。

  • clamav-milter:clamd と連携して動作するメールフィルタリングツールです。メールサーバと連携して Malware スキャンを実施できます。
  • clamconf:ClamAV システム全体の構成をチェックするためのツールです。

参考:Scanning - ClamAV Documentation

参考:Configuration - ClamAV Documentation

参考:メールサーバーでウイルスチェック(Postfix+Clam AntiVirus+clamav-milter) - AlmaLinuxで自宅サーバー構築

サービスユーザアカウントを作成する

パッケージマネージャではなくソースコードから ClamAV をビルドする場合、サービスユーザアカウントは手動で作成する必要があります。

このサービスユーザは freshclam によるシグネチャの更新にも利用します。

# Run with root user in Ubuntu 20.04
groupadd clamav
useradd -g clamav -s /bin/false -c "Clam Antivirus" clamav
mkdir -p /usr/local/share/clamav
chown -R clamav:clamav /usr/local/share/clamav

参考:Configuration - ClamAV Documentation

また、事前にログファイルを作成し、サービスユーザを所有者に変更しておきます。

touch /var/log/freshclam.log ; touch /var/log/clamav.log
chmod 600 /var/log/freshclam.log ; chmod 600 /var/log/clamav.log
chown clamav /var/log/freshclam.log ; chown clamav /var/log/clamav.log

そして、作成した clamav ユーザがパスワードなしで sudo 経由の notification-send を実行できるようにします。

echo "clamav ALL = (ALL) NOPASSWD: SETENV: /usr/bin/notify-send" > /etc/sudoers.d/clamav

参考:ClamAV - ArchWiki

設定ファイルを作成する

今回は clamav-milter は使用しないので clamd.conffreshclam.conf の設定ファイルを作成します。

パッケージマネージャではなくソースコードから ClamAV をビルドする場合、構成ファイルは手動で作成する必要があります。

clamconf を使用することで構成ファイルのサンプルを作成できるので、このサンプルを編集した後に構成ディレクトリに配置します。

# Run with root user in Ubuntu 20.04
# Generate sample config files
mkdir -p /etc/clamav
clamconf -g freshclam.conf > /usr/local/etc/freshclam.confm.conf
clamconf -g clamd.conf > /usr/local/etc/clamd.conf

参考:Configuration - ClamAV Documentation

freshclam.conf を編集する

まず初めに freshclam で作成した /usr/local/etc/freshclam.conf を直接編集していきます。

ClamAV をすでに運用中の場合は、別のディレクトリで編集し、あとで設定ファイルを置き換えます。

最終的に設定した freshclam.conf は以下の通りです。

※ 実運用環境での使用を想定していないため意図的にセキュリティレベルを低下させていたり、パフォーマンス影響の大きい設定を有効化していたりします。

##
## freshclam.conf - automatically generated by clamconf 1.2.0
##

# Maximum size of the log file.
# Value of 0 disables the limit.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 1048576
LogFileMaxSize 5M

# Log time with each message.
# Default: no
LogTime yes

# Use the system logger (can work together with LogFile).
# Default: no
LogSyslog yes

# Type of syslog messages.
# Please refer to 'man syslog' for the facility names.
# Default: LOG_LOCAL6
#LogFacility LOG_MAIL

# Enable verbose logging.
# Default: no
LogVerbose yes

# Rotate log file. Requires LogFileMaxSize option set prior to this option.
# Default: no
LogRotate yes

# Save the process ID to a file.
# Default: disabled
# PidFile /run/clamav/clam.pid

# This option allows you to change the default database directory.
# If you enable it, please make sure it points to the same directory in
# both clamd and freshclam.
# Default: /usr/local/share/clamav
#DatabaseDirectory /var/lib/clamav

# Don't fork into background.
# Default: no
#Foreground no

# Enable debug messages in libclamav.
# Default: no
Debug yes

# Save all reports to a log file.
# Default: disabled
UpdateLogFile /var/log/freshclam.log

# When started by root freshclam will drop privileges and switch to the user
# defined in this option.
# Default: clamav
#DatabaseOwner clamav

# This option defined how many times daily freshclam should check for
# a database update.
# Default: 12
Checks 1

# Use DNS to verify the virus database version. FreshClam uses DNS TXT records
# to verify the versions of the database and software itself. With this
# directive you can change the database verification domain.
# WARNING: Please don't change it unless you're configuring freshclam to use
# your own database verification domain.
# Default: current.cvd.clamav.net
DNSDatabaseInfo current.cvd.clamav.net

# DatabaseMirror specifies to which mirror(s) freshclam should connect.
# You should have at least one entry: database.clamav.net.
# Default: disabled
DatabaseMirror database.clamav.net

# This option allows you to easily point freshclam to private mirrors.
# If PrivateMirror is set, freshclam does not attempt to use DNS
# to determine whether its databases are out-of-date, instead it will
# use the If-Modified-Since request or directly check the headers of the
# remote database files. For each database, freshclam first attempts
# to download the CLD file. If that fails, it tries to download the
# CVD file. This option overrides DatabaseMirror, DNSDatabaseInfo
# and Scripted Updates. It can be used multiple times to provide
# fall-back mirrors.
# Default: disabled
#PrivateMirror mirror1.mynetwork.com
#PrivateMirror mirror2.mynetwork.com

# This option defines how many attempts freshclam should make before giving up.
# Default: 3
#MaxAttempts 5

# With this option you can control scripted updates. It's highly recommended to keep them enabled.
# Default: yes
#ScriptedUpdates yes

# With this option enabled, freshclam will attempt to load new
# databases into memory to make sure they are properly handled
# by libclamav before replacing the old ones. Tip: This feature uses a lot of RAM. If your system has limited RAM and you are actively running ClamD or ClamScan during the update, then you may need to set `TestDatabases no`.
# Default: yes
#TestDatabases yes

# By default freshclam will keep the local databases (.cld) uncompressed to
# make their handling faster. With this option you can enable the compression.
# The change will take effect with the next database update.
# Default: no
#CompressLocalDatabase 

# Include an optional signature databases (opt-in). This option can be used multiple times.
# Default: disabled
#ExtraDatabase dbname1
#ExtraDatabase dbname2

# Exclude a standard signature database (opt-out). This option can be used multiple times.
# Default: disabled
#ExcludeDatabase dbname1
#ExcludeDatabase dbname2

# With this option you can provide custom sources (http:// or file://) for database files.
# This option can be used multiple times.
# Default: disabled
#DatabaseCustomURL http://myserver.com/mysigs.ndb
#DatabaseCustomURL file:///mnt/nfs/local.hdb

# If you're behind a proxy, please enter its address here.
# Default: disabled
#HTTPProxyServer your-proxy

# HTTP proxy's port
# Default: disabled
#HTTPProxyPort 8080

# A user name for the HTTP proxy authentication.
# Default: disabled
#HTTPProxyUsername username

# A password for the HTTP proxy authentication.
# Default: disabled
#HTTPProxyPassword pass

# If your servers are behind a firewall/proxy which does a User-Agent
# filtering you can use this option to force the use of a different
# User-Agent header.
# Default: disabled
#HTTPUserAgent default

# Send the RELOAD command to clamd after a successful update.
# Default: /usr/local/etc/clamd.conf
#NotifyClamd yes

# Run a command after a successful database update. Use EXIT_1 to return 1 after successful database update.
# Default: disabled
#OnUpdateExecute command

# Run a command when a database update error occurs.
# Default: disabled
#OnErrorExecute command

# Run a command when freshclam reports an outdated version.
# In the command string %v will be replaced with the new version number.
# Default: disabled
#OnOutdatedExecute command

# With this option you can provide a client address for the database downloading.
# Useful for multi-homed systems.
# Default: disabled
#LocalIPAddress aaa.bbb.ccc.ddd

# Timeout in seconds when connecting to database server.
# Default: 30
#ConnectTimeout 30

# Timeout in seconds when reading from database server. 0 means no timeout.
# Default: 60
#ReceiveTimeout 60

# This option enables downloading of bytecode.cvd, which includes additional
# detection mechanisms and improvements to the ClamAV engine.
# Default: yes
#Bytecode yes

設定ファイルについて上から順に見ていきます。

まず、先頭行にある Example という文字は必ず削除する必要があります。

# Comment out or remove the line below.
Example

次に、ログファイルの最大サイズを 5 MB に変更し、LogTime と LogSyslog 、そして LogVerbose に LogRotate を有効化します。

LogFacility についてはデフォルトの LOG_LOCAL6 のままでよいので変更しません。

# Maximum size of the log file.
# Value of 0 disables the limit.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 1048576
LogFileMaxSize 5M

# Log time with each message.
# Default: no
LogTime yes

# Use the system logger (can work together with LogFile).
# Default: no
LogSyslog yes

# Enable verbose logging.
# Default: no
LogVerbose yes

# Rotate log file. Requires LogFileMaxSize option set prior to this option.
# Default: no
LogRotate yes

PidFile は有効化し、パスを /run/clamav/clam.pid に設定します。

# Save the process ID to a file.
# Default: disabled
PidFile /run/clamav/clam.pid

DatabaseDirectory は既定値の /usr/local/share/clamav を使用します。

このディレクトリを変更する場合は、サービスアカウント clamav に割り当てるディレクトリを追加する必要があります。

# This option allows you to change the default database directory.
# If you enable it, please make sure it points to the same directory in
# both clamd and freshclam.
# Default: /usr/local/share/clamav
#DatabaseDirectory /var/lib/clamav

libclamav のデバッグメッセージを有効化します。

また、freshclam.log にログを出力するように設定します。

# Enable debug messages in libclamav.
# Default: no
Debug yes

# Save all reports to a log file.
# Default: disabled
UpdateLogFile /var/log/freshclam.log

DatabaseOwner は既定値の clamav から変更しません。

シグネチャデータベースの更新頻度はとりあえず 1 時間にしておきます。

# When started by root freshclam will drop privileges and switch to the user
# defined in this option.
# Default: clamav
#DatabaseOwner clamav

# This option defined how many times daily freshclam should check for
# a database update.
# Default: 12
Checks 1

Private Mirror は使用しないので、DatabaseMirror はデフォルトの公式配布元を指定しておきます。

# Use DNS to verify the virus database version. FreshClam uses DNS TXT records
# to verify the versions of the database and software itself. With this
# directive you can change the database verification domain.
# WARNING: Please don't change it unless you're configuring freshclam to use
# your own database verification domain.
# Default: current.cvd.clamav.net
DNSDatabaseInfo current.cvd.clamav.net

# DatabaseMirror specifies to which mirror(s) freshclam should connect.
# You should have at least one entry: database.clamav.net.
# Default: disabled
DatabaseMirror database.clamav.net

以降の設定はとりあえず既定値のまま使用するので変更しません。

これで flashclam コマンドを実行した際にシグネチャデータベースの更新がかかれば OK です。

image-20240120000027395

更新が完了した場合、DatabaseDirectory で設定したパス(既定では /usr/local/share/clamav) にcvd ファイルが書き込まれます。

image-20240120153130319

freshclam による更新をデーモンとして実行する場合、freshclam -d コマンドを発行します。

例えば、1 日に 10 回の更新チェックを指定する場合は freshclam -d -c 10 を実行して freshclam デーモンを起動します。

image-20240120152820239

または、cron などによって /usr/local/bin/freshclam --quiet コマンドを発行するように構成することでも自動更新を構成することが可能です。

参考:Configuration - ClamAV Documentation

clamd.conf を編集する

次に、/usr/local/etc/clamd.conf を編集していきます。

最終的に使用する構成ファイルは以下の通りです。

※ 実運用環境での使用を想定していないため意図的にセキュリティレベルを低下させていたり、パフォーマンス影響の大きい設定を有効化していたりします。

##
## clamd.conf - automatically generated by clamconf 1.2.0
##

# Default: no
#AlertExceedsMax

# Number of entries the cache can store.
# Default: 65536
# CacheSize 65536

# Enable prelude
# Default: no
#PreludeEnable 

# Name of the analyzer as seen in prewikka
# Default: disabled
#PreludeAnalyzerName 

# Save all reports to a log file.
# Default: disabled
LogFile /var/log/clamav.log

# By default the log file is locked for writing and only a single
# daemon process can write to it. This option disables the lock.
# Default: no
LogFileUnlock yes

# Maximum size of the log file.
# Value of 0 disables the limit.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 1048576
LogFileMaxSize 5M

# Log time with each message.
# Default: no
LogTime yes

# Log all clean files.
# Useful in debugging but drastically increases the log size.
# Default: no
LogClean no

# Use the system logger (can work together with LogFile).
# Default: no
LogSyslog yes

# Type of syslog messages.
# Please refer to 'man syslog' for the facility names.
# Default: LOG_LOCAL6
#LogFacility LOG_MAIL

# Enable verbose logging.
# Default: no
LogVerbose yes

# Rotate log file. Requires LogFileMaxSize option set prior to this option.
# Default: no
LogRotate yes

# Log additional information about the infected file, such as its
# size and hash, together with the virus name.
# Default: no
ExtendedDetectionInfo yes

# Save the process ID to a file.
# Default: disabled
# PidFile /run/clamav/clam.pid

# This option allows you to change the default temporary directory.
# Default: disabled
TemporaryDirectory /tmp

# This option allows you to change the default database directory.
# If you enable it, please make sure it points to the same directory in
# both clamd and freshclam.
# Default: /usr/local/share/clamav
DatabaseDirectory /usr/local/share/clamav

# Only load the official signatures published by the ClamAV project.
# Default: no
OfficialDatabaseOnly no

# Return with a nonzero error code if the virus database is older than the specified number of days.
# Default: disabled
#FailIfCvdOlderThan -1

# Path to a local socket file the daemon will listen on.
# Default: disabled
#LocalSocket /run/clamav/clamd.sock

# Sets the group ownership on the unix socket.
# Default: disabled
#LocalSocketGroup virusgroup

# Sets the permissions on the unix socket to the specified mode.
# Default: disabled
#LocalSocketMode 660

# Remove a stale socket after unclean shutdown
# Default: yes
#FixStaleSocket yes

# A TCP port number the daemon will listen on.
# Default: disabled
TCPSocket 3310

# By default clamd binds to INADDR_ANY.
# This option allows you to restrict the TCP address and provide
# some degree of protection from the outside world.
# Default: disabled
TCPAddr 127.0.0.1

# Maximum length the queue of pending connections may grow to.
# Default: 200
MaxConnectionQueueLength 200

# Close the STREAM session when the data size limit is exceeded.
# The value should match your MTA's limit for the maximum attachment size.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 104857600
StreamMaxLength 100M

# The STREAM command uses an FTP-like protocol.
# This option sets the lower boundary for the port range.
# Default: 1024
StreamMinPort 1024

# This option sets the upper boundary for the port range.
# Default: 2048
StreamMaxPort 2048

# Maximum number of threads running at the same time.
# Default: 10
MaxThreads 20

# This option specifies the time (in seconds) after which clamd should
# timeout if a client doesn't provide any data.
# Default: 120
ReadTimeout 120

# This option specifies the time (in seconds) after which clamd should
# timeout if a client doesn't provide any initial command after connecting.
# Default: 30
CommandReadTimeout 30

# This option specifies how long to wait (in milliseconds) if the send buffer
# is full. Keep this value low to prevent clamd hanging.
# Default: 500
SendBufTimeout 200

# Maximum number of queued items (including those being processed by MaxThreads
# threads). It is recommended to have this value at least twice MaxThreads
# if possible.
# WARNING: you shouldn't increase this too much to avoid running out of file
#  descriptors, the following condition should hold:
#  MaxThreads*MaxRecursion + MaxQueue - MaxThreads  + 6 < RLIMIT_NOFILE
#  (usual max for RLIMIT_NOFILE is 1024)
# 
# Default: 100
MaxQueue 200

# This option specifies how long (in seconds) the process should wait
# for a new job.
# Default: 30
IdleTimeout 60

# Don't scan files/directories whose names match the provided
# regular expression. This option can be specified multiple times.
# Default: disabled
ExcludePath ^/proc/
ExcludePath ^/sys/
ExcludePath ^/run/

# Maximum depth the directories are scanned at.
# Default: 15
MaxDirectoryRecursion 15

# Follow directory symlinks.
# Default: no
FollowDirectorySymlinks yes

# Follow symlinks to regular files.
# Default: no
FollowFileSymlinks yes

# Scan files and directories on other filesystems.
# Default: yes
CrossFilesystems yes

# This option specifies the time intervals (in seconds) in which clamd
# should perform a database check.
# Default: 600
SelfCheck 600

# Enable non-blocking (multi-threaded/concurrent) database reloads. This feature 
# will temporarily load a second scanning engine while scanning continues using 
# the first engine. Once loaded, the new engine takes over. The old engine is 
# removed as soon as all scans using the old engine have completed. This feature 
# requires more RAM, so this option is provided in case users are willing to 
# block scans during reload in exchange for lower RAM requirements.
# Default: yes
#ConcurrentDatabaseReload yes

# This option allows you to disable clamd's caching feature.
# Default: no
#DisableCache no

# Execute a command when a virus is found. In the command string %v will be
# replaced with the virus name and %f will be replaced with the file name.
# Additionally, two environment variables will be defined: $CLAM_VIRUSEVENT_FILENAME
# and $CLAM_VIRUSEVENT_VIRUSNAME.
# Default: disabled
#VirusEvent /usr/bin/mailx -s "ClamAV VIRUS ALERT: %v" alert < /dev/null
VirusEvent /etc/clamav/virus-event.bash

# Stop the daemon when libclamav reports an out of memory condition.
# Default: no
#ExitOnOOM yes

# Permit use of the ALLMATCHSCAN command.
# Default: yes
#AllowAllMatchScan yes

# Don't fork into background.
# Default: no
Foreground yes

# Enable debug messages in libclamav.
# Default: no
Debug yes

# Don't remove temporary files (for debugging purposes).
# Default: no
LeaveTemporaryFiles no

# Record metadata about the file being scanned.
# Scan metadata is useful for file analysis purposes and for debugging scan behavior.
# The JSON metadata will be printed after the scan is complete if Debug is enabled.
# A metadata.json file will be written to the scan temp directory if LeaveTemporaryFiles is enabled.
# Default: no
GenerateMetadataJson yes

# Run the daemon as a specified user (the process must be started by root).
# Default: disabled
User clamav

# With this option enabled ClamAV will load bytecode from the database. It is highly recommended you keep this option on, otherwise you'll miss detections for many new viruses.
# Default: yes
Bytecode yes

# Set bytecode security level.
# Possible values:
# 	TrustSigned - trust bytecode loaded from signed .c[lv]d files,
# 		 insert runtime safety checks for bytecode loaded from other sources
# 	Paranoid - don't trust any bytecode, insert runtime checks for all
# Recommended: TrustSigned, because bytecode in .cvd files already has these checks.
# Default: TrustSigned
BytecodeSecurity Paranoid

# Set bytecode timeout in milliseconds.
# Default: 10000
BytecodeTimeout 10000

# Allow loading bytecode from outside digitally signed .c[lv]d files.
# Default: no
BytecodeUnsigned yes

# Set bytecode execution mode.
# Possible values:
# 	Auto - automatically choose JIT if possible, fallback to interpreter
# ForceJIT - always choose JIT, fail if not possible
# ForceInterpreter - always choose interpreter
# Test - run with both JIT and interpreter and compare results. Make all failures fatal.
# Default: Auto
BytecodeMode Auto

# Detect Potentially Unwanted Applications.
# Default: no
DetectPUA yes

# Exclude a specific PUA category. This directive can be used multiple times.
# See https://docs.clamav.net/faq/faq-pua.html for the complete list of PUA
# categories.
# Default: disabled
#ExcludePUA NetTool
#ExcludePUA PWTool

# Only include a specific PUA category. This directive can be used multiple
# times.
# Default: disabled
IncludePUA Spy
IncludePUA Scanner
IncludePUA RAT
IncludePUA NetTool
IncludePUA PWTool

# PE stands for Portable Executable - it's an executable file format used
# in all 32- and 64-bit versions of Windows operating systems. This option
# allows ClamAV to perform a deeper analysis of executable files and it's also
# required for decompression of popular executable packers such as UPX or FSG.
# If you turn off this option, the original files will still be scanned, but
# without additional processing.
# Default: yes
ScanPE yes

# Executable and Linking Format is a standard format for UN*X executables.
# This option allows you to control the scanning of ELF files.
# If you turn off this option, the original files will still be scanned, but
# without additional processing.
# Default: yes
ScanELF yes

# Enable the built in email scanner.
# If you turn off this option, the original files will still be scanned, but
# without parsing individual messages/attachments.
# Default: yes
ScanMail no

# Scan RFC1341 messages split over many emails. You will need to
# periodically clean up $TemporaryDirectory/clamav-partial directory.
# WARNING: This option may open your system to a DoS attack. Please don't use
# this feature on highly loaded servers.
# Default: no
ScanPartialMessages no

# With this option enabled ClamAV will try to detect phishing attempts by using
# signatures.
# Default: yes
PhishingSignatures yes

# Scan URLs found in mails for phishing attempts using heuristics.
# Default: yes
PhishingScanURLs yes

# In some cases (eg. complex malware, exploits in graphic files, and others),
# ClamAV uses special algorithms to provide accurate detection. This option
# controls the algorithmic detection.
# Default: yes
HeuristicAlerts yes

# Allow heuristic match to take precedence.
# When enabled, if a heuristic scan (such as phishingScan) detects
# a possible virus/phish it will stop scan immediately. Recommended, saves CPU
# scan-time.
# When disabled, virus/phish detected by heuristic scans will be reported only
# at the end of a scan. If an archive contains both a heuristically detected
# virus/phish, and a real malware, the real malware will be reported.
# Keep this disabled if you intend to handle "Heuristics.*" viruses
# differently from "real" malware.
# If a non-heuristically-detected virus (signature-based) is found first,
# the scan is interrupted immediately, regardless of this config option.
# Default: no
HeuristicScanPrecedence yes

# Enable the Data Loss Prevention module.
# Default: no
StructuredDataDetection yes

# This option sets the lowest number of Credit Card numbers found in a file
# to generate a detect.
# Default: 3
#StructuredMinCreditCardCount 5

# This option sets the lowest number of Social Security Numbers found
# in a file to generate a detect.
# Default: 3
#StructuredMinSSNCount 5

# With this option enabled the DLP module will search for valid
# SSNs formatted as xxx-yy-zzzz.
# Default: yes
#StructuredSSNFormatNormal yes

# With this option enabled the DLP module will search for valid
# SSNs formatted as xxxyyzzzz
# Default: no
#StructuredSSNFormatStripped no

# Perform HTML/JavaScript/ScriptEncoder normalisation and decryption.
# If you turn off this option, the original files will still be scanned, but
# without additional processing.
# Default: yes
ScanHTML yes

# This option enables scanning of OLE2 files, such as Microsoft Office
# documents and .msi files.
# If you turn off this option, the original files will still be scanned, but
# without additional processing.
# Default: yes
ScanOLE2 yes

# With this option enabled clamav will try to detect broken executables
# (PE, ELF, & Mach-O) and alert on them with a Broken.Executable heuristic signature.
# Default: no
AlertBrokenExecutables yes

# With this option enabled clamav will try to detect broken media files
# (JPEG, TIFF, PNG, GIF) and alert on them with a Broken.Media heuristic signature.
# Default: no
AlertBrokenMedia yes

# Alert on encrypted archives and documents (encrypted .zip, .7zip, .rar, .pdf).
# Default: no
AlertEncrypted yes

# With this option enabled the DLP module will search for valid Credit Card
# numbers only. Debit and Private Label cards will not be searched.
# Default: no
#StructuredCCOnly no

# Alert on encrypted archives (encrypted .zip, .7zip, .rar).
# Default: no
AlertEncryptedArchive yes

# Alert on encrypted documents (encrypted .pdf).
# Default: no
AlertEncryptedDoc yes

# With this option enabled OLE2 files with VBA macros, which were not
# detected by signatures will be marked as "Heuristics.OLE2.ContainsMacros".
# Default: no
AlertOLE2Macros yes

# Alert on SSL mismatches in URLs, even if they're not in the database.
# This feature can lead to false positives.
# Default: no
AlertPhishingSSLMismatch yes

# Alert on cloaked URLs, even if they're not in the database.
# This feature can lead to false positives.
# Default: no
AlertPhishingCloak yes

# Alert on raw DMG image files containing partition intersections.
# Default: no
AlertPartitionIntersection yes

# This option enables scanning within PDF files.
# If you turn off this option, the original files will still be scanned, but
# without decoding and additional processing.
# Default: yes
ScanPDF yes

# This option enables scanning within SWF files.
# If you turn off this option, the original files will still be scanned, but
# without decoding and additional processing.
# Default: yes
ScanSWF yes

# This option enables scanning xml-based document files supported by libclamav.
# If you turn off this option, the original files will still be scanned, but
# without additional processing.
# Default: yes
ScanXMLDOCS yes

# This option enables scanning HWP3 files.
# If you turn off this option, the original files will still be scanned, but
# without additional processing.
# Default: yes
ScanHWP3 yes

# Scan within archives and compressed files.
# If you turn off this option, the original files will still be scanned, but
# without unpacking and additional processing.
# Default: yes
ScanArchive yes

# This option causes memory or nested map scans to dump the content to disk.
# If you turn on this option, more data is written to disk and is available
# when the leave-temps option is enabled at the cost of more disk writes.
# Default: no
#ForceToDisk no

# This option sets the maximum amount of time a scan may take to complete.
# The value of 0 disables the limit.
# WARNING: disabling this limit or setting it too high may result allow scanning
# of certain files to lock up the scanning process/threads resulting in a Denial of Service.
# The value is in milliseconds.
# Default: 0
#MaxScanTime 120000

# This option sets the maximum amount of data to be scanned for each input file.
# Archives and other containers are recursively extracted and scanned up to this
# value.
# The value of 0 disables the limit.
# WARNING: disabling this limit or setting it too high may result in severe
# damage.
# !!! MaxScanSize: UNKNOWN INTERNAL TYPE !!!
#MaxScanSize 400M

# Files/messages larger than this limit won't be scanned. Affects the input
# file itself as well as files contained inside it (when the input file is
# an archive, a document or some other kind of container).
# The value of 0 disables the limit.
# WARNING: disabling this limit or setting it too high may result in severe
# damage to the system.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 104857600
#MaxFileSize 100M

# Nested archives are scanned recursively, e.g. if a Zip archive contains a RAR
# file, all files within it will also be scanned. This option specifies how
# deeply the process should be continued.
# The value of 0 disables the limit.
# WARNING: disabling this limit or setting it too high may result in severe
# damage to the system.
# Default: 17
#MaxRecursion 17

# Number of files to be scanned within an archive, a document, or any other
# container file.
# The value of 0 disables the limit.
# WARNING: disabling this limit or setting it too high may result in severe
# damage to the system.
# Default: 10000
#MaxFiles 10000

# This option sets the maximum size of a file to check for embedded PE.
# Files larger than this value will skip the additional analysis step.
# Negative values are not allowed.
# WARNING: setting this limit too high may result in severe damage or impact performance.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 41943040
#MaxEmbeddedPE 40M

# This option sets the maximum size of a HTML file to normalize.
# HTML files larger than this value will not be normalized or scanned.
# Negative values are not allowed.
# WARNING: setting this limit too high may result in severe damage or impact performance.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 41943040
#MaxHTMLNormalize 40M

# This option sets the maximum size of a normalized HTML file to scan.
# HTML files larger than this value after normalization will not be scanned.
# Negative values are not allowed.
# WARNING: setting this limit too high may result in severe damage or impact performance.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 8388608
#MaxHTMLNoTags 8M

# This option sets the maximum size of a script file to normalize.
# Script content larger than this value will not be normalized or scanned.
# Negative values are not allowed.
# WARNING: setting this limit too high may result in severe damage or impact performance.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 20971520
#MaxScriptNormalize 20M

# This option sets the maximum size of a ZIP file to reanalyze type recognition.
# ZIP files larger than this value will skip the step to potentially reanalyze as PE.
# Negative values are not allowed.
# WARNING: setting this limit too high may result in severe damage or impact performance.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 1048576
#MaxZipTypeRcg 1M

# This option sets the maximum number of partitions of a raw disk image to be scanned.
# Raw disk images with more partitions than this value will have up to the value number partitions scanned.
# Negative values are not allowed.
# WARNING: setting this limit too high may result in severe damage or impact performance.
# Default: 50
#MaxPartitions 128

# This option sets the maximum number of icons within a PE to be scanned.
# PE files with more icons than this value will have up to the value number icons scanned.
# Negative values are not allowed.
# WARNING: setting this limit too high may result in severe damage or impact performance.
# Default: 100
#MaxIconsPE 100

# This option sets the maximum recursive calls to HWP3 parsing function.
# HWP3 files using more than this limit will be terminated and alert the user.
# Scans will be unable to scan any HWP3 attachments if the recursive limit is reached.
# Negative values are not allowed.
# WARNING: setting this limit too high may result in severe damage or impact performance.
# Default: 16
#MaxRecHWP3 16

# This option sets the maximum calls to the PCRE match function during an instance of regex matching.
# Instances using more than this limit will be terminated and alert the user but the scan will continue.
# For more information on match_limit, see the PCRE documentation.
# Negative values are not allowed.
# WARNING: setting this limit too high may severely impact performance.
# Default: 100000
#PCREMatchLimit 100000

# This option sets the maximum recursive calls to the PCRE match function during an instance of regex matching.
# Instances using more than this limit will be terminated and alert the user but the scan will continue.
# For more information on match_limit_recursion, see the PCRE documentation.
# Negative values are not allowed and values > PCREMatchLimit are superfluous.
# WARNING: setting this limit too high may severely impact performance.
# Default: 2000
#PCRERecMatchLimit 5000

# This option sets the maximum filesize for which PCRE subsigs will be executed.
# Files exceeding this limit will not have PCRE subsigs executed unless a subsig is encompassed to a smaller buffer.
# Negative values are not allowed.
# Setting this value to zero disables the limit.
# WARNING: setting this limit too high or disabling it may severely impact performance.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 104857600
#PCREMaxFileSize 100M

# This option specifies a directory or mount point which should be scanned on access. The mount point specified, or the mount point containing the specified directory will be watched, but only notifications will occur. If any directories are specified, this option will preempt the DDD system. It can also be used multiple times.
# Default: disabled
#OnAccessMountPath /
# OnAccessMountPath /home

# This option specifies a directory (including all files and directories
# inside it), which should be scanned on access. This option can
# be used multiple times.
# Default: disabled
OnAccessIncludePath /home
#OnAccessIncludePath /students

# This option allows excluding directories from on-access scanning. It can
# be used multiple times. Only works with DDD system.
# Default: disabled
OnAccessExcludePath /home/excluded
#OnAccessExcludePath /root

# Use this option to exclude the root UID (0) and allow any processes run under root to access all watched files without triggering scans.
# Default: disabled
OnAccessExcludeRootUID yes

# With this option you can exclude specific UIDs. Processes with these UIDs
# will be able to access all files.
# This option can be used multiple times (one per line). Using a value of 0 on any line will disable this option entirely. To exclude the root UID please enable the OnAccessExcludeRootUID option.
# Default: disabled
OnAccessExcludeUID 0

# This option allows exclusions via user names when using the on-access scanning client. It can
# be used multiple times.
# Default: disabled
OnAccessExcludeUname clamav

# Files larger than this value will not be scanned in on access.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 5242880
#OnAccessMaxFileSize 5M

# This option toggles the dynamic directory determination system for on-access scanning (Linux only).
# Default: no
OnAccessDisableDDD no

# This option changes fanotify behavior to prevent access attempts on malicious files instead of simply notifying the user (On Access scan only).
# Default: no
OnAccessPrevention yes

# Enables extra scanning and notification after catching certain inotify events. Only works with the DDD system enabled.
# Default: no
OnAccessExtraScanning yes

# Max amount of time (in milliseconds) that the OnAccess client should spend for every connect, send, and recieve attempt when communicating with clamd via curl (5s default)
# Default: 5000
#OnAccessCurlTimeout 10000L

# Max number of scanning threads to allocate to the OnAccess thread pool at startup--these threads are the ones responsible for creating a connection with the daemon and kicking off scanning after an event has been processed. To prevent clamonacc from consuming all clamd's resources keep this lower than clamd's max threads. Default is 5
# Default: 5
#OnAccessMaxThreads 10

# Number of times the OnAccess client will retry a failed scan due to connection problems (or other issues). Defaults to no retries.
# Default: 0
#OnAccessRetryAttempts 3

# When using prevention, if this option is turned on, any errors that occur during scanning will result in the event attempt being denied. This could potentially lead to unwanted system behaviour with certain configurations, so the client defaults to off and allowing access events in case of error.
# Default: no
#OnAccessDenyOnError yes

# Disable authenticode certificate chain verification in PE files.
# Default: no
#DisableCertCheck no

# Deprecated option to enable heuristic alerts (e.g. "Heuristics.<sig name>")
# Default: yes
#AlgorithmicDetection no

# 
# Default: no
#BlockMax 

# Deprecated option to alert on SSL mismatches in URLs, even if they're not in the database.
# This feature can lead to false positives.
# Default: no
#PhishingAlwaysBlockSSLMismatch no

# Deprecated option to alert on cloaked URLs, even if they're not in the database.
# This feature can lead to false positives.
# Default: no
#PhishingAlwaysBlockCloak no

# Deprecated option to alert on raw DMG image files containing partition intersections.
# Default: no
#PartitionIntersection no

# With this option enabled OLE2 files with VBA macros, which were not
# detected by signatures will be marked as "Heuristics.OLE2.ContainsMacros".
# Default: no
#OLE2BlockMacros no

# Deprecated option to alert on encrypted archives and documents (encrypted .zip, .7zip, .rar, .pdf).
# Default: no
#ArchiveBlockEncrypted no

まずは構成ファイルを有効化するため、Example を削除します。

# Comment out or remove the line below.
Example

AlertExceedsMax はデフォルト値の no の設定のまま使用します。

# Default: no
#AlertExceedsMax

AlertExceedsMax は本記事執筆時点(2024 年 1 月)で有効に動作しない Bug が存在することが Open 中の issue にて言及されています。

参考:clamd.conf AlertExceedsMax true not working · Issue #633 · Cisco-Talos/clamav

次の CacheSize は一応設定を明示的に追加しますが、デフォルト値をそのまま使用します。

# Number of entries the cache can store.
# Default: 65536
# CacheSize 65536

Prelude SIEM は使用しないので、関連する設定は無効化したままとします。

参考:ClamAV® blog: ClamAV 0.100.0 has been released!

ログ関連の設定は以下の通りとしました。

LogFile については /var/log/clamav.log にパスを変更しておきます。

そして LogFileUnlock を yes とし、LogFileMaxSize を 5 MB に変更します。

また、LogVerbose と LogRotate 、ExtendedDetectionInfo も有効化しています。

# Save all reports to a log file.
# Default: disabled
LogFile /var/log/clamav.log

# By default the log file is locked for writing and only a single
# daemon process can write to it. This option disables the lock.
# Default: no
LogFileUnlock yes

# Maximum size of the log file.
# Value of 0 disables the limit.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 1048576
LogFileMaxSize 5M

# Log time with each message.
# Default: no
LogTime yes

# Log all clean files.
# Useful in debugging but drastically increases the log size.
# Default: no
LogClean no

# Use the system logger (can work together with LogFile).
# Default: no
LogSyslog yes

# Type of syslog messages.
# Please refer to 'man syslog' for the facility names.
# Default: LOG_LOCAL6
#LogFacility LOG_MAIL

# Enable verbose logging.
# Default: no
LogVerbose yes

# Rotate log file. Requires LogFileMaxSize option set prior to this option.
# Default: no
LogRotate yes

# Log additional information about the infected file, such as its
# size and hash, together with the virus name.
# Default: no
ExtendedDetectionInfo yes

PidFile は一応有効化しておきます。

# Save the process ID to a file.
# Default: disabled
PidFile /run/clamav/clam.pid

続く設定はいずれも既定値のままですが、DatabaseDirectory を flashclam で設定した /usr/local/share/clamav に指定しています。

# This option allows you to change the default temporary directory.
# Default: disabled
TemporaryDirectory /tmp

# This option allows you to change the default database directory.
# If you enable it, please make sure it points to the same directory in
# both clamd and freshclam.
# Default: /usr/local/share/clamav
DatabaseDirectory /usr/local/share/clamav

# Only load the official signatures published by the ClamAV project.
# Default: no
OfficialDatabaseOnly no

また、LocalSocket の設定は無効化したまま、TCPSocket を有効化することにします。

これで、clamd が 127.0.0.1 の 3310 ポートを使用できるようになります。

# A TCP port number the daemon will listen on.
# Default: disabled
TCPSocket 3310

# By default clamd binds to INADDR_ANY.
# This option allows you to restrict the TCP address and provide
# some degree of protection from the outside world.
# Default: disabled
TCPAddr 127.0.0.1

# Maximum length the queue of pending connections may grow to.
# Default: 200
MaxConnectionQueueLength 200

# Close the STREAM session when the data size limit is exceeded.
# The value should match your MTA's limit for the maximum attachment size.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 104857600
StreamMaxLength 100M

# The STREAM command uses an FTP-like protocol.
# This option sets the lower boundary for the port range.
# Default: 1024
StreamMinPort 1024

# This option sets the upper boundary for the port range.
# Default: 2048
StreamMaxPort 2048

# Maximum number of threads running at the same time.
# Default: 10
MaxThreads 20

# This option specifies the time (in seconds) after which clamd should
# timeout if a client doesn't provide any data.
# Default: 120
ReadTimeout 120

# This option specifies the time (in seconds) after which clamd should
# timeout if a client doesn't provide any initial command after connecting.
# Default: 30
CommandReadTimeout 30

# This option specifies how long to wait (in milliseconds) if the send buffer
# is full. Keep this value low to prevent clamd hanging.
# Default: 500
SendBufTimeout 200

MaxQueue と IdleTimeout を既定値から変えておきます。

# Maximum number of queued items (including those being processed by MaxThreads
# threads). It is recommended to have this value at least twice MaxThreads
# if possible.
# WARNING: you shouldn't increase this too much to avoid running out of file
#  descriptors, the following condition should hold:
#  MaxThreads*MaxRecursion + MaxQueue - MaxThreads  + 6 < RLIMIT_NOFILE
#  (usual max for RLIMIT_NOFILE is 1024)
# 
# Default: 100
MaxQueue 200

# This option specifies how long (in seconds) the process should wait
# for a new job.
# Default: 30
IdleTimeout 60

ExcludePath にはとりあえず以下の 3 つを指定します。

# Don't scan files/directories whose names match the provided
# regular expression. This option can be specified multiple times.
# Default: disabled
ExcludePath ^/proc/
ExcludePath ^/sys/
ExcludePath ^/run/

MaxDirectoryRecursion については既定値のまま、FollowDirectorySymlinks と FollowFileSymlinks は有効化しています。

# Maximum depth the directories are scanned at.
# Default: 15
MaxDirectoryRecursion 15

# Follow directory symlinks.
# Default: no
FollowDirectorySymlinks yes

# Follow symlinks to regular files.
# Default: no
FollowFileSymlinks yes

# Scan files and directories on other filesystems.
# Default: yes
CrossFilesystems yes

# This option specifies the time intervals (in seconds) in which clamd
# should perform a database check.
# Default: 600
SelfCheck 600

続く設定は既定値のままとし、Foreground と Debug を有効化します。

# Don't fork into background.
# Default: no
Foreground yes

# Enable debug messages in libclamav.
# Default: no
Debug yes

# Don't remove temporary files (for debugging purposes).
# Default: no
LeaveTemporaryFiles no

# Record metadata about the file being scanned.
# Scan metadata is useful for file analysis purposes and for debugging scan behavior.
# The JSON metadata will be printed after the scan is complete if Debug is enabled.
# A metadata.json file will be written to the scan temp directory if LeaveTemporaryFiles is enabled.
# Default: no
# GenerateMetadataJson yes

デーモンユーザを root にすることは非推奨らしいので、今回は clamav をユーザとして指定します。

# Run the daemon as a specified user (the process must be started by root).
# Default: disabled
User clamav

また、BytecodeSecurity は Paranoid に変更し、BytecodeUnsigned も有効化しておきます。

# With this option enabled ClamAV will load bytecode from the database. It is highly recommended you keep this option on, otherwise you'll miss detections for many new viruses.
# Default: yes
Bytecode yes

# Set bytecode security level.
# Possible values:
# 	TrustSigned - trust bytecode loaded from signed .c[lv]d files,
# 		 insert runtime safety checks for bytecode loaded from other sources
# 	Paranoid - don't trust any bytecode, insert runtime checks for all
# Recommended: TrustSigned, because bytecode in .cvd files already has these checks.
# Default: TrustSigned
BytecodeSecurity Paranoid

# Set bytecode timeout in milliseconds.
# Default: 10000
BytecodeTimeout 10000

# Allow loading bytecode from outside digitally signed .c[lv]d files.
# Default: no
BytecodeUnsigned yes

# Set bytecode execution mode.
# Possible values:
# 	Auto - automatically choose JIT if possible, fallback to interpreter
# ForceJIT - always choose JIT, fail if not possible
# ForceInterpreter - always choose interpreter
# Test - run with both JIT and interpreter and compare results. Make all failures fatal.
# Default: Auto
BytecodeMode Auto

PUA スキャンを有効化し、対象も適当に設定しておきます。

IncludePUA と ExcludePUA を同時に設定すると clamd 起動時に ExcludePUA and IncludePUA cannot be used at the same time のエラーが発生します。

# Detect Potentially Unwanted Applications.
# Default: no
DetectPUA yes

# Exclude a specific PUA category. This directive can be used multiple times.
# See https://docs.clamav.net/faq/faq-pua.html for the complete list of PUA
# categories.
# Default: disabled
#ExcludePUA NetTool
#ExcludePUA PWTool

# Only include a specific PUA category. This directive can be used multiple
# times.
# Default: disabled
IncludePUA Spy
IncludePUA Scanner
IncludePUA RAT
IncludePUA NetTool
IncludePUA PWTool

各種ターゲットのスキャン設定を有効化します。

ただし、ScanMail と ScanPartialMessages は無効化しておきます。

# PE stands for Portable Executable - it's an executable file format used
# in all 32- and 64-bit versions of Windows operating systems. This option
# allows ClamAV to perform a deeper analysis of executable files and it's also
# required for decompression of popular executable packers such as UPX or FSG.
# If you turn off this option, the original files will still be scanned, but
# without additional processing.
# Default: yes
ScanPE yes

# Executable and Linking Format is a standard format for UN*X executables.
# This option allows you to control the scanning of ELF files.
# If you turn off this option, the original files will still be scanned, but
# without additional processing.
# Default: yes
ScanELF yes

# Enable the built in email scanner.
# If you turn off this option, the original files will still be scanned, but
# without parsing individual messages/attachments.
# Default: yes
ScanMail no

# Scan RFC1341 messages split over many emails. You will need to
# periodically clean up $TemporaryDirectory/clamav-partial directory.
# WARNING: This option may open your system to a DoS attack. Please don't use
# this feature on highly loaded servers.
# Default: no
ScanPartialMessages no

# With this option enabled ClamAV will try to detect phishing attempts by using
# signatures.
# Default: yes
PhishingSignatures yes

# Scan URLs found in mails for phishing attempts using heuristics.
# Default: yes
PhishingScanURLs yes

# In some cases (eg. complex malware, exploits in graphic files, and others),
# ClamAV uses special algorithms to provide accurate detection. This option
# controls the algorithmic detection.
# Default: yes
HeuristicAlerts yes

# Allow heuristic match to take precedence.
# When enabled, if a heuristic scan (such as phishingScan) detects
# a possible virus/phish it will stop scan immediately. Recommended, saves CPU
# scan-time.
# When disabled, virus/phish detected by heuristic scans will be reported only
# at the end of a scan. If an archive contains both a heuristically detected
# virus/phish, and a real malware, the real malware will be reported.
# Keep this disabled if you intend to handle "Heuristics.*" viruses
# differently from "real" malware.
# If a non-heuristically-detected virus (signature-based) is found first,
# the scan is interrupted immediately, regardless of this config option.
# Default: no
HeuristicScanPrecedence yes

どういう動きになるかいまいちわかってないですが、DLP も有効化しておきます。

関連する設定は既定値のままとします。

# Enable the Data Loss Prevention module.
# Default: no
StructuredDataDetection yes

# This option sets the lowest number of Credit Card numbers found in a file
# to generate a detect.
# Default: 3
#StructuredMinCreditCardCount 5

# This option sets the lowest number of Social Security Numbers found
# in a file to generate a detect.
# Default: 3
#StructuredMinSSNCount 5

# With this option enabled the DLP module will search for valid
# SSNs formatted as xxx-yy-zzzz.
# Default: yes
#StructuredSSNFormatNormal yes

# With this option enabled the DLP module will search for valid
# SSNs formatted as xxxyyzzzz
# Default: no
#StructuredSSNFormatStripped no

こちらも既定値のままですが、HTML と OLE2 のスキャンを有効化しておきます。

さらに、PDF やアーカイブファイルなど、複数の設定を有効化します。

# Perform HTML/JavaScript/ScriptEncoder normalisation and decryption.
# If you turn off this option, the original files will still be scanned, but
# without additional processing.
# Default: yes
ScanHTML yes

# This option enables scanning of OLE2 files, such as Microsoft Office
# documents and .msi files.
# If you turn off this option, the original files will still be scanned, but
# without additional processing.
# Default: yes
ScanOLE2 yes

***

# This option enables scanning within PDF files.
# If you turn off this option, the original files will still be scanned, but
# without decoding and additional processing.
# Default: yes
ScanPDF yes

# This option enables scanning within SWF files.
# If you turn off this option, the original files will still be scanned, but
# without decoding and additional processing.
# Default: yes
ScanSWF yes

# This option enables scanning xml-based document files supported by libclamav.
# If you turn off this option, the original files will still be scanned, but
# without additional processing.
# Default: yes
ScanXMLDOCS yes

# This option enables scanning HWP3 files.
# If you turn off this option, the original files will still be scanned, but
# without additional processing.
# Default: yes
ScanHWP3 yes

# Scan within archives and compressed files.
# If you turn off this option, the original files will still be scanned, but
# without unpacking and additional processing.
# Default: yes
ScanArchive yes

AlertBrokenExecutables、AlertBrokenMedia、そして AlertEncrypted を有効化します。

# With this option enabled clamav will try to detect broken executables
# (PE, ELF, & Mach-O) and alert on them with a Broken.Executable heuristic signature.
# Default: no
AlertBrokenExecutables yes

# With this option enabled clamav will try to detect broken media files
# (JPEG, TIFF, PNG, GIF) and alert on them with a Broken.Media heuristic signature.
# Default: no
AlertBrokenMedia yes

# Alert on encrypted archives and documents (encrypted .zip, .7zip, .rar, .pdf).
# Default: no
AlertEncrypted yes

過検出が増える懸念はありますが、以下の設定もすべて有効化します。

# Alert on encrypted archives (encrypted .zip, .7zip, .rar).
# Default: no
AlertEncryptedArchive yes

# Alert on encrypted documents (encrypted .pdf).
# Default: no
AlertEncryptedDoc yes

# With this option enabled OLE2 files with VBA macros, which were not
# detected by signatures will be marked as "Heuristics.OLE2.ContainsMacros".
# Default: no
AlertOLE2Macros yes

# Alert on SSL mismatches in URLs, even if they're not in the database.
# This feature can lead to false positives.
# Default: no
AlertPhishingSSLMismatch yes

# Alert on cloaked URLs, even if they're not in the database.
# This feature can lead to false positives.
# Default: no
AlertPhishingCloak yes

# Alert on raw DMG image files containing partition intersections.
# Default: no
AlertPartitionIntersection yes

# This option enables scanning within PDF files.
# If you turn off this option, the original files will still be scanned, but
# without decoding and additional processing.
# Default: yes
ScanPDF yes

# This option enables scanning within SWF files.
# If you turn off this option, the original files will still be scanned, but
# without decoding and additional processing.
# Default: yes
ScanSWF yes

# This option enables scanning xml-based document files supported by libclamav.
# If you turn off this option, the original files will still be scanned, but
# without additional processing.
# Default: yes
ScanXMLDOCS yes

# This option enables scanning HWP3 files.
# If you turn off this option, the original files will still be scanned, but
# without additional processing.
# Default: yes
ScanHWP3 yes

# Scan within archives and compressed files.
# If you turn off this option, the original files will still be scanned, but
# without unpacking and additional processing.
# Default: yes
ScanArchive yes

以降のスキャン制限に関する設定値はデフォルトのまま使用するので特に変更しません。

ただし、以下の行だけは、clamd 起動時に parse エラーを引き起こすため、コメントアウトしておきます。

# This option sets the maximum amount of data to be scanned for each input file.
# Archives and other containers are recursively extracted and scanned up to this
# value.
# The value of 0 disables the limit.
# WARNING: disabling this limit or setting it too high may result in severe
# damage.
!!! MaxScanSize: UNKNOWN INTERNAL TYPE !!!
#MaxScanSize 400M

続く OnAccessScan の構成では、OnAccessMountPath を既定値の Disabled のままとします。

OnAccessMountPath は OnAccessScan で監視するファイルシステムのマウントポイントを指定することができますが、Dynamic Directory Determination(DDD) システムとは異なる fanotify 構成を使用するため、DDD との互換性がなくなります。

つまり、OnAccessExtraScanning などのオプションを有効化できなくなります。

諸々の使いやすさなどを考慮し、今回は以下の設定で OnAccessScan を構成しました。

# This option specifies a directory or mount point which should be scanned on access. The mount point specified, or the mount point containing the specified directory will be watched, but only notifications will occur. If any directories are specified, this option will preempt the DDD system. It can also be used multiple times.
# Default: disabled
#OnAccessMountPath /
# OnAccessMountPath /home

# This option specifies a directory (including all files and directories
# inside it), which should be scanned on access. This option can
# be used multiple times.
# Default: disabled
OnAccessIncludePath /home
#OnAccessIncludePath /students

# This option allows excluding directories from on-access scanning. It can
# be used multiple times. Only works with DDD system.
# Default: disabled
OnAccessExcludePath /home/excluded
#OnAccessExcludePath /root

# Use this option to exclude the root UID (0) and allow any processes run under root to access all watched files without triggering scans.
# Default: disabled
OnAccessExcludeRootUID yes

# With this option you can exclude specific UIDs. Processes with these UIDs
# will be able to access all files.
# This option can be used multiple times (one per line). Using a value of 0 on any line will disable this option entirely. To exclude the root UID please enable the OnAccessExcludeRootUID option.
# Default: disabled
OnAccessExcludeUID 0

# This option allows exclusions via user names when using the on-access scanning client. It can
# be used multiple times.
# Default: disabled
OnAccessExcludeUname clamav

# Files larger than this value will not be scanned in on access.
# You may use 'M' or 'm' for megabytes (1M = 1m = 1048576 bytes)
# and 'K' or 'k' for kilobytes (1K = 1k = 1024 bytes). To specify the size
# in bytes just don't use modifiers.
# Default: 5242880
#OnAccessMaxFileSize 5M

# This option toggles the dynamic directory determination system for on-access scanning (Linux only).
# Default: no
OnAccessDisableDDD no

# This option changes fanotify behavior to prevent access attempts on malicious files instead of simply notifying the user (On Access scan only).
# Default: no
OnAccessPrevention yes

# Enables extra scanning and notification after catching certain inotify events. Only works with the DDD system enabled.
# Default: no
OnAccessExtraScanning yes

参考:On-Access Scanning - ClamAV Documentation

参考:ClamAVによるリアルタイムスキャンの設定 | 稲葉サーバーデザイン

最後に、clamd コマンドを実行してデーモンを起動した後、clamonacc を実行すれば OK です。

# デーモンの起動(User の設定によって、デーモンの実行ユーザが clamav になる)
clamd

# fds_poll_recv: timeout after 600 seconds が表示されたら実行
clamonacc

image-20240128225355498

参考:Scanning - ClamAV Documentation

実際に OnAccessScan で Eicar ファイルがブロックされたことを確認できます。

image-20240128231345106

また、ついでに clamscan コマンドでも検知テストを実行してみたところ、こちらでも Eicar ファイルの検出に成功しました。

image-20240128230756961

デバッグと Systemd を有効化して再ビルドする

とりあえず一通りの設定ができたので、最後に Debug モードと Systemd を有効化して ClamAV を再ビルドしてみます。

cmake .. \
    -D CMAKE_BUILD_TYPE=Debug \
    -D OPTIMIZE=OFF \
    -D ENABLE_EXAMPLES=OFF \
    -D ENABLE_STATIC_LIB=ON \
    -D ENABLE_SYSTEMD=ON
cmake --build . --target install

参考:Unix from source (v0.104+) - ClamAV Documentation

ビルドとインストールが完了すると、Unit ファイルは既定で /lib/systemd/system 直下に作成されます。

それぞれ以下のような内容になっています。

$ cat /lib/systemd/system/clamav-daemon.service

[Unit]
Description=Clam AntiVirus userspace daemon
Documentation=man:clamd(8) man:clamd.conf(5) https://docs.clamav.net/
# Check for database existence
ConditionPathExistsGlob=/var/lib/clamav/main.{c[vl]d,inc}
ConditionPathExistsGlob=/var/lib/clamav/daily.{c[vl]d,inc}

[Service]
ExecStart=/usr/local/sbin/clamd --foreground=true
# Reload the database
ExecReload=/bin/kill -USR2 $MAINPID
StandardOutput=syslog
TimeoutStartSec=420

[Install]
WantedBy=multi-user.target
$ cat /lib/systemd/system/clamav-freshclam.service 
[Unit]
Description=ClamAV virus database updater
Documentation=man:freshclam(1) man:freshclam.conf(5) https://docs.clamav.net/
# If user wants it run from cron, don't start the daemon.
ConditionPathExists=!/etc/cron.d/clamav-freshclam
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/usr/local/bin/freshclam -d --foreground=true
StandardOutput=syslog

[Install]
WantedBy=multi-user.target

実際に以下のコマンドで clamd と freshclam の自動起動を有効化してから OS を再起動すると、以下の通り各デーモンが自動起動していることがわかります。

※ 起動時にデータベースファイルが存在していない場合 clamd の起動は ConditionPathExistsGlob=/var/lib/clamav/daily.{c[vl]d,inc} was not met のようなメッセージとともに失敗するので、freshclam を事前に実行しておくと良いです。

sudo systemctl enable clamav-daemon.service
sudo systemctl enable clamav-freshclam.service 

ただし、Unit ファイルの設定を見てもわかる通り、このままでは clamonacc は自動起動されず、OnAccessScan は使用できません。

image-20240129231359522

そこで、/lib/systemd/system/clamav-clamonacc.service として以下の Unit ファイルを手動で作成し、こちらも自動起動設定を行います。(/quarantine が存在しない場合は事前に作成しておきます。)

[Unit]
Description=ClamAV On Access Scanner
Requires=clamav-daemon.service
After=clamav-daemon.service syslog.target network.target

[Service]
Type=simple
User=root
ExecStart=/usr/local/sbin/clamonacc -F --fdpass --config-file=/usr/local/etc/clamd.conf --move=/quarantine
Restart=on-failure
RestartSec=20s

[Install]
WantedBy=multi-user.target

これで、sudo systemctl enable clamav-clamonacc.service コマンドで自動起動設定を入れて OS を再起動します。

OS の起動後、20 秒から 60 秒程度待つと、clamonacc が自動起動することを確認できます。

image-20240129232158799

これで Eicar ファイルを操作するとアクセスがブロックされ、隔離ディレクトリに Eicar ファイルが(生のまま!)配置されていることがわかります。

image-20240129232257243

検知時の通知を設定する

せっかくなので、ClamAV が Malware を検知した際にユーザに通知を発生させるようにしてみます。

作成した clamconf -g clamd.conf > /usr/local/etc/clamd.conf で VirusEvent オプションを有効化します。

# Execute a command when a virus is found. In the command string %v will be
# replaced with the virus name and %f will be replaced with the file name.
# Additionally, two environment variables will be defined: $CLAM_VIRUSEVENT_FILENAME
# and $CLAM_VIRUSEVENT_VIRUSNAME.
# Default: disabled
#VirusEvent /usr/bin/mailx -s "ClamAV VIRUS ALERT: %v" alert < /dev/null
VirusEvent /etc/clamav/virus-event.bash

続いて、/etc/clamav/virus-event.bash を作成して以下のスクリプトを埋め込み、chmod +x /etc/clamav/virus-event.bash コマンドで実行権限を付与します。

#!/bin/bash
PATH=/usr/bin
ALERT="Signature detected by clamav: $CLAM_VIRUSEVENT_VIRUSNAME in $CLAM_VIRUSEVENT_FILENAME"

# Send an alert to all graphical users.
for ADDRESS in /run/user/*; do
    USERID=${ADDRESS#/run/user/}
    /usr/bin/sudo -u "#$USERID" DBUS_SESSION_BUS_ADDRESS="unix:path=$ADDRESS/bus" PATH=${PATH} \
        /usr/bin/notify-send -i dialog-warning "Virus found!" "$ALERT"
done

参考:ClamAV - ArchWiki

これで、ClamAV による検知時に GUI ユーザに通知を送信できるようになりました。

image-20240129233153867

まとめ

とりあえず ClamAV のソースコードを読んでいくために一通りのセットアップと動作確認を試してみました。

ClamAV をまともに運用するのは中々骨が折れそうに感じました。