Racecondition, die Dritte
Wichtige Produktionssystem dürfen nicht manuell konfiguriert werden. Für alle Aufgaben gibt es definierte Update-Wege, die von spezialisierten Programmen umgesetzt werden. Dies soll sicherstellen, daß kein Admin mit dicken Fingern das System außer Tritt bringen kann. Letzte Nacht hat aber der Automatismus ein solches System getötet.
Es kamen drei Konfigurationsänderungen praktisch zeitgleich am System an. Ein Robot an anderer Stelle hatte diese veranlaßt. Diese liefen parallel los, werden aber serialisiert, um Fehler bei der Erstellung der Konfiguration zu vermeiden.
Lockfiles
Diese Serialisierung erfolgt über Lockfiles. Lockfiles können nur von genau einem Prozeß angelegt werden, wenn dieses noch nicht existiert. Bleibt eine solche Datei aber liegen, anstatt nach nach getaner Arbeit wieder entfernt zu werden, blockiert sie alle späteren Prozesse. Deswegen ist das Wegräumen des Lockfiles Bestandteil der Fehlerbehandlung aller Programme, die mit diesen Dateien arbeiten.
shlock(1) ist eine ähnliche Funktion, die aber prüft, ob der Lock-Eigner noch existiert, und ggf. das verwaiste Lock wegräumt. Eine solche Selbstreparatur ist hier explizit unerwünscht, da Stabilität immer Vorrang hat. Das System hat zu funktioniern, wenn auch im Zweifel mit nicht ganz aktuellen Werten. Erst nach Fehlerbeseitigung (wie konnte ein Lock verwaisen?), darf dieser Update-Pfad wieder aktiviert werden.
Ein Drei-Prozeß-System
In dem Fall, daß es nicht möglich ist, das Lockfile auch nach mehreren Versuchen anzulegen, meldet der Prozeß einen Fehler über seine normale Fehlerroutine. Genau diese Routine räumt am Ende aber das Lockfile weg. Dies ist in dem Fall, daß das Lockfile gar nicht angelegt werden konnte, aber selbst ein Fehler.
Heute nacht waren es also drei Prozesse, die parallel liefen:
- Der Erste konnte das Lockfile anlegen.
- Der zweite und der dritte Prozeß warteten gemeinsam auf eine Gelegenheit selbst das Lockfile anlegen zu können.
- Der zweite Prozeß gab nach einiger Zeit auf, weil der Erste noch lief. Er räumte im Rahmen dieser Fehlerbehandlung das Lockfile weg.
- Der dritte Prozeß erhielt nun selbst ein neues Lockfile unter dem gleichen Namen und begann ebenfalls mit der Abarbeitung.
- So liefen zwei Prozesse parallel, die auf die Konfiguration des Systems änderten.
- Dabei haben sie zwei gültige Konfigurationen überlappend übereinander geschrieben. Das Ergebnis war nicht mehr verarbeitbar.
Die Lockdatei wird nun nicht mehr gelöscht, wenn sie nicht selbst angelegt werden konnte.
Robustness Principle
Andererseits sollte man natürlich erzeugte Konfigurationen immer prüfen, bevor man sie anwendet. Dies ist aber nicht immer ganz einfach.
Viele Programme bieten zwar eine Konfigurationsprüfung an. Squid macht das prima. Apache macht das prima. FreeRadius macht das prima. Bind macht das prima.
All diesen Programmen ist aber gemein, daß die Daemonen durchlaufen. Die Existenz der neue Konfig bekommen sie per Signal übermittelt, dann versuchen sie diese einzulesen. Aber was passiert, wenn dies nicht funktioniert? Einige Programme verweigen das Laden der Konfig (bind), andere beenden sich (Apache, FreeRadius).
Umso wichtiger ist, die Konfiguration vor dem Laden zu prüfen. Doch die angebotenen Prüfungen sind lax. Viel zu lax. Bei Bind steht explizit, daß die Prüfung unzureichend ist.
named-checkconf checks the syntax, but not the semantics, of a named configuration file. The file is parsed and checked for syntax errors, along with all files included by it. Note: files that named reads in separate parser contexts, such as rndc.key and bind.keys, are not automatically read by named-checkconf. Configuration errors in these files may cause named to fail to run, even if named-checkconf was successful. named-checkconf can be run on these files explicitly, however.
Auch bei FreeRadius steht sowas da:
Note that there are many limitations to this check. Due to the complexities involved in almost starting a RADIUS server, these checks are necessarily incomplete. The server can return a zero status code when run with -C, but may still exit with an error when run normally.
Wie ernst solche Meldungen zu nehmen sind zeigt ein Thead bei FreeRadius, der mit einer klaren Empfehlung endet:
The preferred method is to have a test server. Generally you want a primary and secondary server anyways and often I will use the secondary to test minor changes since there is very little traffic there normally. Aside from that, I think you can change the port it listens on and start another process along side the production one. Then as long as you don't mess up the syntax when changing the port back, you should have your test.
Und in meinem Fall würde selbst das nichts helfen, weil der Reload erfolgt, während ein Dritter an der Konfig heraum schraubt.
Trotz dieser Erklärung ist es sinnvoll, die Details nochmals genauer unter die Lupe zu nehmen.