Skip to content

monitor_check() launches clamscan even with empty file list #459

@GiampaoloGabba

Description

@GiampaoloGabba

Performance bug: monitor_check() launches clamscan even when there are no files to scan

I've been running maldet v1.6.6 in monitor mode on a Debian 12 server with 119 vhosts, and noticed something odd: even during completely idle periods with zero file activity, clamscan keeps spinning up every 30 seconds and eating CPU for no reason.

After digging into the code, I found that monitor_check() in /usr/local/maldetect/internals/functions always calls clamscan regardless of whether there are actually any files to scan.

What's Happening

The current flow in monitor_check() goes like this:

  1. Build a list of modified files into $monitor_scanlist
  2. Immediately fire up clamscan with that list (line 1815)
  3. Wait for it to finish
  4. Then count how many files were scanned and log the result

The issue is step 2 - clamscan gets launched even when the list is completely empty. So ClamAV has to load all its signatures, initialize the engine, process an empty list, then exit. This happens every inotify_sleep seconds whether anything changed or not.

On my server, I was seeing clamscan spike CPU every 30 seconds just to scan... nothing.

How to Reproduce

Set up maldet with:

  • scan_clamscan="1"
  • inotify_sleep="30"
  • Monitor mode active on any path

Wait during an idle period and watch:

  • ps aux | grep clamscan shows brief clamscan processes appearing regularly
  • Event log shows {mon} scanned 0 new/changed files with clamav engine repeatedly
  • CPU usage spikes every 30 seconds even with zero file modifications

Suggested Fix

Just add a simple check before launching the scanner to see if there's actually work to do:

monitor_check() {
    monitor_scanlist="$tmpdir/.monitor.scan.${RANDOM}${RANDOM}"
    touch $monitor_scanlist ; chmod 600 $monitor_scanlist
    $tlog $inotify_log inotify | grep -E " CREATE| MODIFY| MOVED_TO" | awk -F" CREATE| MODIFY| MOVED_TO" '{print $1}' | sort -u | grep -vf $ignore_paths> $monitor_scanlist

    # Skip scanning if no files were modified
    scanned_count=`wc -l $monitor_scanlist | awk '{print$1}'`
    if [ "$scanned_count" -eq 0 ]; then
        eout "{mon} scanned 0 new/changed files (skipped scan - no files detected)"
        rm -f $monitor_scanlist
        return
    fi

    if [ "$scan_clamscan" == "1" ]; then
        # Now launch clamscan knowing we have files to scan

The same logic would benefit the native engine path (lines 1859-1875) as well.

Why This Matters

This becomes really noticeable on servers that:

  • Monitor lots of paths (like shared hosting with many vhosts)
  • Use aggressive monitoring intervals (low inotify_sleep values)
  • Have periods of low activity where files aren't being modified constantly

The fix is trivial and completely backward compatible - it just skips unnecessary work when there's nothing to do, while maintaining full real-time protection the moment any file actually gets modified.

Testing

I applied this patch to my production server and the difference is immediate:

  • Before: clamscan running every 30 seconds eating CPU even during idle hours
  • After: No clamscan invocations when nothing changes, instant scanning when files are modified
  • Logs are clearer too: now says "skipped scan" instead of misleadingly claiming it scanned 0 files

Environment Details

  • Linux Malware Detect: v1.6.6
  • OS: Debian 12
  • ClamAV: v1.0.9
  • Config: Real-time inotify monitoring with 30-second intervals

Let me know if you need any more details or want me to submit a proper patch!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions