コンテンツにスキップ
macOS (Apple Silicon) に ClamAV を入れて自分のホームをまるごとスキャンする

macOS (Apple Silicon) に ClamAV を入れて自分のホームをまるごとスキャンする

2026年5月10日

ClamAV は商用 AV と違って 自分のマシンで何が起きているか可視化しやすい のが面白い。 Apple Silicon の Mac (M1/M2/M3) で brew install から ホームディレクトリのフルスキャン完了 までを実機で走らせ、所要時間と途中で詰まった点を全部記録した。

検証環境は次のとおり。

項目
OSmacOS 26.3.1 (Tahoe / Build 25D771280a)
CPUApple Silicon (arm64)
Homebrew/opt/homebrew (Apple Silicon 配置)
ClamAV1.5.2 (bottle)
ホーム合計286 GB (うち Parallels 117 GB / Library 102 GB)

Intel Mac の人は Homebrew のパスが /usr/local になるので、本記事中の /opt/homebrew/.../usr/local/... に読み替えてください。

1. インストール (実測 14 秒)

brew install clamav

依存込みで bottle が落ちてきた。

==> Installing clamav dependency: libmagic
🍺  /opt/homebrew/Cellar/libmagic/5.47: 367 files, 13MB
==> Installing clamav dependency: yara
🍺  /opt/homebrew/Cellar/yara/4.5.5: 49 files, 2.4MB
==> Installing clamav
🍺  /opt/homebrew/Cellar/clamav/1.5.2: 181 files, 57.8MB

brew install clamav  8.52s user 4.40s system 90% cpu 14.227 total

合計 73 MB。libmagicyara が一緒に入るのは ClamAV のシグネチャに YARA ルールが使われるから。

brew info の Caveats が大事で、設定ファイルは .sample 拡張子で置かれている だけ。コピーして編集しないと freshclamclamscan も動かない。

To finish installation & run clamav you will need to edit
the example conf files at /opt/homebrew/etc/clamav/

2. 設定ファイルを生成する (ハマりポイント)

freshclam.conf.sample をコピーするだけでは動かない。サンプルの 8 行目に Example という単語だけの行があり、これは「設定ファイルがそのままサンプルだから読み込みを拒否する」というセーフティ機構。コメントアウトしないと freshclam がエラーを吐く。

ついでに、デフォルトの DB / ログ パスは Linux 前提で /var/lib/clamav/var/log/freshclam.log を指している。macOS では Homebrew 配下に揃えたほうが整理できる。

# サンプルをコピー
cp /opt/homebrew/etc/clamav/freshclam.conf.sample \
   /opt/homebrew/etc/clamav/freshclam.conf

# Example 行をコメントアウト & パスを Homebrew 配下に
sed -i '' \
  -e 's/^Example$/#Example/' \
  -e 's|^#DatabaseDirectory /var/lib/clamav|DatabaseDirectory /opt/homebrew/var/lib/clamav|' \
  -e 's|^#UpdateLogFile /var/log/freshclam.log|UpdateLogFile /opt/homebrew/var/log/freshclam.log|' \
  -e 's|^#LogTime yes|LogTime yes|' \
  /opt/homebrew/etc/clamav/freshclam.conf

# 受け皿ディレクトリを作る (これを忘れると Permission denied)
mkdir -p /opt/homebrew/var/lib/clamav /opt/homebrew/var/log

diff で見るとサンプルからの変更はこれだけ。

< Example
> #Example
< #DatabaseDirectory /var/lib/clamav
> DatabaseDirectory /opt/homebrew/var/lib/clamav
< #UpdateLogFile /var/log/freshclam.log
> UpdateLogFile /opt/homebrew/var/log/freshclam.log
< #LogTime yes
> LogTime yes

3. 定義 DB の取得 — freshclam (実測 10 秒)

freshclam

出力 (一部抜粋)。

ClamAV update process started at Sun May 10 22:05:34 2026
daily database available for download (remote version: 27996)
ERROR: NULL X509 store
ERROR: NULL X509 store
Testing database: '.../tmp.../daily.cvd' ...
Database test passed.
daily.cvd updated (version: 27996, sigs: 355446, f-level: 90, ...)
main database available for download (remote version: 63)
ERROR: NULL X509 store
ERROR: NULL X509 store
main.cvd updated (version: 63, sigs: 3287027, ...)
bytecode database available for download (remote version: 339)
ERROR: NULL X509 store
ERROR: NULL X509 store
bytecode.cvd updated (version: 339, sigs: 80, ...)

freshclam  4.58s user 0.95s system 52% cpu 10.504 total

