Das Problem
Der UCS-DC bootet. Alles sieht normal aus. Und dann… macht der Server einfach nichts mehr.
free -h zeigt ein Bild, das man lieber nicht sehen möchte:
total used free shared buff/cache available
Mem: 7.9G 7.9G 12M 2.1M 142M 0B
Swap: 2.0G 2.0G 0B
8 GB RAM. Voll. Swap. Voll. Und das System hat gerade erst gebootet.
Die betroffenen Services:
● univention-directory-policy.service - Loaded: loaded; Active: failed
● univention-maintenance.service - Loaded: loaded; Active: failed
journalctl lädt… lädt… lädt. Und dann kommt die Zahl, die alles erklärt:
-- Journal begins at Tue 2026-04-07 00:00:01 CET,
ends at Wed 2026-04-08 09:14:22 CEST. --
Apr 08 06:31:44 dc-vader kernel: [ 12.441] systemd[1]: Starting Univention Directory Policy...
Apr 08 06:31:45 dc-vader univention-policy-repository-sync[1337]:
AddressSanitizer:DEADLYSIGNAL
<2.637.914 weitere Meldungen unterdrückt>
2,6 Millionen Log-Zeilen. Beim Boot. Von einem einzigen Prozess.
Willkommen in der wunderbaren Welt von AddressSanitizer in Produktion.
Die Diagnose
Schritt 1: Wer frisst den RAM?
ps aux --sort=-%mem | head -5
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1337 99.1 94.7 21474836480 7892M ? Ss 06:31 2:14 /usr/bin/python3 /usr/sbin/univention-policy-repository-sync
Da ist er. Ein einzelner Python-Prozess. 94,7 % RAM. 7,9 GB RSS. 21 TB VSZ.
21 Terabyte virtueller Adressraum. Ein Python-Prozess. Auf einem Server mit 8 GB RAM.
Das ist kein Speicherleck. Das ist kein schlechter Code. Das ist AddressSanitizer.
Schritt 2: OOM-Kills bestätigen
dmesg | grep -i oom
[ 15.442] Out of memory: Killed process 1337 (python3) total-vm:21474836480kB, anon-rss:8085880kB, file-rss:0kB, shmem-rss:0kB, UID:0 pgtables:67328kB oom_score_adj:0
[ 15.443] oom_kill_process: Kill process 1337 (python3) score 997 or sacrifice child
Score 997. Der OOM-Killer hat praktisch keine Wahl.
Schritt 3: Die Root Cause - libasan.so.5
ldd /usr/bin/univention_policy_result
linux-vdso.so.1 (0x00007ffd1e9fd000)
libasan.so.5 => /lib/x86_64-linux-gnu/libasan.so.5 (0x00007f8b3c200000)
libuniventionconfig.so.0 => /usr/lib/libuniventionconfig.so.0 (0x00007f8b3be00000)
libldap-2.5.so.0 => /usr/lib/x86_64-linux-gnu/libldap-2.5.so.0 (0x00007f8b3b900000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8b3b600000)
...
libasan.so.5. AddressSanitizer. Direkt gelinkt. In einem Production-Binary.
Das ist das /usr/bin/univention_policy_result-Binary aus dem Paket univention-policy-tools 11.0.4-4, das mit UCS 5.0-9 ausgeliefert wurde.
dpkg -l univention-policy-tools
ii univention-policy-tools 11.0.4-4 amd64 Univention Policy Tools
Version bestätigt. Debug-Build in Produktion bestätigt.
Schritt 4: journald unter Last
Warum war journald bei 50-60 % CPU? Weil es 2,6 Millionen Zeilen in die Datenbank schreiben wollte:
journalctl --disk-usage
Archived and active journals take up 4.2G in the filesystem.
4,2 GB Journals. Für einen einzigen Boot-Vorgang. Das sind ausschließlich AddressSanitizer:DEADLYSIGNAL-Einträge im Millionenformat.
Die Ursache
Was ist AddressSanitizer?
AddressSanitizer (ASan) ist ein Memory-Error-Detector, entwickelt von Google. Wenn man ein Programm mit -fsanitize=address kompiliert, passiert folgendes:
- Shadow Memory Mapping: ASan reserviert 1/8 des gesamten Adressraums als Shadow Memory. Auf einem 64-Bit-System sind das theoretisch ~18 TB, in der Praxis reserviert ASan typischerweise ~21 TB virtuellen Adressraum.
- Jeder Speicherzugriff wird instrumentiert: Vor jedem Read/Write prüft ASan über das Shadow Memory, ob der Zugriff gültig ist.
- Performance-Overhead: Ca. 2x langsamer, 1,5-3x mehr RAM-Bedarf.
Das ist ein Entwicklungs- und Test-Tool. Es gehört nicht in Produktion. Niemals.
Warum ist es in UCS 5.0-9?
Das ist eine gute Frage, die Univention beantworten muss. Vermutlich ist ein Debug-Build versehentlich in den Release-Prozess gerutscht. Das passiert – aber für ein Production-Paket ist das ein schwerwiegender Fehler im Release-Management.
Das binary /usr/bin/univention_policy_result wurde mit ASan kompiliert und das Paket ohne Qualitätsprüfung ausgeliefert.
Warum explodiert es erst im LXC-Container?
Auf einer vollwertigen VM oder einem Bare-Metal-Server mit viel RAM fällt es möglicherweise nicht auf: 21 TB virtueller Adressraum ist kein Problem, solange niemand wirklich 21 TB RAM hat. Der Prozess würde trotzdem langsamer sein, aber der OOM-Killer würde nicht sofort eingreifen.
In einem LXC-Container mit 8 GB RAM passiert folgendes:
- ASan startet und versucht, das Shadow Memory zu mappen
- Das Mapping schlägt fehl (kein Speicher)
- ASan bricht mit
DEADLYSIGNALab - Aber vorher hat der Prozess bereits genug echten RAM allokiert, um alles andere zu verdrängen
- OOM-Killer beendet den Prozess
- Systemd startet ihn neu
- Das gleiche passiert wieder - in einer Schleife, bis der Service als
failedmarkiert wird
Die Lösung
Workaround: ASan per Umgebungsvariable zähmen
Bis Univention ein Errata liefert, kann ASan per ASAN_OPTIONS so konfiguriert werden, dass es keinen Schaden anrichtet:
Systemd-Override anlegen:
mkdir -p /etc/systemd/system/univention-directory-policy.service.d/
cat > /etc/systemd/system/univention-directory-policy.service.d/asan-workaround.conf << 'EOF'
[Service]
Environment="ASAN_OPTIONS=abort_on_error=0:detect_leaks=0:log_path=/dev/null:disable_coredump=1:allocator_may_return_null=1"
EOF
Das gleiche für univention-maintenance:
mkdir -p /etc/systemd/system/univention-maintenance.service.d/
cat > /etc/systemd/system/univention-maintenance.service.d/asan-workaround.conf << 'EOF'
[Service]
Environment="ASAN_OPTIONS=abort_on_error=0:detect_leaks=0:log_path=/dev/null:disable_coredump=1:allocator_may_return_null=1"
EOF
Die wichtigsten Optionen erklärt:
| Option | Bedeutung |
|---|---|
abort_on_error=0 | Bei Fehler kein SIGABRT mehr, Prozess läuft weiter |
detect_leaks=0 | LeakSanitizer deaktivieren (spart RAM) |
log_path=/dev/null | Keine DEADLYSIGNAL-Spam mehr in journald |
disable_coredump=1 | Kein Coredump bei Crash |
allocator_may_return_null=1 | Bei OOM null zurückgeben statt aborten |
systemctl daemon-reload
Services temporär deaktivieren (optional, aber empfehlenswert)
Bis zum Errata-Fix können beide Services sicher deaktiviert werden. univention-directory-policy synchronisiert UCR-Policies aus dem LDAP – wichtig für Policy-Änderungen, aber kein kritischer Daemon für den laufenden Betrieb:
systemctl disable --now univention-directory-policy.service
systemctl disable --now univention-maintenance.service
Wann wieder aktivieren? Sobald Univention univention-policy-tools in einer bereinigten Version ausliefert. Prüfen mit:
apt-cache policy univention-policy-tools
Sobald eine Version > 11.0.4-4 verfügbar ist: Services wieder aktivieren, Override entfernen, testen.
Kollateralschaden: zabbix-agent2
Durch den RAM-Engpass beim Boot scheitert nss-ldap manchmal, bevor zabbix-agent2 startet. Das erzeugt einen kaputten PID-Directory-Fehler:
journalctl -u zabbix-agent2 --no-pager | tail -20
Apr 08 06:31:55 dc-vader zabbix_agent2[2112]: cannot create PID file [/run/zabbix/zabbix_agent2.pid]: [13] Permission denied
Fix:
mkdir -p /run/zabbix
chown zabbix:zabbix /run/zabbix
chmod 755 /run/zabbix
Damit das nach jedem Reboot erhalten bleibt:
cat > /etc/tmpfiles.d/zabbix-agent2.conf << 'EOF'
d /run/zabbix 0755 zabbix zabbix -
EOF
systemd-tmpfiles --create /etc/tmpfiles.d/zabbix-agent2.conf
systemctl restart zabbix-agent2
Journal aufräumen
Nach dem Workaround lohnt es sich, den Journal-Müll zu beseitigen:
journalctl --vacuum-size=500M
Lessons Learned
1. ASan in Production-Binaries ist ein Release-Management-Versagen.
Ein einfaches ldd /usr/bin/univention_policy_result | grep asan in der CI/CD-Pipeline hätte das verhindert. Das ist kein exotischer Check – das ist Basisqualitätssicherung für System-Packages.
2. Symptome und Root Cause können weit auseinanderliegen.
Das erste sichtbare Symptom war „Service failed". Die naheliegendste Diagnose wäre: „LDAP nicht erreichbar", „Python-Script kaputt", „Config-Fehler". Die tatsächliche Ursache war eine 20 Jahre alte Debug-Toolchain, die versehentlich in einem Production-Build landete.
3. 21 TB VSZ ist kein Speicherleck - es ist ein Red Flag.
Ein normaler Python-Prozess hat nie 21 TB virtuellen Adressraum. Wenn ps aux solche Zahlen zeigt, ist das ein sofortiger Hinweis auf ASan, Valgrind oder ähnliche Instrumentierungs-Tools.
4. ldd auf verdächtige Binaries ist unterschätzt.
ldd /usr/bin/<verdächtiges-binary> | grep -E 'asan|tsan|ubsan|msan'
Wenn dieser Befehl Output produziert: Das Binary gehört nicht in Produktion.
5. LXC-Container mit wenig RAM sind ehrlicher als fette VMs.
Auf einem Server mit 128 GB RAM wäre das Problem wahrscheinlich nie aufgefallen – der Prozess wäre nur langsamer gewesen. Tight-memory-Umgebungen zwingen dazu, solche Fehler zu finden.
Meldung an Univention
Das sollte als Bug gemeldet werden. Univention betreibt ein öffentliches Bug-Tracking-System:
- Bugzilla: https://forge.univention.org/bugzilla/
- Betreff:
univention-policy-tools 11.0.4-4: Production binary linked against libasan.so.5 (ASan debug build) - Paket:
univention-policy-tools - Version:
11.0.4-4 - UCS-Version:
5.0-9
Je mehr Meldungen, desto schneller kommt das Errata.
Reproduziert auf: UCS 5.0-9, LXC-Container, dc-vader.deathstar.lan, 192.168.66.x-Netz
Fix getestet: 2026-04-08