Sichere Software für Embedded-Systeme Mensch und Maschine müssen sich ergänzen

Ein Tool alleine kann die Fehlerfreiheit von Embedded-Software nicht garantieren. Nur eine sinnvolle Kombination aus den Fähigkeiten eines menschlichen Entwicklers sowie der effizienten, automatisierten Unterstützung durch Analyse-Tools kann ein Höchstmaß an Sicherheit erreichen.

In unserer heutigen digitalen Lebenswelt ist Software allgegenwärtig. In manchem modernen Fahrzeug stecken heutzutage mehr Zeilen an Softwarecode als in einer Boeing 787 – und dabei sprechen wir noch längst nicht vom autonomen Fahren. Tritt der Fahrer eines klassischen Fahrzeugs aufs Gaspedal, reguliert er keineswegs mehr mechanisch die Beschleunigung, sondern löst einen digitalen Befehl aus, auf dessen Basis eine Software steuert, wie viel Benzin in den Motor eingespritzt wird. Anstelle eines Gaspedals könnte er genauso gut eine Taste auf einer Tastatur betätigen, der Effekt wäre derselbe.

In dem Maße jedoch, in dem Software zunehmend die Steuerung von für uns kritischen Embedded-Systemen, Geräten oder gar Infra­strukturen übernimmt, sind wir ebenso stark auf eine einwandfreie Funktionsfähigkeit der dahinterstehenden Logik angewiesen. Im schlimmsten Fall gefährden Software-Bugs die Gesundheit oder gar das Leben von Menschen.

Reale Vorfälle haben die damit verbundene Brisanz bereits mehrfach verdeutlicht. So musste 2014 ein Automobilhersteller eine hohe Strafe wegen unbeabsichtigter Beschleunigung zahlen, nachdem es sogar zu mehreren tödlichen Unfällen im Zusammenhang damit gekommen sein soll. Eine spätere Analyse des Softwarecodes durch den Experten für Embedded-Software Michael Barr hatte gezeigt, dass dieser derart fehlerhaft und kompliziert geschrieben war, dass sich keine sinnvolle Testmethodik entwickeln ließ, um dessen Funktion überhaupt erschöpfend zu untersuchen.

Im April 2017 nahm ein Medizintechnikhersteller ein Beatmungsgerät vom Markt, bei dem die Gefahr bestand, dass es sich aufgrund eines Softwarefehlers unerwartet abschaltete. Beispiele wie diese machen deutlich, wie wichtig es ist, dass Embedded-Hersteller ein Höchstmaß an Sicherheit in ihrem Softwarecode sicherstellen – und ein entsprechend hohes Gewicht auf umfassende und sorgfältige Testprozesse legen.

Gerade C und C++, zwei der zentralen Programmiersprachen in der Embedded-Branche, geben Entwicklern ein hohes Maß an Flexibilität – und genau diese ist auch notwendig, um den steigenden Anforderungen an Leistung und Funktionen gerecht zu werden. Gleichzeitig bedeuten höhere Freiheitsgrade jedoch auch ein höheres Risiko, unbeabsichtigte Fehler in den Code zu integrieren, die dann im finalen Produkt zu Bugs oder Sicherheitslücken führen. Ein Dilemma, denn gerade in Zeiten, in denen diese in der Praxis immer weniger akzeptiert werden können, wird es damit gleichzeitig immer schwerer, tatsächlich fehlerfreien Code sicherzustellen.

Entsprechend kommt dem möglichst umfassenden Prüfen und Testen des Codes eine zentrale Bedeutung zu. Die klassische – und grundlegende – Vorgehensweise hierzu stellt nach wie vor die manuelle Softwareprüfung durch einen menschlichen Entwickler dar. Eine Analyse des Experten für Software-Qualität Capers Jones kommt dabei zu dem Ergebnis, dass Entwickler in ihrem eigenen Code weniger als die Hälfte der Fehler finden. Das Heranziehen einer zweiten Person ist daher unerlässlich. Entsprechend dem Vier-Augen-Prinzip wird entwickelter Code bei der manuellen Prüfung in der Regel an einen Reviewer gegeben, der die entsprechenden Abschnitte auf Fehler oder Mängel hin untersucht. Im Zentrum stehen dabei sowohl die Funktion des Codes (Macht die Funktion das, was sie machen soll?) als auch die Integrität (Verhält sich die Software auf eine vorhersehbare Art und Weise?) und der Stil (Ist der Quellcode sauber und den Programmierstandards entsprechend geschrieben?).

All diese Aspekte an fremdem Code zu prüfen ist eine anspruchsvolle Aufgabe. Die Qualität der Prüfung ist hochgradig von der Expertise des Reviewers abhängig. Darüber hinaus ist der entsprechende Prozess sehr zeitintensiv: Menschliche Prüfer benötigen in der Regel sehr lange, um komplexe Code-Abschnitte nachzuvollziehen und den Sinn einer Funktion zu verstehen. In der Regel schaffen sie nur wenige hundert Codezeilen pro Stunde.

Gerade dieser hohe Zeitaufwand stellt in Zeiten des heutigen Wettbewerbs ein zunehmendes Spannungsfeld für Embedded-Entwickler dar. Denn die sorgfältige Durchführung zeitintensiver manueller Prüfprozesse verlangsamt den Release-Zyklus der Software und verzögert damit eine schnelle Markteinführung. Da jedoch gerade diese nicht selten den entscheidenden Erfolgsfaktor darstellt, erhält Geschwindigkeit immer öfter den Vorzug vor Fragen der Sicherheit.

Eine Problematik, die nicht zuletzt auch durch den Trend zur Nutzung von Open-Source-Komponenten zusätzliche Brisanz erhält: Um Entwicklungszeiten möglichst gering zu halten, greifen immer mehr Embedded-Hersteller auf die Wiederverwendung von Open-Source-Komponenten in ihren Softwareprodukten zurück. Doch befinden sich darin bereits ihrerseits Software-Bugs – und werden diese nicht durch eine umfassende Prüfung entdeckt –, sind Cyber-Kriminelle unter Umständen in der Lage, nicht nur die Produkte eines Herstellers zu hacken, sondern im schlimmsten Fall Millionen von Geräten, die diese Komponente verwenden.