落ちてきた DB はこの通り。

ファイルサイズシグネチャ数
main.cvd85 MB3,287,027
daily.cvd22 MB355,446
bytecode.cvd275 KB80

合計 約 107 MB / 約 364 万シグネチャ。これに加えて *.cvd.sign 署名ファイルが 9 KB ずつ。

ERROR: NULL X509 store の正体

ClamAV 1.5 系から CVD に X.509 証明書ベースの追加検証が入ったが、macOS ビルド (Homebrew bottle) では証明書ストアの初期化に失敗してこの ERROR が出る のが既知挙動。 Database test passed. が直後に出ていて DB 自体の SHA / FP 検証は通っているので、実害はない (*.cvd は別経路で改ざん検知されている)。 ただしログに ERROR の文字列が並ぶので、CI 等で固定文字列を grep していると false alarm になる。手動で気にしなくていいが、自動監視のフィルタはこのパターンを除外しておくと良い

4. 動作確認に EICAR テストファイルを置く

EICAR (European Institute for Computer Antivirus Research) のテスト文字列は AV ベンダ全社が「無害だが必ず検出する」という運用合意のあるシグネチャ。本物のマルウェアを使わずに動作確認できる。

mkdir -p ~/clamav-test
printf 'X5O!P%%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' \
  > ~/clamav-test/eicar.com

clamscan ~/clamav-test/eicar.com
/Users/user/clamav-test/eicar.com: Eicar-Test-Signature FOUND

----------- SCAN SUMMARY -----------
Known viruses: 3627854
Engine version: 1.5.2
Scanned files: 1
Infected files: 1
Data scanned: 68 B
Time: 7.760 sec (0 m 7 s)

68 バイトのファイル 1 件で 7.76 秒。これがほぼ全部 エンジン起動 + DB ロード時間。 スキャン本体ではなく初期化が重いので、たくさんの呼び出しを直列に走らせるユースケースでは clamd (常駐デーモン) + clamdscan を使ったほうが圧倒的に速い。今回は単発のフルスキャンが目的なので clamscan のままで進める。

5. ホームディレクトリのフルスキャン

du -sh ~ で見ると 286 GB。この内訳が問題で、

117G  /Users/user/Parallels       # 仮想マシンのディスクイメージ
102G  /Users/user/Library         # アプリ データ / キャッシュ / コンテナ
 13G  /Users/user/Documents
8.7G  /Users/user/.cache
 7G   /Users/user/go
6.7G  /Users/user/.ollama

Parallels の VM ディスク (117 GB) と Library/CachesLibrary/Containers 系を除外 することにした。理由は次の3つ。

  1. VM ディスクは .hdd バンドル内部にゲスト OS の全データが入っており、ClamAV はそこを再帰的に展開してスキャンしようとする。これは「自分の Mac をスキャンしたい」というスコープから完全に外れる
  2. Library/Containers 配下は macOS の Sandbox/TCC 制御対象 で、フルディスクアクセス権限を clamscan プロセスに付与していない限り Permission denied の山になる。出力ノイズが膨大
  3. Library/Caches は内容が常に揺れる。スキャン中に消えるファイルが大量に発生し、Can't open file 警告が大量に出る

商用 AV 製品 (Sophos, ESET 等) は Apple の Endpoint Security フレームワークで権限を持つので Container の中も読めるが、Homebrew 版 ClamAV は普通のユーザ権限で動く。tccutil で許可を渡すこともできるが、本記事では「素の状態」を優先した。

実行コマンド。

nohup clamscan -r -i \
  --max-filesize=100M \
  --max-scansize=400M \
  --exclude-dir='^/Users/user/Parallels' \
  --exclude-dir='^/Users/user/Library/Caches' \
  --exclude-dir='^/Users/user/Library/Containers' \
  --exclude-dir='^/Users/user/Library/Group Containers' \
  /Users/user > ~/clamav-test/logs/home-scan.log 2>&1 &

オプションの意味。

オプション意味
-r再帰的にディレクトリを下る
-i感染ファイルのみ表示 (クリーン ファイルのログを抑制)
--max-filesize=100M100MB を超えるファイルはスキップ。VM ディスクや動画など
--max-scansize=400M1ファイルから展開される総量がこれを超えたら打ち切る (圧縮爆弾対策)
--exclude-dir='^...'パス先頭一致で除外

実行中の様子。

PID 55770, 98% CPU (single-thread)
RSS 341 MB → 220 MB (DB ロード後はメモリ常駐)

