From 29b3fb2a6d64bfd4ad67575bc9851466671b2a8d Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Sun, 19 Jul 2026 08:09:13 +0200 Subject: [PATCH] Repair ClamAV runtime PID path --- src/apps/config/tests/test_scanner_config.py | 2 + .../bongo/configuration/scanner_config.py | 39 ++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/apps/config/tests/test_scanner_config.py b/src/apps/config/tests/test_scanner_config.py index c07ee6e..5f563e0 100644 --- a/src/apps/config/tests/test_scanner_config.py +++ b/src/apps/config/tests/test_scanner_config.py @@ -59,6 +59,7 @@ class ScannerConfigurationTest(unittest.TestCase): original = ( "# Distribution configuration\n" "LocalSocket /run/clamav/clamd.sock\n" + "PidFile /run/clamd.pid\n" "TCPAddr 0.0.0.0\n" "TCPSocket 9999\n" "TCPAddr 192.0.2.2\n" @@ -66,6 +67,7 @@ class ScannerConfigurationTest(unittest.TestCase): ) edited = edit_clamd_configuration(original) self.assertIn("LocalSocket /run/clamav/clamd.sock", edited) + self.assertIn("PidFile /run/clamav/clamd.pid", edited) self.assertIn("LogTime yes", edited) self.assertIn("TCPAddr 127.0.0.1", edited) self.assertIn("TCPSocket 3310", edited) diff --git a/src/libs/python/bongo/configuration/scanner_config.py b/src/libs/python/bongo/configuration/scanner_config.py index 08da933..8c67e34 100644 --- a/src/libs/python/bongo/configuration/scanner_config.py +++ b/src/libs/python/bongo/configuration/scanner_config.py @@ -30,7 +30,7 @@ import shutil import subprocess import time from dataclasses import dataclass, replace -from pathlib import Path +from pathlib import Path, PurePosixPath from typing import Callable, Mapping, Sequence from .probes import ProbeResult, probe_clamav, probe_spamd @@ -230,9 +230,46 @@ def _read_configuration(path: Path) -> str: from error +def _clamd_runtime_pid_file(content: str) -> str | None: + """Move a root-level runtime PID beside clamd's private socket. + + Several distribution configurations still use ``/run/clamd.pid`` while + telling clamd to drop privileges. The daemon can create that file while + privileged, but cannot remove it during a clean shutdown. Reuse the + distribution's existing LocalSocket directory instead of hard-coding a + distro-specific runtime directory. + """ + values: dict[str, str] = {} + for line in content.splitlines(): + if not line.strip() or line.lstrip().startswith("#"): + continue + try: + fields = shlex.split(line, comments=True, posix=True) + except ValueError: + continue + if len(fields) >= 2 and fields[0].lower() in {"localsocket", "pidfile"}: + values.setdefault(fields[0].lower(), fields[1]) + + if "localsocket" not in values or "pidfile" not in values: + return None + socket = PurePosixPath(values["localsocket"]) + pid = PurePosixPath(values["pidfile"]) + if not socket.is_absolute() or not pid.is_absolute(): + return None + runtime_roots = {PurePosixPath("/run"), PurePosixPath("/var/run")} + if pid.parent not in runtime_roots or socket.parent in runtime_roots: + return None + if not any(root in socket.parents for root in runtime_roots): + return None + return str(socket.parent / "clamd.pid") + + def edit_clamd_configuration(content: str) -> str: """Return clamd configuration with one safe active value per setting.""" desired = dict(CLAMD_SETTINGS) + runtime_pid_file = _clamd_runtime_pid_file(content) + if runtime_pid_file is not None: + desired["PidFile"] = runtime_pid_file canonical = {name.lower(): name for name in desired} seen: set[str] = set() output: list[str] = []