Anti-Ransomware Scheduled Scanner (YARA + Allowlist + CPU Throttle)

1. Overview

This component implements BastionGuard’s scheduled Anti-Ransomware scanner, designed to run either as a long-lived daemon or as an on-demand CLI tool. It performs filesystem scans using a consolidated YARA ruleset, applies anti false-positive logic (allowlist + filters), and reduces system impact through CPU throttling, I/O niceness, and rate limiting.

The scanner supports multiple operational modes:

  • Daemon mode – continuous scanning loop over configured paths, with optional Samba scans
  • Single file scan--scan <file>
  • Single directory scan--scan-dir <dir>

Detection events are reported via D-Bus to allow the desktop UI to display real-time alerts.


2. Core Architecture

2.1 Global Runtime State

The scanner uses global state for lifecycle and rules management:

  • static bool running – main loop control flag (set false by signal handler)
  • static YR_RULES* yara_rules – compiled YARA ruleset cache
  • bool running_as_daemon – controls D-Bus loop handling behavior for CLI mode

Thread safety is ensured with global mutexes for sensitive operations:

  • yara_mtx – serializes YARA scans against shared YR_RULES*
  • log_mtx – serializes event-log writes

2.2 ThreadPool for Parallel Scanning

To accelerate traversal across large directory trees, the scanner uses a simple internal ThreadPool based on:

  • Worker threads that wait on a condition variable
  • A task queue of std::function<void()>
  • enqueue() accepting lambdas and callable objects

Thread count is bounded:

  • min(16, hardware_concurrency) with fallback assumptions when concurrency is unknown

The destructor performs a clean stop, wakes all workers, and joins threads.


3. Resource Control and Performance Hardening

3.1 CPU and I/O Priority Reduction

At startup, the daemon lowers scheduling priority to reduce impact on interactive workloads:

  • setpriority(PRIO_PROCESS, 0, 19) – low CPU scheduling priority
  • ionice -c3 -p <pid> – idle I/O class (best-effort)

3.2 CPU Throttling via /proc Sampling

The CpuThrottle subsystem estimates process CPU usage by comparing:

  • System CPU time from /proc/stat
  • Process CPU time from /proc/self/stat (utime + stime)

If the process exceeds the configured target (default 2%), it applies a proportional sleep to reduce CPU consumption. The check interval is configurable (e.g., every 5 seconds in the daemon loop).


3.3 Rate Limiting (Token Bucket)

The scanner uses an explicit token bucket model to cap scanning throughput:

  • MAX_FILES_PER_SEC defines available tokens per second
  • Each file scan consumes one token
  • Tokens are refilled every 1 second using an atomic timestamp guard

This prevents uncontrolled bursts when scanning large directory trees, particularly when combined with multithreading.


4. Configuration Model

4.1 ScannerConfig Keys

Runtime settings are represented by ScannerConfig, including:

  • enable_yara – enable/disable YARA scanning
  • enable_sanesecurity – optional DB-based detection toggle (placeholder in this excerpt)
  • scan_path – semicolon-separated scan paths
  • scan_interval – scan interval (minutes)
  • max_memory – memory budget / stack configuration
  • enable_samba_scan – toggle Samba scanning
  • samba_path – semicolon-separated Samba paths
  • Anti false positives:
    • ignore_paths – glob patterns
    • ignore_ext – extension blocklist
    • suspicious_ext – extension allowlist for “suspicious-only” mode
    • suspicious_only – scan only suspicious extensions
    • allowlist_file – SHA256 allowlist file path

Configuration is loaded from:

resource("config/scanner.conf")

When absent, the scanner uses safe defaults (scan /home, YARA on, conservative filters enabled).


4.2 Dynamic YARA Rules Directory Selection

If no rules directory is provided, the scanner attempts to locate YARA rules in the following order:

  1. User rules: ~/.local/share/BastionGuard/data/yara
  2. System rules: /usr/share/BastionGuard/data/yara
  3. Fallback internal resource directory: resource("rules")

4.3 Samba Directory Loading

Samba directories are loaded from:

resource("config/samba_dirs.conf")

Non-empty, non-comment lines are treated as paths. If missing, Samba scanning remains possible but uses an empty set until configured.


5. Allowlist (SHA256;Optional Rule)

5.1 Format and Storage

The allowlist supports per-file and per-rule suppression using the format:

SHA256
SHA256;rule_id

Entries are loaded into:

  • std::unordered_multimap<std::string, std::string> g_allow_sha_rule

Matching logic:

  • If the SHA exists with an empty rule value → allow the file globally
  • If the SHA exists with a rule id → allow only when that rule matched

6. Debounce and Fingerprinting Cache

6.1 Purpose

To reduce repeated scanning of unchanged files across periodic passes, the scanner maintains an in-memory fingerprint cache:

  • Keyed by full path
  • Tracks size and last-write ticks
  • Optionally stores the last computed SHA256

unchanged(entry) returns true when both size and mtime match the cached values.


7. YARA Ruleset Compilation and Match Aggregation

7.1 Unified Ruleset Compilation

The scanner compiles all .yara rules within the configured directory into a single YR_RULES* using:

  • yr_compiler_create()
  • yr_compiler_add_file() for each rule
  • yr_compiler_get_rules() to finalize

