Einleitung
Die Linux-Audit-Infrastruktur wird häufig von mehreren Sicherheitskomponenten gleichzeitig genutzt. Neben Wazuh können beispielsweise zusätzliche SIEM-Forwarder, Compliance-Werkzeuge oder forensische Audit-Plugins dieselben Ereignisse verarbeiten. In einer solchen Multi-Plugin-Architektur darf der Ausfall eines einzelnen Verbrauchers nicht die gesamte Audit-Pipeline beeinträchtigen.
Genau dieses Fehlerbild kann jedoch entstehen, wenn Wazuh Whodata im Audit-Modus verwendet wird: Bleibt der Wazuh-seitige UNIX-Socket geöffnet, ohne dass der Agent die eintreffenden Ereignisse liest, füllt sich dessen Socket-Puffer. Ein blockierender Schreibzugriff des Audit-Dispatchers kann anschließend verhindern, dass auch alle nachfolgenden Plugins weitere Ereignisse erhalten.
Das sicherheitsrelevante Ergebnis ist ein systemweiter Blindflug: Nicht nur Wazuh verliert Whodata-Informationen, sondern auch unabhängige Audit-Konsumenten können keine Ereignisse mehr verarbeiten.
Ausgangslage / Problemstellung
Das untersuchte Verhalten trat auf einem Linux-System mit Wazuh Agent 4.10.1 und aktiviertem Whodata-Monitoring über das Linux-Audit-Subsystem auf. Zusätzlich zu Wazuh waren weitere Audit-Plugins eingebunden.
Während des normalen Betriebs funktionierte die Ereignisverteilung wie erwartet. Sobald der Wazuh Agent jedoch ohne erreichbaren Manager gestartet wurde, entstand nach einiger Zeit folgendes Fehlerbild:
- Der Audit-Prozess blockierte bei einem Schreibzugriff auf den Wazuh-Socket unter
/var/ossec/queue/sockets/audit. - Andere Audit-Plugins erhielten keine neuen Ereignisse mehr.
- Nach Wiederherstellung der Verbindung beziehungsweise einem Neustart setzte die Verarbeitung wieder ein.
- Das Problem ließ sich auch mit nur zwei überwachten Verzeichnissen reproduzieren.
Ein zunächst vermuteter Zusammenhang mit einer vollständig belegten internen Wazuh-Audit-Queue erwies sich als unvollständig. Der Reader-Thread von Wazuh verwirft im regulären Betrieb neue Ereignisse, wenn seine interne Queue voll ist. Er beendet deshalb nicht automatisch das Lesen aus dem UNIX-Socket. Entscheidend war stattdessen eine besondere Startreihenfolge bei nicht verfügbarem Manager.
Technische Analyse
Ereignispfad im Audit-Modus
Bei Whodata im Audit-Modus verläuft die Verarbeitung vereinfacht über folgende Komponenten:
Linux-Kernel
|
v
auditd / Audit-Dispatcher
|
+--> Audit-Plugin A
|
+--> Wazuh-af_unix-Plugin
| |
| v
| /var/ossec/queue/sockets/audit
| |
| v
| audit_read_events()
| |
| v
| interne Wazuh-Audit-Queue
| |
| v
| Parser und FIM-Verarbeitung
|
+--> Audit-Plugin B
Im Quellcode des Linux-Audit-Dispatchers werden die aktiven Plugins nacheinander durchlaufen. Für jedes Plugin wird write() beziehungsweise writev() aufgerufen. Diese Schreibzugriffe sind nicht grundsätzlich nichtblockierend. Kann ein Plugin keine weiteren Daten aufnehmen, bleibt der Dispatcher deshalb in diesem Schreibzugriff hängen und erreicht die nachfolgenden Plugins nicht mehr.
Damit besitzt jedes blockierende Audit-Plugin potenziell einen größeren Ausfallradius als seine eigene Funktion vermuten lässt.
Warum eine volle interne Wazuh-Queue allein nicht genügt
In Wazuh 4.10.1 liest audit_read_events() die Daten über recv() aus dem Audit-Socket. Anschließend werden vollständige Audit-Ereignisse in eine interne Queue übertragen.
Ist diese Queue voll, schlägt das Einfügen fehl. Wazuh protokolliert den Zustand und gibt den betreffenden Speicherbereich wieder frei. Der Reader kann danach grundsätzlich weitere Daten aus dem Socket lesen. Eine volle interne Queue führt in diesem Ablauf daher primär zum Verlust Wazuh-eigener Whodata-Ereignisse, aber nicht zwangsläufig zu einem dauerhaft gefüllten UNIX-Socket.
Diese Unterscheidung ist wichtig, weil drei verschiedene Puffer betrachtet werden müssen:
- die Queue des Linux-Audit-Dispatchers,
- der Kernel-Puffer des UNIX-Sockets,
- die interne Whodata-Queue des Wazuh Agents.
Eine Vergrößerung des dritten Puffers behebt keinen Zustand, in dem der Socket überhaupt nicht gelesen wird.
Der kritische Startpfad in Wazuh 4.10.1
Die relevante Reihenfolge ist im Quellcode von Wazuh 4.10.1 nachvollziehbar:
audit_init()erzeugt mitinit_auditd_socket()eine Verbindung zum Audit-Socket.- Der Whodata-Healthcheck wird ausgeführt.
- Die interne Audit-Queue und der Parser-Thread werden initialisiert.
- Der Thread
audit_main()wird gestartet. audit_main()wartet aufaudit_db_consistency_flag.- Erst nach Setzen dieses Flags wird
audit_read_events()aufgerufen.
Der Socket ist somit bereits geöffnet und mit dem Audit-Dispatcher verbunden, während der eigentliche Reader noch auf eine Condition Variable wartet.
Ist der Manager beim Start des Agents erreichbar, wird die FIM-Initialisierung abgeschlossen, das Konsistenz-Flag gesetzt und der Reader beginnt mit dem Empfang der Audit-Ereignisse.
Ist der Manager dagegen bereits beim Agent-Start nicht erreichbar, kann ein vorgelagerter FIM-Schritt beim Versand beziehungsweise bei der Synchronisierung warten. Wird die Initialisierung dadurch nicht bis zum Setzen des Konsistenz-Flags fortgeführt, verbleibt audit_main() in:
while (!audit_db_consistency_flag) {
w_cond_wait(&audit_db_consistency, &audit_mutex);
}
Währenddessen bleibt der zuvor erzeugte Audit-Socket geöffnet. Da audit_read_events() noch nicht läuft, erfolgen keine recv()-Aufrufe.
Der resultierende Ablauf ist deterministisch:
Manager nicht erreichbar
|
v
FIM-Initialisierung bleibt vor Abschluss stehen
|
v
audit_db_consistency_flag bleibt 0
|
v
audit_main() wartet
|
v
Audit-Socket bleibt offen, wird aber nicht gelesen
|
v
Kernel-Socket-Puffer füllt sich
|
v
write() des Audit-Dispatchers blockiert
|
v
Alle nachfolgenden Audit-Plugins warten
Damit handelt es sich nicht primär um ein Problem zu hoher Ereignislast. Eine hohe Änderungsrate beschleunigt lediglich das Füllen des Socket-Puffers. Auch ein kleiner Whodata-Umfang kann den Zustand auslösen, sofern genügend Audit-Ereignisse eintreffen.
Warum das Problem sicherheitskritisch ist
Der Audit-Modus von Wazuh hängt an einem gemeinsam genutzten Verteilungspfad. Ein lokaler Initialisierungsfehler kann deshalb Auswirkungen auf unabhängige Sicherheitskontrollen haben.
Mögliche Folgen sind:
- Verlust von Audit-Ereignissen anderer Anwendungen,
- unterbrochene Compliance-Protokollierung,
- fehlende Erkennung privilegierter Aktionen,
- unvollständige forensische Daten,
- nicht erkannte Manipulationen während einer Manager-Störung,
- scheinbar funktionierendes
auditd, obwohl dessen Plugin-Verteilung stillsteht.
Besonders kritisch ist, dass der Zustand nicht zwingend durch einen abgestürzten Prozess sichtbar wird. Der Audit-Dienst kann weiterhin laufen, während ein Thread dauerhaft in einem blockierenden Systemaufruf hängt.
Abgrenzung zu anderen Whodata-Problemen
Neuere Wazuh-Versionen enthalten mehrere Korrekturen für Warte- und Deadlock-Situationen im FIM- beziehungsweise Whodata-Bereich.
Wazuh 4.14.1 korrigierte einen potenziell unbegrenzten Wartezustand im Whodata-Healthcheck. Wazuh 4.14.5 enthielt weitere Korrekturen für Lock-Reihenfolgen und mögliche FIM-Deadlocks. Diese Änderungen sind betrieblich relevant, belegen jedoch nicht automatisch, dass der hier beschriebene Startpfad vollständig behoben wurde.
Eine Prüfung des aktuellen Hauptentwicklungszweigs zeigt weiterhin die grundsätzliche Reihenfolge „Socket erzeugen, anschließend im Reader-Thread auf das Datenbank-Konsistenz-Flag warten, danach audit_read_events() starten“. Ob alle Voraussetzungen für den beschriebenen Stillstand in aktuellen Releases noch reproduzierbar sind, muss daher versionsspezifisch getestet werden.
Lösung / Best Practices
1. Agent auf eine aktuelle Wazuh-Version aktualisieren
Wazuh 4.10.1 sollte für die weitere Fehleranalyse nicht als Referenzversion verwendet werden. Zum Zeitpunkt der Erstellung dieses Artikels ist Wazuh 4.14.6 das aktuelle stabile Release. Dieses enthält unter anderem zusätzliche Korrekturen für FIM-Whodata und eBPF.
Das Upgrade sollte zuerst in einer Testgruppe erfolgen. Entscheidend ist nicht nur ein allgemeiner Funktionstest, sondern die gezielte Reproduktion der problematischen Startbedingung:
- Manager stoppen oder Netzwerkverbindung blockieren.
- Wazuh Agent vollständig neu starten.
- Audit-Ereignisse erzeugen.
- Prüfen, ob andere Audit-Plugins weiterhin Daten erhalten.
- Socket-Queue und Thread-Zustände kontrollieren.
- Manager-Verbindung wiederherstellen.
- Test nach einem regulären Verbindungsabbruch bei bereits laufendem Agent wiederholen.
Damit werden zwei technisch unterschiedliche Situationen geprüft:
- Manager ist beim Agent-Start nicht erreichbar.
- Manager fällt erst nach erfolgreicher Whodata-Initialisierung aus.
2. Whodata auf eBPF umstellen
Die wirksamste architektonische Entkopplung besteht darin, Whodata nicht über den gemeinsam genutzten Linux-Audit-Dispatcher zu beziehen.
Wazuh unterstützt hierfür einen eBPF-basierten Provider:
<syscheck>
<directories whodata="yes">/etc</directories>
<directories whodata="yes">/var/ossec/etc</directories>
<whodata>
<provider>ebpf</provider>
</whodata>
</syscheck>
Im eBPF-Modus werden relevante Dateisystemereignisse über eine BPF-Ring-Buffer-Struktur vom Kernel an Wazuh übertragen. auditd, der Audit-Dispatcher und das Wazuh-af_unix-Plugin befinden sich damit nicht mehr im Whodata-Ereignispfad. Ein Wazuh-interner Rückstau kann dann zwar weiterhin Wazuh-Ereignisse betreffen, blockiert aber keine anderen Audit-Konsumenten.
Voraussetzungen und Prüfungen:
- Kernel 5.8 oder neuer,
- eBPF-Unterstützung im verwendeten Kernel,
- ausreichende BPF-Berechtigungen,
- erfolgreicher Start des eBPF-Providers,
- Kontrolle, ob die Events tatsächlich im Whodata-Modus eintreffen,
- Prüfung auf einen möglichen Fallback zum Audit-Modus.
Wazuh fällt bei nicht verfügbarem eBPF standardmäßig auf den Audit-Provider zurück. Eine gesetzte Konfiguration allein beweist daher noch nicht, dass die Entkopplung aktiv ist.
Nach der Umstellung sollten Änderungsereignisse für alle relevanten Operationen getestet werden:
touch /etc/wazuh-ebpf-test
echo test >> /etc/wazuh-ebpf-test
chmod 600 /etc/wazuh-ebpf-test
rm /etc/wazuh-ebpf-test
Anschließend ist zu prüfen, ob Benutzer, Prozess und Änderungsart korrekt in den FIM-Ereignissen erscheinen.
3. Whodata gezielt statt flächendeckend einsetzen
Whodata liefert einen hohen Mehrwert, weil zusätzlich zur Dateiänderung auch der verantwortliche Benutzer und Prozess ermittelt werden. Diese Information ist jedoch nicht für jedes Verzeichnis erforderlich.
Für besonders sensible Pfade kann Whodata aktiviert bleiben:
<directories whodata="yes">/etc/sudoers.d</directories>
<directories whodata="yes">/etc/ssh</directories>
<directories whodata="yes">/var/ossec/etc</directories>
Für umfangreiche oder besonders änderungsintensive Verzeichnisse kann stattdessen Realtime-FIM ausreichen:
<directories realtime="yes">/usr/bin</directories>
<directories realtime="yes">/usr/sbin</directories>
<directories realtime="yes">/usr/lib</directories>
Eine Reduzierung des Whodata-Umfangs beseitigt den beschriebenen Initialisierungsfehler nicht. Sie reduziert jedoch die Ereignisrate, verlängert die Zeit bis zur Pufferbelegung und senkt den Ressourcenverbrauch.
4. Interne Whodata-Queue nicht mit dem Socket-Puffer verwechseln
Die Wazuh-Konfiguration erlaubt eine Anpassung der Whodata-Queue:
<whodata>
<provider>audit</provider>
<queue_size>65536</queue_size>
</whodata>
Die aktuell dokumentierte Voreinstellung beträgt 16.384 Einträge. Der zulässige Bereich reicht von 10 bis 1.048.576.
Eine größere Queue kann kurzfristige Lastspitzen abfangen. Sie behebt jedoch nicht den hier beschriebenen Startzustand, weil audit_read_events() zu diesem Zeitpunkt noch gar keine Daten in die Queue überträgt.
Zusätzlich steigt mit der Queue-Größe der Speicherbedarf. Die Einstellung sollte deshalb nur anhand gemessener Ereignisraten und definierter Burst-Szenarien verändert werden.
5. Queue des Audit-Dispatchers nur als Puffer einsetzen
In /etc/audit/auditd.conf kann die Dispatcher-Queue über q_depth vergrößert werden:
q_depth = 8192
Aktuelle Versionen von audit-userspace dokumentieren einen Standardwert von 2.000. Eine größere Queue kann Ereignisspitzen besser abfangen, verhindert aber keinen dauerhaft blockierten Plugin-Schreibzugriff. Sie verschiebt den Ausfall lediglich zeitlich und erhöht die Zahl der Ereignisse, die bei einem Prozessende noch unverarbeitet sein können.
Nach einer Änderung sollte die Konfiguration distributionsabhängig neu geladen oder der Audit-Dienst kontrolliert neu gestartet werden. Dabei sind lokale Compliance-Anforderungen und immutable Audit-Konfigurationen zu berücksichtigen.
6. Blockierenden Prozess und Wazuh-Reader gemeinsam untersuchen
Während des Fehlers müssen sowohl die schreibende als auch die lesende Seite erfasst werden.
WAZUH_PID=$(pgrep -o wazuh-syscheckd)
ps -T -p "$WAZUH_PID"
sudo gstack "$WAZUH_PID"
Falls gstack nicht verfügbar ist:
sudo eu-stack -p "$WAZUH_PID"
UNIX-Sockets und Warteschlangen anzeigen:
sudo ss -xap | grep -E 'wazuh|queue/sockets/audit'
Audit-Prozesse identifizieren:
pgrep -a -f 'auditd|audispd|audisp-af'
Blockierende Schreibzugriffe verfolgen:
sudo strace -ff \
-p "$(pgrep -o auditd)" \
-e trace=write,writev,sendto,sendmsg
Je nach Distribution läuft der relevante Dispatcher in einem separaten Prozess. In diesem Fall muss strace an dessen PID angehängt werden.
Wazuh-Protokolle prüfen:
grep -Ei \
'audit|whodata|queue|consistency|syscheck|manager' \
/var/ossec/logs/ossec.log
Audit-Zustand und Regeln prüfen:
sudo auditctl -s
sudo auditctl -l
Für die Diagnose sind insbesondere folgende Thread-Zustände relevant:
- Warten auf
audit_db_consistency, - Blockierung in einem Mutex,
- aktives Warten in
select(), - Blockierung in
recv(), - nicht vorhandener Reader-Thread,
- Parser- oder FIM-Thread in einem Sendewartezustand.
Zeigt der Wazuh-Thread eine Condition-Variable vor audit_read_events(), während der Audit-Dispatcher beim Schreiben auf den Wazuh-Socket hängt, entspricht dies dem beschriebenen Startpfad.
7. Lokalen Quellcode-Patch nur kontrolliert einsetzen
Als technische Gegenmaßnahme wurde erfolgreich getestet, den Audit-Socket vor dem Warten auf das Konsistenz-Flag zu schließen und erst nach erfolgreicher Initialisierung neu zu erzeugen.
Das Prinzip lautet:
close(audit_data->socket);
audit_data->socket = -1;
while (!audit_db_consistency_flag) {
w_cond_wait(&audit_db_consistency, &audit_mutex);
}
audit_data->socket = init_auditd_socket();
if (audit_data->socket < 0) {
return NULL;
}
audit_read_events(&audit_data->socket, &audit_thread_active);
Dadurch existiert während des Wartezustands kein verbundener Wazuh-Socket, dessen Empfangspuffer sich füllen könnte.
Ein solcher Patch sollte jedoch nicht ungeprüft in produktive Installationen übernommen werden. Er benötigt mindestens:
- Validierung gegen die exakt eingesetzte Wazuh-Version,
- Behandlung aller Fehler- und Abbruchpfade,
- Prüfung auf doppelte oder verlorene File Descriptors,
- Tests mit Audit-Healthcheck,
- Tests bei Audit-Neustarts,
- Tests mit immutable Audit-Regeln,
- Prüfung der Wiederverbindung,
- Last- und Langzeittests,
- erneute Bewertung nach jedem Wazuh-Upgrade.
Bis zur Aufnahme einer entsprechenden Änderung in ein offizielles Release handelt es sich um eine lokale Modifikation außerhalb des regulären Paket- und Supportpfads.
Lessons Learned / Best Practices
Gemeinsame synchrone Pipelines besitzen einen großen Ausfallradius
Werden mehrere Security-Komponenten seriell über denselben Dispatcher versorgt, kann ein einzelner blockierender Verbraucher alle anderen beeinträchtigen. Die Funktionsfähigkeit jedes Plugins ist damit Teil der Verfügbarkeit der gesamten Audit-Infrastruktur.
Startfehler und Laufzeitfehler getrennt testen
Ein Agent, der zunächst erfolgreich mit dem Manager verbunden war und später die Verbindung verliert, kann sich anders verhalten als ein Agent, der bereits ohne Manager-Verbindung startet.
Folgende Szenarien gehören in jeden Regressionstest:
- Agent-Start bei verfügbarem Manager,
- Agent-Start bei nicht verfügbarem Manager,
- Verbindungsverlust nach erfolgreichem Start,
- längere Trennung,
- Wiederverbindung,
- Agent-Neustart während der Trennung,
- Audit-Neustart während der Trennung.
Graceful Degradation muss lokal begrenzt bleiben
Bei einem Ausfall des Wazuh Managers ist es akzeptabler, ausschließlich Wazuh-eigene FIM-Ereignisse kontrolliert zu verwerfen, als die gesamte Audit-Verteilung anzuhalten.
Dieses Prinzip sollte für alle gemeinsam genutzten Telemetriepfade gelten: Ein nachgelagerter Verbraucher darf keinen globalen Rückstau verursachen.
eBPF reduziert Abhängigkeiten
Der eBPF-Provider entfernt Whodata aus dem gemeinsamen Audit-Plugin-Pfad. Neben möglichen Performancevorteilen ist vor allem die Fehlerisolation relevant. Andere Audit-Konsumenten bleiben unabhängig von Wazuh-internen Queues, Threads und Manager-Verbindungen.
Queue-Tuning ersetzt keine Ursachenbehebung
Größere Puffer können Lastspitzen ausgleichen, aber keinen dauerhaft fehlenden Consumer reparieren. Jede Queue besitzt eine endliche Kapazität. Bei einer unbegrenzten Blockierung wird deshalb lediglich der Zeitpunkt des Ausfalls verschoben.
Whodata nach Schutzbedarf einsetzen
Nicht jede Systembibliothek und nicht jeder Binärpfad benötigt dauerhaft eine vollständige Benutzer- und Prozesszuordnung. Eine risikobasierte Aufteilung zwischen Whodata, Realtime-FIM und periodischen Scans reduziert Komplexität und Ereignislast.
Audit-Verfügbarkeit aktiv überwachen
Die Überwachung sollte nicht nur den Prozessstatus von auditd erfassen. Sinnvolle zusätzliche Signale sind:
- wachsende Dispatcher-Queues,
- belegte UNIX-Socket-Queues,
- fehlende Ereignisse einzelner Plugins,
- Wazuh-Whodata-Queue-Warnungen,
- blockierte Threads,
- Audit-Backlog- und Lost-Zähler,
- Abweichungen zwischen erwarteter und tatsächlicher Ereignisrate.
Ein laufender Prozess ist kein ausreichender Nachweis für eine funktionierende Audit-Pipeline.
Fazit
Der beobachtete Stillstand war nicht einfach die erwartete Folge einer vollen internen Wazuh-Queue. Im untersuchten Startpfad wurde der Audit-Socket bereits geöffnet, während der zugehörige Reader-Thread noch auf den Abschluss der FIM-Datenbankinitialisierung wartete.
War der Manager beim Start des Wazuh Agents nicht erreichbar, blieb dieses Signal aus. Der Socket wurde nicht gelesen, sein Empfangspuffer füllte sich und der Linux-Audit-Dispatcher blockierte beim Schreiben. Aufgrund der seriellen Plugin-Verarbeitung erhielten anschließend auch unabhängige Audit-Konsumenten keine Ereignisse mehr.
Die bevorzugte Betriebsstrategie besteht aus einem Upgrade auf eine aktuelle Wazuh-Version, einem gezielten Regressionstest des Offline-Starts und – sofern technisch möglich – der Umstellung von Whodata auf eBPF. Queue-Vergrößerungen und eine Reduzierung der überwachten Pfade können die Auswirkungen begrenzen, stellen jedoch keine vollständige Behebung des zugrunde liegenden Initialisierungsproblems dar.
Quellen
Wazuh: Advanced File Integrity Monitoring und eBPF-Whodata
https://documentation.wazuh.com/current/user-manual/capabilities/file-integrity/advanced-settings.html
Wazuh: Referenz der Whodata-Konfiguration
https://documentation.wazuh.com/current/user-manual/reference/ossec-conf/syscheck.html
Wazuh 4.10.1: syscheck_audit.c
https://github.com/wazuh/wazuh/blob/v4.10.1/src/syscheckd/src/whodata/syscheck_audit.c
Wazuh Hauptentwicklungszweig: syscheck_audit.c
https://github.com/wazuh/wazuh/blob/main/src/syscheckd/src/whodata/syscheck_audit.c
Linux Audit: Plugin-Verteilung in audispd.c
https://github.com/linux-audit/audit-userspace/blob/master/audisp/audispd.c
Linux Audit: Dokumentation zu auditd.conf und q_depth
https://github.com/linux-audit/audit-userspace/blob/master/docs/auditd.conf.5
Wazuh: Unbegrenzter Wartezustand im Whodata-Healthcheck
https://github.com/wazuh/wazuh/issues/21310
Wazuh: FIM-Deadlocks und Lock-Reihenfolge
https://github.com/wazuh/wazuh/issues/17957
Wazuh 4.14.6 Release
https://github.com/wazuh/wazuh/releases/tag/v4.14.6
Mehr zum Wazuh Ambassador Program …
https://wazuh.slack.com/archives/C07BK5RJM3R/p1783686305019789