Einfache Sicherheit - Komplexe Gefahr

Sergio Montenegro (.)
GMD-FIRST (http://www.first.fhg.de)

(1.81)

Bei der Entwicklung sicherheitsrelevanter Systeme, deren Versagen tödliche Folgen haben kann, stehen Sicherheit und Funktionalität oft gegeneinander, wie die Abbildung 1 zeigt. Die Sicherheit ist diese lästige Eigenschaft, die die Funktionalität begrenzt; man kann nicht so schnell fahren, wie die Maschine eigentlich könnte, man muß Abstand halten usw. Man merkt erst dann, daß die Sicherheit wichtig ist, wenn man sie braucht und sie nicht da ist. Aber dann ist es meistens schon zu spät. Dann erkennt man den Wert der Sicherheit, der weit über ihrem Preis liegt.

 

Im Folgenden zwei Beispiele, wo Sicherheit und Funktion gegeneinander stehen und wo wir einen Kompromiß wählen müssen: 1. Ein Auto, das niemals fährt, ist sicher: es geht keine Gefahr von ihm aus, es ist aber nicht brauchbar. Ein Auto, das immer fahren kann, auch wenn es auseinanderfällt, hat die höchste Verfügbarkeit, ist aber nicht sicher. 2. Oft wird eine potentielle Gefahr rechtzeitig erkannt. Bei der Behandlung der Ausnahme- oder Fehlersituation entsteht ein Dilemma: Sicherheit oder Verfügbarkeit. Bei einer höheren Sicherheit müssen sofort beim Erkennen einer potentiellen Gefahr die Notmaßnahmen eingeleitet werden, um das System in einen sicheren Haltzustand zu bringen. Bei einer höheren Verfügbarkeit wird das System weiter bis an die Gefahrengrenze betrieben. Die Notmaßnahmen werden erst eingeleitet, wenn es sicher ist, daß ohne Notmaßnahmen ein Unfall eintreten wird. Bei dieser Abschätzung kann man sich sehr leicht vertun und dann geschieht ein Unfall.

Die Sicherheit braucht man angesichts einer Gefahr, die meistens aus der Umgebung kommt, die wir selbst für uns geschaffen haben, z.B. aus den Maschinen, die uns helfen sollen, aber bei denen die Sicherheitsaspekte nicht im Vordergrund stehen, und das ist meistens der Fall. Es wird mehr in die Funktionalität der Maschinen als in ihre Sicherheit investiert. Technologischer Fortschritt bedeutet nicht unbedingt eine höhere Sicherheit. Man hat wieder die Wahl, ob die neuen Möglichkeiten benutzt werden sollen, um die Sicherheit oder die Funktionalität des Systems zu steigern. Meistens wird das letztere gewählt. Man versucht, mit demselben alten Risiko eine höhere Funktionalität anzubieten. Beispielsweise wird versucht, daß das System schneller fährt, gleich schnell bei schlechterem Wetter oder daß es weiter arbeiten kann, trotz höherer Explosionsgefahr usw., ohne die Gefahr und das Risiko zu steigern. Das ist schon etwas, aber im Endeffekt können Risiko und Gefahr sogar steigen, ohne daß man es merkt. Bei der Luftfahrt wird mit der Verbesserung der Technologie schneller, höher und mit geringerem Abstand zwischen Flugzeugen geflogen, ohne das Risiko zu steigern (hoffentlich). Durch instabileres aerodynamisches Verhalten wird ein niedrigerer Luftwiderstand erreicht und dadurch der Kraftstoffverbrauch reduziert. Die zusätzliche Gefahr aus der instabilen Lage wird durch eine rechnergesteuerte Regelung kompensiert, um das Flugzeug stabil und lenkbar zu halten. Bei den Zügen wird mit neuen Technologien versucht, den Abstand zwischen Zügen zu minimieren und ihre Geschwindigkeit zu erhöhen, auch bei engen Kurven, wo es früher nicht möglich war, und das, ohne die Gefahr zu steigern (hoffentlich).

Daß uns die Funktionalität wichtiger als die Sicherheit ist, kann man auch bei der Zigarettenwerbung beobachten. Es wird sehr Groß geschrieben "Probieren sie den Genuß.." und ganz klein "Vorsicht, das ist gefährlich". Andersherum: Wenn man ganz groß schreiben würde: "Gefahr" und dann klein: "Aber wenn Sie trotzdem rauchen wollen, dann probieren Sie den Genuß"....

Aber wie gesagt, Sicherheit ohne Funktion ist nutzlos -- aber noch schlimmer ist Gefahr ohne Funktion. Was wir von einer Anlage erwarten ist nicht nur Sicherheit oder Verfügbarkeit, sondern Verläßlichkeit, d.h. daß das System seine Aufgabe erfüllt. Die Verläßlichkeit besteht, wie es in der Abbildung 2 dargestellt ist, aus:

 

Die Funktionalität wird als Zuverlässigkeit und Vertraulichkeit definiert. Aber Vorsicht: Ist ein System als sehr zuverlässig und sicher bewertet worden, heißt das nur, daß wenige Fehler sich bemerkbar machen. Absolute Verläßlichkeit ist in technischen Systemen kaum möglich.

Was tun?

Die Grenze zwischen Sicherheit und Funktion kann hin und her diskutiert werden, bis entschieden wird, daß das System sicher genug ist. Dann bekommen wir als Ingenieure bestimmte Mittel, um die Sicherheit zu implementieren. Unsere Aufgabe ist es, mit diesen Mitteln die Sicherheit zu maximieren, ohne die Funktionalität (zu viel) zu reduzieren. Dies scheint schwierig zu sein, aber es ist sehr einfach, man braucht nur alles so einfach wie möglich zu machen -- aber nicht einfacher.

Die Sicherheit (und auch die Verläßlichkeit) einer Anlage baut auf zwei Aspekten auf: 1. Die Entwicklung war korrekt, so daß das System macht, was es machen soll -- unter allen möglichen Zuständen. 2. Laufzeitfehler wie Ausfälle (z.B. Hardware, Mechanik), Ausnahmen (Bedienungsfehler, unerwartete Umgebung) und unentdeckte Entwicklungsfehler werden erkannt und rechtzeitig behandelt.

Diese Aspekte können am besten bei einfachen Systemen realisiert werden.

Einfach: Es soll einfacher werden

Wenn die Komplexität eines Systems steigt, sinken seine Sicherheit und insgesamt seine Verläßlichkeit, da ein Versagen jeder Komponente das Versagen des Gesamtsystems bedeuten kann (muß aber nicht), die Entwicklung unübersichtlicher wird und die Anzahl der Schnittstellen (Schwachstellen und Fehlerquellen) steigt. Sicherheit kann durch Einfachheit gefördert werden. Denn der erste Feind der Sicherheit ist die Komplexität. Deswegen ist die einfachste Lösung die beste (die sicherste).

Auch eine komplexe Bedienung ist eine gefährliche Sache. Dabei werden "Bedienungsfehler" vorprogrammiert. Z.B. ist mir die Bedienung unserer rechnergesteuerten Waschmaschine nach wie vor ein Rätsel. Für moderne Kochherde bieten die Hersteller sogar Einführungskurse an. Ohne den Kurs wird man kaum damit zurecht kommen. Das gleiche kann man beim "modernen" Videorecorder beobachten. Ohne eine 100-seitige Gebrauchsanweisung geht nichts mehr. Dies sind aber einfache Geräte. Bei den komplizierten Geräten ist ein Bedienungsfehler wirklich vorprogrammiert, und wenn der "Bedienungsfehler" in einem sicherheitskritischen Moment geschieht, dann hat man den Unfall vorprogrammiert. Dagegen hilft nur "Einfach bleiben" und die wichtigsten Funktionen nicht mit unwichtigen Zusätzen zu überladen.

Oft wird die Funktionalität überdimensioniert, um einen höheren Komfort anzubieten. Aber dadurch rückt die primäre Funktionalität in den Hintergrund und man kann sie schlechter erreichen. Um die wichtige Funktion zu aktivieren, muß der Benutzer sich durch ein Labyrinth von unwichtigen, aber verwirrenden Funktionen durchkämpfen. Dadurch steigt die Wahrscheinlichkeit von Benutzerfehlern und die Sicherheit des Systems sinkt. Der Benutzer ist sogar bereit, einen eingebetteten Rechner in seinem Gerät zu tolerieren, aber der Rechner soll zumindest nicht stören oder die Bedienung verkomplizieren [Mangold].

Die Entwicklung der Sicherheitseinrichtungen kann auch durch die Komplexität ineffektiv werden. Die wichtigsten Sicherheitsanforderungen sind meistens sehr einfach und können in einen einzigen Chip z.B. in einen PAL (Programable Array Logik), implementiert werden. Nehmen wir ein Beispiel: Wenn der Druck zu hoch ist, ist ein Entleerungsventil zu öffnen. Manchmal reicht ein Stück Mechanik wie z.B. ein Ventil mit einer Feder, die bei einem kritischen Druck nachgibt. Oder noch einfacher wäre ein Ventil, das durch sein eigenes Gewicht zugehalten wird, bis der Druck so hoch ist, daß es springt (wie die alten Schnellkochtöpfe). Eine komplexere Lösung wäre z.B. ein elektronischer Drucksensor, der ein Signal zu einen PAL-Chip liefert, und der PAL sendet ein Signal zu einem elektrischen Ventil, um es zu öffnen. Aber meistens wird auch für solche einfachen kritischen Aufgaben die komplizierteste Lösung mit einem Rechner vorgezogen. In diesem Fall bekommt man folgenden Fluß: Ein Drucksensor meldet einen Wert, es wird ein Interrupt erzeugt, das laufende Programm wird unterbrochen, das Betriebssystem rettet den Zustand des laufenden Programms, das Betriebssystem aktiviert den Interrupthandler, der Interrupthandler aktiviert das passende Programm, um diese Ausnahme zu behandeln, das Programm wird initialisiert, es ruft den Gerätetreiber, um den Druck zu prüfen usw., bis endlich der Gerätetreiber für das Ventil aufgerufen wird, damit er den Öffnen-Befehl an das Ventil sendet. Und irgendwann später wird das unterbrochene Programm wieder aktiviert. Alle diese Module zusammen bestehen aus mehr als Hunderttausend lines-of-code (OS. Treibers, u.a.), bis das Ventil geöffnet wird, werden mehr als Tausend Prozessorbefehle ausgeführt, und dabei werden mehr als eine Million Transistoren (Prozessor, Speicher, u.a.) benutzt. Ein einziger Fehler in diesem großen Fluß kann die Sicherheitshandlung blockieren, und ein Unfall kann eintreten. Bei einer Lösung wie in der Abbildung 3 kann jeder lachen und erkennen, daß zu viel schief gehen kann (wird), daß es nur ein Witz sein kann (darf). Bei der Rechnerlösung mit vielen Seiten Spezifikation (Die Abbildung 3 war nur 1/4 Seite) und hunderten von Seiten Programm, plus hunderte Seiten Prozessor-Entwurf, plus viele andere Komponenten, lacht keiner. Das wird als eine seriöse, gute Lösung angenommen. Warum? Was ist der Unterschied? Solche Komplexität soll bei kritischen, aber einfachen Anforderungen lieber nicht in Kauf genommen werden. Eine einfache Feder oder ein einziger PAL könnte es besser und sicherer tun als ein Rechner.

 

Ein Waschmaschinenhersteller hatte eine Sicherung, damit die Tür nicht geöffnet werden kann, solange die Temperatur des Waschwassers über 50 Grad liegt. Sie war einfach. Ein Metallpin hat dieselbe Temperatur wie das Wasser. Wenn er warm ist, dehnt er sich so, daß er das Türschloß blockiert. Um modern und flexibel zu sein, wurde diese Einrichtung durch ein rechnergesteuertes Schloß ersetzt. Unter Bedingungen, die der Hersteller im labor nie reproduzieren konnte, ging dann dem Kunden die Tür beim kochwaschgang manchamal automatisch und spontan auf. Die alte, veraltete Sicherheitseinrichtung wurde wieder eingebaut.

Trennung von Sicherheit und Funktion

Die gesamten Funktionsanforderungen eines Systems sind wesentlich komplexer als seine Sicherheitsanforderungen und deswegen sind mehr Fehler bei der Funktion als bei der Sicherheit zu erwarten. Wenn wir die Sicherheitsaspekte abtrennen, können wir uns gezielter auf die Sicherheit konzentrieren, ohne viele irrelevante Aspekte mit berücksichtigen zu müssen. Bei der Spezifikation des Systems sollte eine explizite Trennung funktionaler und sicherheitsrelevanter Bestandteile erfolgen. Nach Möglichkeit sollten beide Spezifikationen sogar von verschiedenen Entwicklern gemacht werden. Die sicherheitsrelevanten Teile sollten so klein und einfach wie möglich und frei von für die Sicherheit irrelevanten Teilen gehalten werden.

Die Sicherheit sollte mit den einfachsten Mittel, die es gibt implementiert werden (es ist sicherer). Wenn sie von einem Rechner durchgeführt werden soll, sollte sie so einfach wie möglich programmiert werden und deutlich vom Rest der Funktion getrennt und übergeordnet sein.

Der Sicherheitsteil kann als einfache Bedingungstests implementiert werden. Dagegen braucht der Funktionsteil Servokontrolle, Regelungsschleife, Wegplanung, Wegtracking, Motion-Control, Positionskontrolle, Geschwindigkeitskontrolle u.a. und noch dazu eine Benutzerschnittstelle. Als Beispiel dient eine fahrende Anlage. Eine Sicherheitsanforderung könnte sein "mindestens 3 Meter Abstand zu vorausfahrenden oder stehenden Objekten halten". Die Funktionssteuerung ist komplexer. Sie mißt Geschwindigkeit, Abstand, Neigung, Winkel der Räder und Position, nimmt von einer Datenbasis den gewünschten Weg, berechnet die Sollwerte für die Motoren und andere Aktuatoren, kontrolliert die Istwerte und steuert die Aktuatoren. Diese Funktion ist viel komplexer als die entsprechende Sicherheit, die in einer Zeile programmiert werden kann:
"if(abstand < 3.0) Emergency_Action();"

Das sicherste wäre, alle Sicherheitstests in einem getrennten Prozessor zu implementieren, so daß die restliche Funktion diese kritischen, aber einfachen Teile nicht stören kann. Meistens ist dies aus Kostengründen nicht praktikabel. In diesen Fällen sollte die Funktion in einer sicheren Schale eingekapselt werden. Diese Schale soll klein und übersichtlich sein. z.B.:

void Sichere_Steuerung() {

Unsichere_Steuerung();

if(abstand < 3.0) Emergency_Action();

}

Modularisierung

Außer der üblichen Modularisierung, um eine saubere Systementwicklung durchzuführen, sollte auch eine sicherheitsorientierte Modularisierung stattfinden. Die sicherheitsrelevante Funktionalität wird von der restlichen Funktionalität getrennt und in wenigen sicheren Modulen eingekapselt. Bei wenigen Modulen ist es möglich, einen höheren Aufwand darin zu investieren, sie sicherer zu gestalten. Wenn die Sicherheitsaspekte im ganzen System zerstreut sind, sind sie nicht mehr durchschaubar und können nicht besonders behandelt werden.

Alle Module, die sicherheitsrelevante Daten bearbeiten (und weitergeben) werden als sicherheitskritische Module betrachtet. Wenn man nicht darauf Achtet und die sicherheitskritischen Daten durch das ganze System fahren läßt, bekommt man ein für die Sicherheit undurchschaubares System, wo alle Komponenten sicherheitskritisch geworden sind. (siehe Abbildung 4).

 

Viel besser und sicherer ist es, die sicherheitskritischen Daten in sichere Schnittstellen-Module einzukapseln. Diese Module können mit höherem Aufwand entwickelt werden, so daß sie das kritische Gerät nur im sicheren Bereich betreiben und steuern (Abbildung 5). Diese Module können dann gefährliche Befehle aus anderen (unsicheren) Modulen filtrieren und nur sichere Ansteuerung weitergeben.

 

Sicherheit ohne Fehlertoleranz

Ein fehlertolerantes System kann weiter seine Funktion erfüllen trotz Fehlern, Ausfällen und Ausnahmen. Das zu erreichen, ist eine schwierige Aufgabe und oft nicht nötig. Oft reicht es, dafür zu sorgen, daß das System zu einen sicheren stabilen (Halt) Zustand gebracht wird, wenn Fehler aufgetreten sind. Danach kann man das System reparieren und weiter betreiben.

Bei einem fehlertoleranten System müssen alle Komponenten redundant und voneinander unabhängig sein. Dies erfordert einen hohen Aufwand. Bei einem einfach sicheren System reicht es, ein Sicherheitsmodul einzubauen, das die Sicherheit der Anlage prüft und die passenden Notmaßnahmen bei Bedarf aktivieren kann. Das Sicherheitsmodul kann auf einer getrennten Hardware (Prozessor, Speicher, Sensorik, usw.) laufen, um eine höhere Sicherheit gegen Störungen aus dem Funktionsmodul zu erreichen. Aber dies ist nicht immer möglich. Wenn beide, das Funktions- und das Sicherheitsmodul auf derselben Hardware laufen, muß das Sicherheitsmodul mit einer höheren Priorität laufen und seine Adressbereiche müssen (per MMU) geschützt werden, um seine Integrität so weit wie möglich zu erhalten. Aber es bleibt die Unsicherheit, daß der Prozessor sich aufhängen kann, eventuell durch einen Fehler im Funktionsmodul. Dies muß durch einen Watchdog (Timer, Time out) gefangen werden, um auch in diesen Fällen eine Notfunktion aktivieren zu können.

Wenn das Sicherheitsmodul auf dedizierter Hardware läuft, sollte man ein extrem einfaches (oder gar kein) Betriebssystem anwenden und die Sicherheitsbedingungen zyklisch und nicht interruptgesteuert prüfen.

Das Sicherheitsmodul muß unabhängig vom Rest lauffähig sein. Es darf nicht auf eine Kommunikation mit dem Rest warten oder seine Berechnungen davon abhängig machen.

Beide Module (Funktion und Sicherheit) sollten sich gegenseitig beobachten, d.h. sie führen eine Watch-Dog Funktion, und Plausibilitätsprüfungen durch. Wenn das Sicherheitsmodul ein Fehlverhalten beim anderen entdeckt, kann es den anderen anhalten oder reinitialisieren und in der Zwischenzeit übernimmt das Sicherheitsmodul die Kontrolle über die Anlage. Die einfachste Lösung ist die Anlage sicher herunterzufahren. Eine etwas kompliziertere Lösung ist, die Anlage mit einer begrenzten Not-Funktionalität weiter zu betreiben, bis das Funktionsmodul wieder lauffähig ist. In jedem Fall braucht das Sicherheitsmodul nicht die vollständige Funktionalität der Anlage zu implementieren und kann daher viel einfacher, durchschaubarer und dadurch sicherer als das Funktionsmodul sein. Wenn das Funktionsmodul ein verdächtiges Verhalten beim Sicherheitsmodul entdeckt, kann es nichts direkt unternehmen, nur den Benutzer informieren, damit er die nötigen Handlungen durchführt.

Die Kopplung zwischen Sicherheitsmodul und Funktionsmodul kann folgende Formen annehmen:

1. Das Funktionsmodul meldet sich regelmäßig beim Sicherheitsmodul an. Die Meldungen erhalten Zustandsinformationen und Absichten. Dies ermöglicht eine Früherkennung, aber das Funktionsmodul muß um dieses Kommunikationsprotokoll erweitert werden. (Abbildung 6,a). Wenn die Meldungen verdächtig werden oder nicht zum erwarteten Zeitpunkt kommen, aktiviert das Sicherheitsmodul eine Notfunktion.

2. Das Sicherheitsmodul überwacht alle I/O-Aktivitäten des Funktionsmoduls. Dadurch kann es Fehlentscheidungen rechtzeitig beobachten. Das Funktionsmodul braucht keine Erweiterungen, aber eine spezielle Hardware ist notwendig. (Abbildung 6,b)

3. Das Sicherheitsmodul liest direkt regelmäßig den Zustand der kontrollierten Anlage, um fehlerhafte Situationen zu erkennen. Software und Hardware brauchen keine Erweiterungen, aber die Fehler werden sehr spät erkannt, möglicherweise nach dem Eintreten einer gefährlichen Situation. (Abbildung 6,b)

4. Das Sicherheitsmodul hat die vollständige Kontrolle über die Anlage. Das Funktionsmodul kann Befehle nur über das Sicherheitsmodul abgeben. Das Sicherheitsmodul prüft die Sicherheit jedes Befehls bevor es ihn weitergibt. (Abbildung 6,c). Bei einer reiner Software- implementierung ist das Funktionsmodul innerhalb des Sicherheitsmodul eingekapselt.

 

Außer diesen Anlagezustandsüberprüfungen kann das Sicherheitsmodul weitere Überprüfungen durchführen, um eine höhere Sicherheit zu erreichen. Es kann z.B. den Kontrollfluß des Steuerprogramms monitorieren (mit Hilfe des Steuerprogramms selbst) um feststellen zu können, ob alles normal läuft. Die Informationen über den erwarteten Kontrollfluß können automatisch vom Compiler generiert werden [Wildner]. Das Timing des Kontrollflusses kann durch andere automatisierte Analysen vorausgesagt werden.

Gefahr aus den Sicherheitsmaßnahmen

Ironischerweise können unsere Sicherheitsmaßnahmen selbst der Grund für Unfälle sein.

Wir müssen uns bewußt sein, daß unsere Sicherheitsmaßnahmen keine absolute Sicherheit garantieren können. Trotzdem können die Geräte oder Anlagen dadurch beim Benutzer so viel Vertrauen erlangen, daß sie ihnen ihr Leben blind anvertrauen, z.B. Autos, Ampeln, medizinische Geräte usw.. Durch die Routine ist man sich kaum noch bewußt, daß deren Versagen tödliche Folgen haben kann, d.h. wir vertrauen voll in ihre Sicherheit und Zuverlässigkeit dank der Routine und der eingebauten Sicherheitsfunktionen. Und um so schlimmer ist dann eine Fehlfunktion, mit der keiner gerechnet hat. Deswegen ist gar keine Sicherheit besser als eine falsche oder schlecht implementierte Sicherheit, die uns nur täuscht. Denn man verläßt sich darauf und vergißt die natürliche Vorsicht. Eine offensichtliche Gefahr ist viel besser als eine versteckte oder vertuschte. Die letztere ist nichts anderes als eine Falle -- und genau das erschafft man mit einer falsch implementierten Sicherheit.

Die Einführung eines zusätzlichen Frühwarnsystems um eine höhere Sicherheit zu bringen, kann auch zu einem zweischneidigen Schwert werden. Durch ein Frühwarnsystem kann der Rechner potentielle Gefahren durch ständige Überwachung entdecken und melden. Auch wenn es nicht offensichtlich ist, kann so eine zusätzliche Funktion neue Gefahren bringen. Die Menschen werden sich (nach einer Weile) auf das Frühwarnsystem blind verlassen und nachlässig werden. Wenn dann eine gefährliche Situation nicht gemeldet wird, z.B. wegen eines technischen Fehlers (was zu erwarten ist), hat man sehr wahrscheinlich einen Unfall. Dies wäre ohne das Frühwarnsystem nicht geschehen, denn der Operator wäre wachsamer gewesen. Das andere Extrem ist auch gefährlich. Das Frühwarnsystem ist zu empfindlich und meldet Gefahren, die keine sind. In diesem Fall verliert der Operator das Vertrauen in die Warnungen und kann dadurch Warnungen ignorieren, die eine wirkliche Gefahr signalisieren.

Eine nachträgliche Sicherheitsvorrichtung, die bei Entwurf und Entwicklung des Systems noch nicht konzipiert war, kann die Komplexität des System deutlich erhöhen und Inkonsistenzen ins System einbringen. Dadurch kann es vorkommen, daß sie mehr Unfälle verursacht als verhindert. Wenn die Gefahren bereits während des Entwurfs identifiziert werden können, ist es viel besser, sie durch eine Entwurfsänderung zu beseitigen, die die Komplexität nicht erhöht, als nachträglich zusätzliche Komponenten für die Sicherheit einzubauen. Oft werden unsichere Anlagen entworfen, bei denen in der Betriebsphase die Sicherheitslücken mit Sicherheitsvorrichtungen gestopft werden. Dies erhöht die Komplexität des Systems und seine Undurchschaubarkeit, aber nicht seine Sicherheit. Am Ende würde diese Anlage wie ein Sieb voll mit Flicken und mit Flicken auf älteren Flicken aussehen. Es ist viel besser, von Anfang an an die Sicherheit zu denken, ohne die Komplexität erhöhen zu müssen.

Oft können Sicherheitslücken durch Fehlerbeseitigung korrigiert werden. In diesen Fällen war die Sicherheit beim Entwurf vorgesehen, aber sie wurde schlecht implementiert. Diese Korrekturen können auch ein gefährliches Spiel werden. Bei komplexen Systemen, wo eine Änderung sehr umfangreich werden kann, kann man nicht ahnen, was für weitere Folgen die Korrektur bringen kann (z.B. ein Fehler wird korrigiert und drei neue werden eingebaut). In diesem Fall gilt: Drei wohlbekannte Fehler sind besser als ein unbekannter. Von den bekannten Fehler weiß man, man kann die Operatoren warnen und Umwege benutzen. Bei den unbekannten Fehlern lauert die Gefahr im Verborgenen. Sie sind ein Hinterhalt. Deswegen hat man bei sehr komplexen Systemen das Dilemma, ob eine bekannter Fehler korrigiert werden soll, oder on man lieber damit lebt.

Redundanz wird als eine Sicherheitsmaßnahme benutzt. Aber Redundanz alleine erhöht nicht die Sicherheit, nur die Komplexität und die Wahrscheinlichkeit von Komponentenausfällen. Eine NASA Studie über ein experimentelles Flugzeug fand heraus, daß alle Softwarefehler, die während eines Testfluges vorgekommen waren, aus den Fehlern eines redundanten Managementsystems und nicht aus der Steuerung selbst resultierten. Redundanz kann Sicherheit bringen, aber sie muß richtig benutzt werden und darf die Komplexität nicht wesentlich erhöhen.

Man könnte meinen, daß alle diese Probleme beim Testen gelöst werden können. Aber während die Zuverlässigkeit von einfachen Maschinen sich durch Prüfungen und Tests ermitteln läßt, ist die Beurteilung der Sicherheit von softwaregesteuerten Maschinen mit komplexem Verhalten äußerst schwierig. Hier können Tests nur das Vorhandensein von Fehlern zeigen, nicht aber deren Abwesenheit beweisen. Es ist nicht realisierbar, alle mögliche Systemzustände (mit der Zeit als Teilzustand), ihren Kombinationen und Reihenfolgen durchzuspielen und außerdem können Tests nicht immer unter allen möglichen oder erwartet realistischen Bedingungen durchgeführt werden. Wäre das möglich, dann wäre so ein Test wie eine Verifikation, die die Korrektheit des Systems beweisen könnte. Ein praktikabler Kompromiß ist ein systematischer Test, wo versucht wird, relevante Zustandsreihenfolgen zu identifizieren, zu minimieren und durchzuspielen [espress]. Aber Anforderungsfehler und Fehler, die auf falschen Annahmen beruhen, werden auch hier nicht entdeckt, sondern fallen frühestens in Praxistests oder schlimmstenfalls in der Anwendungsphase auf. Außerdem kann der Anteil der Test-Kosten bei den hier beschriebenen Systemen bis zu 80% der Gesamtentwicklungskosten betragen. Auch deswegen wird das System nicht nach jeder Änderung wieder vollständig getestet. Daher bringt jede Änderung ungeahnte, neue, latente Gefahren mit sich. Besonderes, da wo man sie nicht erwartet und weswegen nicht getestet wird.

Weitere Referenzen

Mein Buch: Sichere und Fehlertolerante Steuerungen

[espress]
http://www.first.fhg.de/~espress
ESPRESS: Ingenieurmäßige Entwicklung sicherheitsrelevanter eingebetteter Systeme.
Das Vorhaben ESPRESS zielt auf eine breite Verbesserung der Produktivität bei der Entwicklung komplexer, sicherheitsrelevanter, eingebetteter Systeme und auf eine Steigerung der Verläßlichkeit der Systeme selbst. Dies wird durch die Entwicklung einer durchgängigen, methodischen und werkzeugunterstützten Software-Technologie für spezifische Anwendungsgebiete erreicht.

./public
Verschiedene Publikationen und Informationen zum Thema Sicherheit und Echtzeit.

./seminar
Seminar an der Technischen Universität Berlin über Sicherheit, Hazard-Analyse, Fehlertoleranz, Analysen von Unfällen und Entwicklung sicherheitsrelevanter eingebetteter Systeme.

[Mangold] "zuviel elektronik verdirbt den Brei" Karlotto Mangold PEARL 96 Workshop. GI, Springer Verlag.

[Wildner] Compiler Assisted Self-Checking of Structural Integrity. Dissertation, Universität Potsdam, 1997 Monitoring des Kontrollflusses bei Steuerprogrammen, um Fehler frühzeitig zu erkennen; Validierung und Verifikation, Software Fehlertoleranz, Fehlerinjektion.