Für sicherheitsrelevante Steuerungssysteme werden von der FuSi Maßnahmen zur Erhöhung der Gerätesicherheit gefordert. Abhängig von der ASIL-Klassifikation können neben Anforderungen wie Architektur, Coding und Tests auch funktionale Tests gefordert werden.

In diesem zweiteiligen Beitrag soll ein Überblick über mögliche FuSi Maßnahmen in embedded Systemen gegeben werden.

Im zweiten Teil werden FuSi Maßnahmen zur Überprüfung des Programmablaufs (PFM – Program Flow Monitoring), sicheres Speichern von Laufzeitvariablen (SDS – Safety Data Storage) und weitere Möglichkeiten zur Erhöhung der Betriebssicherheit wie Verwendung von Invalid Opcode, Umgang mit Interruptvektoren und Konfigurationsregistern sowie Output Pins und unbenutzte Pins erörtert.

PFM – Program Flow Monitoring
Das Program Flow Monitoring soll den korrekten, aufeinanderfolgenden Ablauf der verschiedenen sicherheitsrelevanten Programmteile innerhalb eines Programmzyklus sicherstellen. Für den embedded Bereich bietet sich eine schlanke Lösung mittels einer Checksummenberechnung an. Dazu wird ein Programmzyklus in mehrere sicherheitsrelevante Abschnitte, so genannte Checkpoints, unterteilt. Jeder Checkpoint erhält eine eindeutige Nummer.

Am Startpunkt eines Zyklus wird die Checksumme initialisiert. An jedem erreichten Checkpoint wird die Checksumme mit der zugeordneten, eindeutigen Nummer weiter gerechnet. Wenn der Zyklus beendet ist, wird die errechnete Checksumme mit einer zuvor bestimmten Referenzchecksumme verglichen. Es ist zwingend notwendig, dass alle zu überprüfenden Programmteile in einer wiederkehrenden, deterministischen Reihenfolge abgearbeitet werden. Die einzelnen Programmteile können auch mehrfach während eines Zyklus ausgeführt werden. Wenn die Programmteile von Zyklus zu Zyklus in wechselnder, nicht vorhersehbarer Reihenfolge aufgerufen werden, führt das zu Fehlermeldungen des PFM.

Die Referenzchecksumme muss zuvor durch einen sicheren Zyklus ermittelt werden oder mittels eines separaten, externen (PC) Programms, welches die Aufrufreihenfolge abbildet.

Je nach Ergebnis wird nach Beendigung der laufenden Prüfung eine Reaktion (fail/pass) veranlasst.

Die Art der Checksumme CRC32, CRC16 oder CRC8 und die einzubeziehenden Programmteile sind abhängig von den FuSi Anforderungen.

SDS – Safety Data Storage
Die Integrität von veränderlichen Daten ist in einer sicherheitsrelevanten Anwendung von hoher Bedeutung. Neben den in der Hardware möglicherweise integrierten Maßnahmen zur Fehlererkennung und Korrektur (ECC), gibt es Softwaremaßnahmen, die manipulierte Daten erkennen und eine entsprechende Reaktion auslösen.

Mögliche Maßnahmen sind:

  • Sicherung eines Speicherblocks mittels Checksumme
  • redundant – inverse Speicherung von Variablen

Bei der Sicherung mittels Checksumme werden die sicherheitsrelevanten Variablen in einem Block zusammengefasst, idealer Weise in einer Struktur. Bei jedem Schreibvorgang auf diesen Block wird die Checksumme neu berechnet und abgelegt. Die Prüfung der Checksumme kann bei jedem Lesevorgang oder zyklisch erfolgen, sofern die Zykluszeit innerhalb der Fehlertoleranzzeit des Systems liegt.

Das Konzept der redundant – inversen Speicherung sieht vor, dass neben der normalen Variable eine Kopie mit invertierten Inhalt abgelegt wird. Für jeden benötigten Datentyp wird eine entsprechende Struktur und ein dazugehöriger Satz an Makros bzw. Funktionen bereit gestellt (Initialisieren, Schreiben, Prüfen und Lesen).

Beim Initialisieren bzw. Schreiben wird der normale Datenbereich und der inverse Datenbereich entsprechend beschrieben. Die Prüffunktion validiert die Datenintegrität und liefert pass/fail als Ergebnis. Die Lesefunktion validiert die Datenintegrität ebenso wie die Prüffunktion, liefert aber als Ergebnis den Inhalt des normalen Datenbereichs. Im Fehlerfall wird implizit eine Fehlerfunktion gerufen, die den Fortlauf des Programms bestimmt.

Beide Methoden haben Vor- und Nachteile
Die Blockmethode benötigt mehr Rechenzeit, besonders dann, wenn mit jedem Lesevorgang die Checksumme neu berechnet wird. Da sollte man lieber zur zyklischen Prüfung greifen. Der Speicherbedarf hält sich in Grenzen, da nur die Checksumme zusätzlich gehalten werden muss. Die redundant – inverse Methode ist schneller in der Ausführung, da nur die Variable mit ihrem Komplement verglichen wird und keine weiteren Berechnungen notwendig sind. Der Speicherbedarf ist letztendlich doppelt so groß, wie an normalen Variablen benötigt wird.

Welche Maßnahme zum Einsatz kommt, hängt in hohem Maße von den verfügbaren Ressourcen ab und natürlich von den FuSi Anforderungen.

Verwendung von Invalid Opcode
Eine weitere FuSi Anforderung ist, den unbenutzten Programmspeicher mit invalid opcode zu füllen. Es soll verhindert werden, dass ein fehlgeleitetes Programm undefinierte Operationen ausführt. Stattdessen soll der Prozessor eine Fehlerbehandlung in Form eines invalid opcode trap ausführen und dort in einer Endlosschleife verbleiben, bis der Watchdog einen Reset auslöst.

Bei den ARM Cortex-M Prozessoren sollte ein leerer Speicher mit 0xFFFF ausreichend sein, um eine hardfault exception auszulösen. Die entsprechende Interrupt Service Routine sollte dann in einer Endlosschleife enden.

Ein Atmega z. B. kennt keinen invalid opcode trap. Hier kann man sich mit dem Opcode für eine Endlosschleife behelfen (0xFFCF -> while(1)).

Die Fehlerreaktion ist in jedem Einzelfall zu prüfen.

Umgang mit Interruptvektoren
Alle nicht verwendeten Interruptvektoren sollen auf eine zentrale Interrupt Service Routine zeigen. Diese Routine soll mit deaktivierten Interrupts eine Endlosschleife ausführen. Dies soll verhindern, dass durch Fehlkonfiguration aktivierte Interruptquellen das Systemverhalten beeinflussen. Außerdem sollte man Herr über seine Software sein und wissen, was abläuft. Das schließt weak Attribute an Funktionen aus, insbesondere bei Interrupt Service Routinen. Eine weak Funktionen wird durch eine möglicherweise vorhandene strong Funktion verdeckt. Es kann so ein ungewollter Code ausgeführt werden.

Umgang mit Konfigurationsregistern
Zyklisches Lesen von Konfigurationsregistern und Prüfung auf korrekten Inhalt. Im Fehlerfall wird der Initialwert zugewiesen und ggf. eine Fehlerfunktion ausgeführt. Die Zykluszeit und Fehlerreaktion werden durch die FuSi Anforderungen vorgegeben.

Umgang mit Output Pins
Zyklisches Schreiben der Output Pins.

Die Zykluszeit wird durch die FuSi Anforderungen vorgegeben.

Umgang mit unbenutzten Pins
Initialisierung von unbenutzten Pins auf unkritische Funktionalität, z.B. Input mit Pullup.

Die Vorgaben sollten von der Hardwareentwicklung in Abstimmung mit den FuSi Vorgaben erfolgen.