7.2 Optional Zero-Day Rule with Integrity Check

An optional “0-day” rule file can be provided via:

  • --0day-protection <file>

Before loading, the module can validate integrity by comparing the file SHA256 against an expected value. If mismatched:

  • Rule loading is suppressed
  • A D-Bus alert is generated with Integrity_Mismatch

7.3 Per-File Hit Accumulator

YARA matches are aggregated per file via a per-thread map:

  • thread_local std::unordered_map<std::string, HitInfo> g_hits

HitInfo tracks:

  • Total match count
  • Maximum severity meta value
  • High-confidence flag (tag high or severity ≥ 80)
  • List of matched rule identifiers

7.4 Callback Logic

The YARA callback:

  • Collects rule identifier into rules
  • Reads severity from YARA meta (severity)
  • Checks tag “high” (compatible with YARA 3.x / 4.x build variations)
  • Maintains count, max_severity, and high_conf

Detection decision uses a quorum/threshold model:

  • malicious if count >= 2 or high_conf == true

8. Detection Workflow (process_one)

8.1 Filtering Pipeline

In daemon mode, each candidate file goes through sequential filters before scanning:

  • Path glob ignore list (ignore_paths_glob)
  • Extension ignore list (ignore_exts)
  • Optional “suspicious-only” extension gating (suspicious_exts)
  • Unchanged-file bypass (fingerprint cache)
  • Minimum size threshold (MIN_YARA_SIZE, e.g., 4096 bytes)

This pipeline reduces false positives and dramatically lowers compute cost on benign content.


8.2 YARA Scan and Event Handling

When scanning is enabled and rules are available:

  • YARA scan is serialized under yara_mtx because the ruleset pointer is shared
  • Matches are evaluated for maliciousness using quorum + severity/tag gating
  • SHA256 is computed on malicious candidates for allowlist checks

8.3 Allowlist Suppression vs Real Alerts

If the file’s SHA (and optionally matched rules) is allowlisted:

  • The event is logged as SUPPRESSED_ALLOWLIST
  • No D-Bus alert is emitted

If not allowlisted:

  • An event is logged to: /tmp/BastionGuard-ransomware-events.log
  • A D-Bus alert is emitted with family:
    • YARA (local filesystem)
    • YARA_SAMBA (Samba path scan)

When running in CLI mode, a short-lived GLib main loop is created to ensure the D-Bus message is flushed before process exit.


9. D-Bus Alert Transport

9.1 Direct Session-Bus Connection

Alerts are sent using Gio::DBus::Connection::create_for_address_sync(). The address is taken from:

  • DBUS_SESSION_BUS_ADDRESS

A robust fallback is provided:

unix:path=/run/user/1000/bus

This enables operation when the environment is incomplete (e.g., system service contexts) at the cost of assuming a default UID if not otherwise set by the caller.


9.2 Alert Interface

The D-Bus call is issued to:

  • Object path: /org/BastionGuard/ransomware/alert
  • Interface: org.BastionGuard.Ransomware.Alert
  • Method: ShowAlert

Payload is a tuple containing:

  • File path
  • Alert family identifier

10. Operational Modes and CLI

10.1 CLI Options

The scanner supports:

  • --scan / -s – scan a single file and print results
  • --scan-dir / -d – scan a directory recursively
  • --rules-dir – override YARA rules directory
  • --0day-protection – override the 0-day rule path
  • --help / -h – usage output

A guard prevents conflicting CLI modes (file and directory scan simultaneously).


10.2 Daemon Loop

In daemon mode, the scanner loops while running == true:

  • Optionally scans Samba paths (if enabled)
  • Scans configured local paths
  • Waits for scan_interval minutes before repeating

Directory traversal uses recursive iterators with skip_permission_denied to avoid crashes on restricted paths.


11. Dynamic Memory Selection and YARA Configuration

11.1 Total RAM Detection

The scanner reads total system memory from:

/proc/meminfo

and derives a memory budget tier (256MB → 2GB) based on total RAM.


11.2 YARA Configuration Application

The chosen value is applied via:

yr_set_configuration(YR_CONFIG_STACK_SIZE, &cfg.max_memory)

This allows the scanner to adapt to low-memory systems while enabling higher stack sizes on capable hosts.


12. Shutdown and Cleanup

On termination:

  • The daemon stops scheduling new work
  • The compiled YARA ruleset (if present) is destroyed via yr_rules_destroy()
  • YARA is finalized via yr_finalize()

ThreadPool workers are joined during destruction, ensuring no dangling tasks remain.


13. Runtime and Security Considerations

  • Low-impact scanning: priority lowering, CPU throttling, and token bucket limiting collectively reduce system load.
  • False-positive resistance: ignore globs, ignore extensions, suspicious-only mode, quorum logic, severity gating, and SHA allowlist combine to reduce noise.
  • Ruleset integrity: optional zero-day integrity check enables tamper detection for high-value rules.
  • D-Bus assumptions: the fallback session-bus path may be incorrect on multi-user systems; best practice is to resolve the active user bus dynamically.
  • Thread safety: serializing YARA scans avoids concurrency issues on shared rulesets; task-level parallelism still benefits directory traversal speed.
  • Log placement: event logs are written under /tmp; for production use, rotation and secure permissions should be considered.