-
Notifications
You must be signed in to change notification settings - Fork 247
Description
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:
- Build a list of modified files into
$monitor_scanlist - Immediately fire up clamscan with that list (line 1815)
- Wait for it to finish
- 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 clamscanshows brief clamscan processes appearing regularly- Event log shows
{mon} scanned 0 new/changed files with clamav enginerepeatedly - 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 scanThe 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!