ClamAV は シングルスレッドのスキャナ。マルチコアの恩恵を得るには clamdscan で並列化するか、clamscan を複数同時起動して対象を分割するしかない。

スキャン結果 — 74 分でディスク フル落ち

ここが今回いちばん書きたかったところで、SCAN SUMMARY が出ないまま終わった。プロセスは生きていたまま clamscan 自身がエラーを吐き続けて止まった、というのが正確な顛末。

ログ末尾はこんな感じ。

LibClamAV Error: cli_gentempfd_with_prefix: Can't create temporary file
  /var/folders/c2/.../T//clamav-46bbf1b1...tmp: No space left on device
LibClamAV Error: cli_gentempfd_with_prefix: Can't create temporary file
  /var/folders/c2/.../T//clamav-e26d2bb7...tmp: No space left on device
... (以下、`No space left on device` が延々と続く)
LibClamAV Warning: cli_unzip: failed to create temporary file ...

スキャン開始前のディスク空きが 3.2 GB しかなかったのが原因。 ClamAV はアーカイブ (zip / xz / tar / Office 文書 / .ipa / .apk / Mach-O Universal Binary など) を $TMPDIR 配下に展開してからスキャンする。286 GB のホームを舐めると、Go モジュール キャッシュ・npm キャッシュ・Xcode の中間ビルド成果物・Docker レイヤなど 無数の中規模アーカイブが順に展開され、温度の温まったテンポラリで空きが押し切られた

ClamAV 本体のメモリは ~200 MB で問題なかったが、$TMPDIR の使い方は派手なので Mac だと特に注意。回避策は次のいずれか。

  • clamscan --tempdir=/path/to/spacious/volume で別ボリュームを指定 (外付け SSD など)
  • --scan-archive=no でアーカイブ展開を一切やらない (速いが、暗号化・難読化済みアーカイブ内のマルウェアを見逃す)
  • --max-files=N --max-recursion=N で深さ制限
  • スキャン前に du -sh $TMPDIR を確認、最低でも 20 GB 以上の空きを確保

実際に検出された 7 件

74 分の間に拾われたヒットはこの 7 件。

~/go/pkg/mod/cache/download/github.com/klauspost/compress/@v/v1.18.2.zip:
    Heuristics.Zip.OverlappingFiles FOUND
~/go/pkg/mod/cache/download/github.com/klauspost/compress/@v/v1.18.3.zip:
    Heuristics.Zip.OverlappingFiles FOUND
~/go/pkg/mod/github.com/klauspost/compress@v1.18.2/zip/testdata/FuzzReader-raw.zip:
    Heuristics.Zip.OverlappingFiles FOUND
~/go/pkg/mod/github.com/klauspost/compress@v1.18.3/zip/testdata/FuzzReader-raw.zip:
    Heuristics.Zip.OverlappingFiles FOUND
~/go/pkg/mod/cache/download/github.com/vulncheck-oss/go-exploit/@v/v1.51.0.zip:
    Txt.Backdoor.MetasploitPayload-9874938-0 FOUND
~/go/pkg/mod/github.com/vulncheck-oss/go-exploit@v1.51.0/payload/bindshell/bindshell_test.go:
    Txt.Backdoor.MetasploitPayload-9874938-0 FOUND
~/clamav-test/eicar.com:
    Eicar-Test-Signature FOUND

カテゴリ別に意味を読むと、

  1. Eicar-Test-Signature (1件): 自分で置いたテスト ファイル。期待通り
  2. Heuristics.Zip.OverlappingFiles (4件): klauspost/compress (Go の zip 高速実装) のテスト フィクスチャ。ヒューリスティックであって YARA / 既知ハッシュ ベースの検出ではない。「ZIP のローカル ヘッダがオーバラップしている = ZIP 仕様の隙を突いた構造」という、まさに klauspost/compress がフェイルセーフ実装をテストしたい対象そのもの。完全に正当
  3. Txt.Backdoor.MetasploitPayload-9874938-0 (2件): vulncheck-oss/go-exploit という 正規の脆弱性検証ライブラリ に含まれる Metasploit ペイロード サンプル文字列を検出。シグネチャ ベースなので、これも当然のヒット

つまり 7 件すべて誤検出 (false positive) または意図したヒット。逆に言うと、開発者の Mac には 「シグネチャに引っかかるが正当な研究 / テスト データ」が普通に入っている ということで、自動隔離 (--move, --remove) は絶対に避けたほうがいい。手動で 1 件ずつパスを見て判断する運用が現実解。

途中で出たエラー / ワーニングの内訳

完走しなかったとはいえ、ログ全 537 行の内訳は次のとおり。

件数パターン意味
430index_local_file_headers_within_boundsZIP として認識した小さなファイルがマルフォーム。Go モジュール キャッシュの *.ziphash 等の小ファイルが疑似的に ZIP マジックを持っているのが原因
77cli_unzip: failed to create temporary fileテンポラリ作成失敗 (上記のディスク フルが原因)
16cli_gentempfd_with_prefix: ... No space left on device同上 (より低レイヤの直接的なエラー)
4cli_scanxz: premature end of compressed stream切り詰められた xz アーカイブ。スナップショット途中のキャッシュ ファイル等で発生しがち
1cli_writen書込失敗 (これもディスク起因)

index_local_file_headers_within_bounds の 430 件はディスク関係ない純粋な誤検知ログで、Go や Node エコシステムを使う Mac なら必ず出る。「ClamAV の Error は無視可能なものが含まれる」 という事実をまず受け入れる必要がある。

結局スキャンの「結果」はどうなのか

SCAN SUMMARY ブロックは出ていないので、通常の意味でのスキャン完了ではない。ただし、

  • 開始: 2026-05-10 22:10:32
  • 異常終了: 2026-05-10 23:24:53 (ログ最終更新)
  • 経過: 74 分 21 秒
  • 検出 (FOUND): 7 件すべて誤検出 / 意図したヒット
  • ピーク CPU: 99% (シングルスレッド)
  • ピーク RSS: 約 340 MB → 後半は 120 MB 前後で安定
  • ホーム実スキャン量: 286 GB のうち、Parallels と Library/{Caches,Containers,Group Containers} を除いた約 67 GB を 7 割程度処理した時点で停止 (推定)

6. 詰まりどころ早見表

症状原因対処
freshclam: ERROR: Please edit the example config file before running freshclam!サンプルそのままの Example 行が残っている8 行目をコメントアウト
freshclam: Can't create new file ...: Permission deniedDB ディレクトリが存在しないか書込権限がないmkdir -p してオーナーを自分に
ERROR: NULL X509 store (連発)macOS bottle の証明書ストア初期化失敗 (CVD 検証は別経路で通る)無視可。CI フィルタからは除外
clamscan: ... Permission deniedmacOS の TCC / Sandbox や Library/Containers 権限--exclude-dir で除外。深く読みたい場合は tccutil でフルディスクアクセスを付与
スキャンが終わらないVM ディスクや巨大ファイルを再帰展開している--max-filesize / --max-scansize / --exclude-dir
cli_gentempfd_with_prefix: No space left on device$TMPDIR の空きを使い切った (アーカイブ展開で膨張)--tempdir= で大きいボリュームを指定。最低 20 GB は確保
index_local_file_headers_within_bounds: Invalid offset arguments 大量発生小さい非 ZIP ファイルを ZIP と誤認している無視可。Go / npm キャッシュを抱えると数百件出る
cli_scanxz: premature end of compressed stream切り詰められた xz無視可
単一ファイル スキャンに 7 秒DB ロードに時間がかかっているclamd + clamdscan で常駐させる

7. 常用するなら clamd 化を検討

毎回 ~7 秒のロードが入る clamscan は単発向け。常用したいなら clamd をデーモンで動かして clamdscan を叩く のがセオリー。Homebrew なら、

sudo brew services start clamav

これで clamd がポート (UNIX socket) で待ち受けるので、clamdscan <path> 一発で 1 秒以内に結果が返ってくるようになる。 ただし clamd.conf も同じく Example 行のコメントアウトと TCPSocket / LocalSocket の設定が必要。

まとめ

  • インストールは 14 秒、DB 取得は 10 秒。早い
  • 真の難所は freshclam.confExample 行と DB / ログ パスのデフォルト値。Linux 前提なので macOS では必ず置換する
  • ERROR: NULL X509 store は無視してよい既知挙動 (ClamAV 1.5 系 / Homebrew bottle)
  • 「ホーム フルスキャン」 = ~/ 全部、ではない。Mac では Library/ContainersLibrary/CachesParallels を除外しないと、ノイズで本当に怪しいヒットが埋もれる
  • $TMPDIR 空きが命取り。今回 3.2 GB で始めて 74 分で ENOSPC 落ち。アーカイブ展開分を含めて 20 GB 以上の空きと --tempdir 指定 が現実解
  • 検出ヒットは「正当データ」が混ざる。開発者 Mac では Go / Node / セキュリティ研究系のテスト データがシグネチャに引っかかる。--remove / --move の自動隔離は危険
  • シングルスレッドで重い。常用するなら clamd 化する

参考