DE102023202348A1 - Verfahren zum Testen eines Computerprogramms - Google Patents

Verfahren zum Testen eines Computerprogramms Download PDF

Info

Publication number
DE102023202348A1
DE102023202348A1 DE102023202348.2A DE102023202348A DE102023202348A1 DE 102023202348 A1 DE102023202348 A1 DE 102023202348A1 DE 102023202348 A DE102023202348 A DE 102023202348A DE 102023202348 A1 DE102023202348 A1 DE 102023202348A1
Authority
DE
Germany
Prior art keywords
memory
computer program
watchpoint
protection zone
memory area
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Pending
Application number
DE102023202348.2A
Other languages
English (en)
Inventor
Christopher Huth
Max Camillo Eisele
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Robert Bosch GmbH
Original Assignee
Robert Bosch GmbH
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by Robert Bosch GmbH filed Critical Robert Bosch GmbH
Priority to DE102023202348.2A priority Critical patent/DE102023202348A1/de
Priority to US18/598,291 priority patent/US20240311276A1/en
Priority to CN202410297310.8A priority patent/CN118672894A/zh
Publication of DE102023202348A1 publication Critical patent/DE102023202348A1/de
Pending legal-status Critical Current

Links

Images

Classifications

    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F11/00Error detection; Error correction; Monitoring
    • G06F11/36Preventing errors by testing or debugging software
    • G06F11/3664Environments for testing or debugging software
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F11/00Error detection; Error correction; Monitoring
    • G06F11/36Preventing errors by testing or debugging software
    • G06F11/362Software debugging
    • G06F11/3636Software debugging by tracing the execution of the program

Landscapes

  • Engineering & Computer Science (AREA)
  • Theoretical Computer Science (AREA)
  • Computer Hardware Design (AREA)
  • Quality & Reliability (AREA)
  • Physics & Mathematics (AREA)
  • General Engineering & Computer Science (AREA)
  • General Physics & Mathematics (AREA)
  • Debugging And Monitoring (AREA)

Abstract

Gemäß verschiedenen Ausführungsformen wird ein Verfahren zum Testen eines Computerprogramms (105) beschrieben, aufweisend Ausführen des Computerprogramms (105) bis zum Aufruf eines Speicherallokierungsbefehls zum Allokieren eines Speicherbereichs, Erweitern des Speicherbereichs um eine Schutzzone mit mindestens einer Speicherstelle, Allokieren des erweiterten Speicherbereichs, Setzen eines Watchpoints auf jede von ein oder mehreren Speicherstellen der Schutzzone, Fortsetzen des Ausführung des Computerprogramms (105) und Anzeigen, für jeden gesetzten Watchpoint, dass das Computerprogramm (105) einen Fehler hat, falls der gesetzte Watchpoint ausgelöst wird.

Description

  • Stand der Technik
  • Die vorliegende Offenbarung bezieht sich auf Verfahren zum Testen eines Computerprogramms.
  • Ein wesentlicher Bestandteil der Entwicklung von Softwareanwendungen ist das Testen und, wenn Fehler gefunden werden, eine entsprechende Fehlerbereinigung. Insbesondere sollten Fehler, die zum Versagen einer Anwendung führen, identifiziert und korrigiert werden. Ein wichtiger Aspekt ist dabei das Testen hinsichtlich darauf, dass auf wichtige Speicherbereiche nicht ungewollt (oder durch einen Angreifer) zugegriffen wird, d.h. ein Testen mit Speicherüberwachung, wie sie durch einen sogenannten (Speicher-)Sanitizer erfolgt. Das Kompilieren und Testen von Software auf gängiger Desktop- und Server-Hardware, z. B. x86, mit Hilfe verschiedener Sanitizer ist eine Maßnahme, gegen die Fehler wie beispielsweise der Heartbleed-Bug, der zuvor lange unentdeckt geblieben ist, entdeckt werden können.
  • Besonders für Computerprogramme auf eingebetteten Systemen, wie z.B. Steuereinrichtungen für ein Fahrzeug, die oft sicherheitsrelevant sind, ist ein umfassendes Testen, das auch eine solche Speicherüberwachung mit einbezieht, wichtig. Sanitizer, die für Desktop- und Server-Hardware eingesetzt werden, sind für solche Systeme jedoch nicht oder nur schlecht einsetzbar, weil eingebettete Systeme typischerweise über eingeschränkte Ressourcen verfügen und solche Sanitizer einen erheblichen Ressourcenbedarf haben und somit nicht verwendet werden können oder sogar die Ausführung des Computerprogramms so beeinflussen können, dass überhaupt erst ein Fehler entsteht.
  • Es sind deshalb Verfahren für das Testen von Computerprogrammen, die eine Speicherüberwachung ermöglichen und für eingebettete Systeme geeignet sind, wünschenswert.
  • Offenbarung der Erfindung
  • Gemäß verschiedenen Ausführungsformen wird ein Verfahren zum Testen eines Computerprogramms bereitgestellt, aufweisend Ausführen des Computerprogramms bis zum Aufruf eines Speicherallokierungsbefehls zum Allokieren eines Speicherbereichs, Erweitern des Speicherbereichs um eine Schutzzone mit mindestens einer Speicherstelle, Allokieren des erweiterten Speicherbereichs, Setzen eines Watchpoints auf jede von ein oder mehreren Speicherstellen der Schutzzone, Fortsetzen des Ausführung des Computerprogramms und Anzeigen, für jeden gesetzten Watchpoint, dass das Computerprogramm einen Fehler hat, falls der gesetzte Watchpoint ausgelöst wird.
  • Das oben beschriebene Verfahren ermöglicht ein Testen mit Speicherüberwachung (d.h. mit einem Sanitizer) auf einem eingebetteten System mit Hilfe eines Debuggers. Dies eignet sich besonders beim Testen mit Fuzzing, da auch Fuzzing Debugger-gesteuert implementiert werden kann und auf diese Weise effektiv für eingebettete Systeme verwendet werden kann.
  • Sanitizer können mittels Code-Instrumentierung implementiert werden. Dazu muss aber entweder der Quellcode zur Verfügung stehen, oder es ist eine anweisungssatzspezifische Instrumentierung auf der Grundlage der Binärdatei (binäre Instrumentierung) erforderlich, die sehr anfällig ist. Eine alternative, auf einem Emulator basierende Instrumentierung ist ebenfalls sehr plattformspezifisch, und jede eingebettete Plattform benötigt einen eigenen Emulator. Das oben beschriebene Verfahren ermöglicht das Testen mit einem Debugger-gesteuerten Sanitizer und erfordert keine Instrumentierung oder Emulation und ist daher in vielen Fällen anwendbar.
  • Im Folgenden werden verschiedene Ausführungsbeispiele angegeben.
  • Ausführungsbeispiel 1 ist ein Verfahren zum Steuern eines Roboters, wie oben beschrieben.
  • Ausführungsbeispiel 2 ist ein Verfahren nach Ausführungsbeispiel 1, aufweisend Löschen der Watchpoints in Reaktion auf eine Freigabe des Speicherbereichs (d.h. insbesondere bei einem Freigabefehl für den Speicherbereich in dem Computerprogramm).
  • Damit können die Speicherstellen der Schutzzone neu zugewiesen werden, ohne dass möglicherweise ein Fehler angezeigt wird, obwohl der Speicherbereich schon freigegeben wurde.
  • Ausführungsbeispiel 3 ist ein Verfahren nach Ausführungsbeispiel 1 oder 2, wobei die Schutzzone mindestens eine Speicherstelle vor und mindestens eine Speicherzelle nach dem Speicherbereich enthält und mindestens ein Watchpoint auf eine Speicherstelle der Schutzzone vor dem Speicherbereich und mindestens ein Watchpoint auf eine Speicherstelle der Schutzzone nach dem Speicherbereich gesetzt wird.
  • Damit können Zugriffe, die über den Speicherbereich hinausgehen, detektiert werden, unabhängig von der Richtung, in der sie das tun.
  • Ausführungsbeispiel 4 ist ein Verfahren nach einem der Ausführungsbeispiele 1 bis 3, aufweisend Ausführen des Computerprogramms auf einem eingebetteten System und Setzen des Watchpoints und der Breakpoints durch ein mit dem eingebetteten System verbundenes Testsystem.
  • Gemäß verschiedenen Ausführungsformen wird insbesondere das Testen eines Computerprogramms für ein eingebettetes System auf dem eingebetteten System selbst inklusive einer Speicherüberwachung ermöglicht.
  • Ausführungsbeispiel 5 ist ein Verfahren nach einem der Ausführungsbeispiele 1 bis 4, aufweisend Anpassen einer Information über die Position des Speicherbereichs im Speicher entsprechend einer Verschiebung der Position des Speicherbereichs durch Erweitern des Speicherbereichs durch die Schutzzone.
  • Beispielsweise wird eine Anfangsadresse des Speicherbereichs entsprechend erhöht, wenn ein oder mehrere Speicherstellen der Schutzzone vor dem Speicherbereich eingefügt werden (und zu Beginn des freien Speichers allokiert werden). Damit wird sichergestellt, dass Zugriffe auf den Speicherbereich, die diese Information verwenden, korrekt erfolgen. Das Erweitern um die Schutzzone kann dann für das Computerprogramm transparent bleiben.
  • Ausführungsbeispiel 6 ist ein Verfahren nach einem der Ausführungsbeispiele 1 bis 5, aufweisend Erweitern des Speicherbereichs um die Schutzzone mittels eines Debuggers.
  • Dies ermöglicht eine für das Computerprogramm transparente Erweiterung mit der Schutzzone. Der Debugger (der auch für das Setzen der Breakpoints und Watchpoints verwendet wird) kann auch für die Anpassung der Information über die Position des Speicherbereichs im Speicher verwendet werden.
  • Ausführungsbeispiel 7 ist ein Verfahren nach einem der Ausführungsbeispiele 1 bis 6, aufweisend Testen des Computerprogramms mittels Fuzzing mit mehreren Testfällen, wobei jeder Testfall eine jeweilige Menge von (ein oder mehreren) Speicherallokierungsbefehlen spezifiziert und für jeden Speicherallokierungsbefehl der für den Testfall spezifizierten Menge aufweist: Ausführen des Computerprogramms bis zum Aufruf des Speicherallokierungsbefehls zum Allokieren eines Speicherbereichs, Erweitern des Speicherbereichs um eine Schutzzone mit mindestens einer Speicherstelle, Allokieren des erweiterten Speicherbereichs, Setzen eines Watchpoints auf jede von ein oder mehreren Speicherstellen der Schutzzone, Fortsetzen des Ausführung des Computerprogramms; und Anzeigen, für jeden gesetzten Watchpoint, dass das Computerprogramm einen Fehler hat, falls der gesetzte Watchpoint ausgelöst wird.
  • Die Speicherüberwachung kann also Teil eines Fuzz-Tests sein, wobei der Fuzzer die Speicherallokierungen, die überwacht werden, auswählen kann. Dadurch können Fehler hinsichtlich von Zugriffen, die über einen allokierten Speicherbereich hinausgehen (also z.B. eines Überlaufs) für viele verschiedene Eingaben des Computerprogramms und Teilprogramme des Computerprogramms gefunden werden, auch dann, wenn nur eine bestimmte Anzahl von Breakpoints und Watchpoints auf dem (z.B. eingebetteten) System, auf dem das Computerprogramm ausgeführt wird, zur Verfügung steht.
  • Ausführungsbeispiel 8 ist ein Verfahren nach einem der Ausführungsbeispiele 1 bis 7, wobei das Computerprogramm ein Steuerprogramm für eine Robotervorrichtung ist und die Robotervorrichtung abhängig von einem Ergebnis des Testens des Computerprogramms mit dem Computerprogramm gesteuert wird.
  • In anderen Worten kann ein Verfahren zum Steuern einer Robotervorrichtung bereitgestellt werden, bei dem die Sicherheit gegenüber Überlauf eines Speicherbereichs im Heap-Speicher durch Testen mittels eines Sanitizers gewährleistet wird.
  • Ausführungsbeispiel 9 ist eine Testanordnung, die eingerichtet ist, ein Verfahren nach einem der Ausführungsbeispiele 1 bis 8 durchzuführen.
  • Ausführungsbeispiel 10 ist ein Computerprogramm mit Befehlen, die, wenn sie durch einen Prozessor ausgeführt werden, bewirken, dass der Prozessor ein Verfahren nach einem der Ausführungsbeispiele 1 bis 8 durchführt.
  • Ausführungsbeispiel 11 ist ein computerlesbares Medium, das Befehle speichert, die, wenn sie durch einen Prozessor ausgeführt werden, bewirken, dass der Prozessor ein Verfahren nach einem der Ausführungsbeispiele 1 bis 8 durchführt.
  • In den Zeichnungen beziehen sich ähnliche Bezugszeichen im Allgemeinen auf dieselben Teile in den ganzen verschiedenen Ansichten. Die Zeichnungen sind nicht notwendigerweise maßstäblich, wobei die Betonung stattdessen im Allgemeinen auf die Darstellung der Prinzipien der Erfindung gelegt wird. In der folgenden Beschreibung werden verschiedene Aspekte mit Bezug auf die folgenden Zeichnungen beschrieben.
    • 1 zeigt einen Computer für die Entwicklung und/oder das Testen von Softwareanwendungen.
    • 2 zeigt ein Ablaufdiagramm, das ein Verfahren zum Testen eines Computerprogramms gemäß einer Ausführungsform darstellt.
  • Die folgende ausführliche Beschreibung bezieht sich auf die begleitenden Zeichnungen, die zur Erläuterung spezielle Details und Aspekte dieser Offenbarung zeigen, in denen die Erfindung ausgeführt werden kann. Andere Aspekte können verwendet werden und strukturelle, logische und elektrische Änderungen können durchgeführt werden, ohne vom Schutzbereich der Erfindung abzuweichen. Die verschiedenen Aspekte dieser Offenbarung schließen sich nicht notwendigerweise gegenseitig aus, da einige Aspekte dieser Offenbarung mit einem oder mehreren anderen Aspekten dieser Offenbarung kombiniert werden können, um neue Aspekte zu bilden.
  • Im Folgenden werden verschiedene Beispiele genauer beschrieben.
  • 1 zeigt einen Computer 100 für die Entwicklung und/oder das Testen von Softwareanwendungen.
  • Der Computer 100 weist eine CPU (Central Processing Unit) 101 und einen Arbeitsspeicher (RAM) 102 auf. Der Arbeitsspeicher 102 wird zum Laden von Programmcode verwendet, z.B. von einer Festplatte 103, und die CPU 101 führt den Programmcode aus.
  • Im vorliegenden Beispiel wird davon ausgegangen, dass ein Benutzer beabsichtigt, mit dem Computer 100 eine Softwareanwendung zu entwickeln und/oder zu testen.
  • Dazu führt der Benutzer eine Softwareentwicklungsumgebung 104 auf der CPU 101 aus.
  • Die Softwareentwicklungsumgebung 104 ermöglicht es dem Benutzer, eine Anwendung 105 für verschiedene Geräte 106, also ein Ziel-Hardware, wie eingebettete Systeme zum Steuern von Robotervorrichtungen, inklusive Roboterarme und autonome Fahrzeuge, oder auch für mobile (Kommunikations)Geräte, zu entwickeln und zu testen. Dazu kann die CPU 101 als Teil der Softwareentwicklungsumgebung 104 einen Emulator ausführen, um das Verhalten des jeweiligen Geräts 106 zu simulieren, für das eine Anwendung entwickelt wird oder wurde. Wird sie nur zum Testen einer Software aus anderer Quelle eingesetzt, kann die Softwareentwicklungsumgebung 104 auch als Softwaretestumgebung angesehen werden bzw. ausgestaltet sein.
  • Der Benutzer kann die fertige Anwendung über ein Kommunikationsnetzwerk 107 an entsprechende Geräte 106 verteilen. Statt über ein Kommunikationsnetzwerk 107 kann dies auch auf andere Weise erfolgen, beispielsweise mittels eines USB-Sticks.
  • Bevor dies geschieht, sollte der Benutzer jedoch die Anwendung 105 testen, um zu vermeiden, dass eine nicht ordnungsgemäß funktionierende Anwendung an die Geräte 106 verteilt wird.
  • Ein Testverfahren ist das sogenannte Fuzzing. Fuzzing oder Fuzz-Testing ist ein automatisiertes Software-Testverfahren, bei dem einem zu testenden Computerprogramm ungültige, unerwartete oder zufällige Daten als Eingaben zugeführt werden. Das Programm wird dann auf Ausnahmen wie Abstürze, fehlende fehlgeschlagene integrierte Code-Assertions oder potenzielle Speicherlecks hin überwacht.
  • Typischerweise werden Fuzzer (d.h. Testprogramme, die Fuzzing verwenden) zum Testen von Programmen verwendet, die strukturierte Eingaben verarbeiten. Diese Struktur ist z. B. in einem Dateiformat oder einem Dateiformat oder Protokoll spezifiziert und unterscheidet zwischen gültigen und ungültigen Eingaben. Ein effektiver Fuzzer erzeugt halb-gültige Eingaben die „gültig genug“ sind, um nicht direkt vom Eingabeparser des zu testenden Programms zurückgewiesen zu werden, aber „ungültig genug“ sind, um unerwartete Verhaltensweisen und Grenzfälle aufzudecken, die im zu testenden Programm nicht richtig behandelt werden.
  • Im Folgenden wird im Zusammenhang mit Fuzzing verwendete Terminologie beschrieben:
    • • Fuzzing oder Fuzz-Testing ist der automatisierte Test-Prozess, zufällig generierte Eingaben an ein Zielprogramm (zu testendes Programm) zu senden und seine Reaktion zu beobachten.
    • • Ein Fuzzer oder eine Fuzzing-Engine ist ein Programm, das automatisch Eingaben generiert. Sie ist also nicht mit der zu testenden Software verknüpft, und es wird auch keine Instrumentierung durchgeführt. Es hat jedoch die Fähigkeit, Code zu instrumentieren, Testfälle zu erzeugen und zu testende Programme auszuführen. Bekannte Beispiele sind afl und libfuzzer.
    • • Ein Fuzz-Target ist ein Softwareprogramm oder eine Funktion, die durch Fuzzing getestet werden soll. Ein Hauptmerkmal eines Fuzz-Targets sollte sein, dass es potenziell nicht vertrauenswürdige Eingaben annimmt, die vom Fuzzer während des während des Fuzzing-Prozesses erzeugt wird.
    • • Ein Fuzz-Test ist die kombinierte Version eines Fuzzers und eines Fuzz-Targets. Ein Fuzz-Target kann dann instrumentierter Code sein, bei dem ein Fuzzer mit seinen Eingaben verknüpft ist (d.h. diese liefert). Ein Fuzz-Test ist ausführbar. Ein Fuzzer kann auch mehrere Fuzz-Tests starten, beobachten und stoppen (normalerweise Hunderte oder Tausende pro Sekunde), jeder mit einer etwas anderen Eingabe, die vom Fuzzer erzeugt wird.
    • • Ein Testfall ist eine bestimmte Eingabe und ein bestimmter Testdurchlauf aus einem Fuzz-Test. Normalerweise werden für die Reproduzierbarkeit interessante Läufe (Finden von neuen Codepfaden oder Abstürzen) gespeichert. Auf diese Weise kann ein bestimmter Testfall mit der entsprechenden Eingabe auch auf einem Fuzz-Target ausgeführt werden, das nicht mit einem Fuzzer verbunden ist, z.B. die Release-Version eines Programms.
    • • Abdeckungsgesteuertes Fuzzing (engl. coverage-guided fuzzing) verwendet Code-Abdeckungsinformationen als Feedback während des Fuzzings, um zu erkennen, ob eine Eingabe die Ausführung neuer Code-Pfade oder Blöcke verursacht hat.
    • • Generator-basiertes Fuzzing (engl. generation-based fuzzing) verwendet vorheriges Wissen über das Zielprogramm (Fuzz-Target), um Testeingaben zu erstellen. Ein Beispiel für ein solches Vorwissen ist eine Grammatik, die der Eingabespezifikation des Fuzz-Targets entspricht, d.h. die Eingabe-Grammatik des Fuzz-Targets (d.h. des zu testenden Programms).
    • • Statische Instrumentierung ist das Einfügen von Anweisungen in ein (zu testendes) Programm, um Feedback über die Ausführung zu erhalten. Sie wird meist durch den Compiler realisiert und kann zum Beispiel die erreichten Codeblöcke während der Ausführung angeben.
    • • Dynamische Instrumentierung ist die Steuerung der Ausführung eines (zu testenden) Programms während der Laufzeit, um Feedback aus der Ausführung zu generieren. Sie wird meist durch Betriebssystem-Systemfunktionalitäten oder durch die Verwendung von Emulatoren realisiert.
    • • Ein Debugger ist eine Vorrichtung oder ein Programm, das ein Zielgerät oder Zielprogramm steuern kann und Funktionen bereitstellen kann, z.B. zum Abrufen von Register- oder Speicherwerten und zum Pausieren und Ausführen es Zielprogramms in Einzelschritten.
    • • Ein Breakpoint wird über einen Debugger auf eine Anweisung des Zielprogramms oder Geräts gesetzt, um die Ausführung bei Erreichen zu stoppen und den steuernden Prozess darüber zu informieren.
    • • Ein Daten-Watchpoint wird über einen Debugger auf eine Speicheradresse eines Zielprogramms oder Zielgeräts gesetzt, um die Ausführung anzuhalten, wenn auf die Speicheradresse zugegriffen wird, und den steuernden Prozess darüber zu informieren, indem ein Interrupt ausgelöst wird.
  • Eingebettete Systeme verfügen in der Regel über einen Mikrocontroller, der Eingaben verarbeitet und mit Ausgaben reagiert, um eine bestimmte Aufgabe zu erfüllen. Obwohl Mikrocontroller das gleiche Speichermodell verwenden und mit den gleichen Programmiersprachen programmiert werden wie normale Benutzerprogramme, sind ihre Programme wesentlich schwieriger zu testen. Um das Debugging zu ermöglichen, bieten Mikrocontroller in der Regel die Möglichkeit, das Programm mit Breakpoints (Haltepunkten) zu unterbrechen, die Anweisungen des Programms in Einzelschritten zu durchlaufen und Watchpoints auf Speicheradressen zu setzen. Watchpoints lösen einen Interrupt aus, wenn auf die entsprechenden Speicherbereiche zugegriffen wird. Hardware-Break- und Watchpoints sind typischerweise als physische Register in der Debug-Einheit eines Mikrocontrollers implementiert und ihre Anzahl ist daher begrenzt und hängt vom jeweiligen System ab. Beispielsweise ist die maximale Anzahl für einen typischen Mikrocontroller vier Breakpoints und zwei Daten-Watchpoints. Normalerweise können Watchpoints zwischen Lese- und Schreibzugriffen unterscheiden.
  • Breakpoints und Watchpoints können insbesondere für die Realisierung eines Debugger-gesteuerten Fuzzings verwendet werden, sodass es keine Instrumentierung erfordert.
  • Fuzzing, auch Debugger-gesteuertes Fuzzing, ist sehr effizient beim Auffinden von Fehlern, die ein beobachtbares Verhalten auslösen, wie z.B. einen Absturz oder Neustart. Allerdings können ganze Klassen von Fehlern nicht beobachtet werden, da das Programm bei diesen stillschweigend versagt. Ein Beispiel ist der Heartbleed-Bug. Der Kern des Heartbleed-Bugs lag darin, dass er nur über die Grenze eines Arrays hinaus liest, während eine Schreiboperation einen leicht zu beobachtenden Segmentierungsfehler verursacht hätte.
  • Der Heartbleed-Bug wurde erst mit Hilfe des Address Sanitizer (ASan) gefunden. ASan fügt während der Kompilierung eines Programms zusätzliche Anweisungen, Metadaten und Überprüfungen ein, um Fehler bei der Speicherbeschädigung zu verhindern. Wenn solche Sanitizer-Anweisungen in einem Programm verfügbar sind, können beim Debuggen des Programms mehr Fehler gefunden werden als ohne Sanitizer. Insbesondere automatisierte Tests, wie Fuzzing, glänzen, wenn ein Sanitizer im zu testenden Programm (d.h. im Fuzz-Target) vorgesehen ist, um zusätzliche Fehler aufdecken.
  • Für eingebettete Systeme, wie einer Datenverarbeitungsvorrichtung mit ARM-Architektur, sind solche Sanitizer nicht so einfach verwendbar wie für Standardplattformen, wie x86-Plattformen. Dafür gibt es mehrere Gründe:
    • • Ein eingebettetes System ist zu ressourcenbeschränkt, um einen Sanitizer zu implementieren. Zum Beispiel benötigt Asan den doppelten Speicher, MSan (MemorySanitizer) benötigt das 2,5-fache der Ressourcen, und UBSan (UndefinedBehaviorSanitizer) benötigt sogar das Dreifache des Arbeitsspeichers des Programms.
    • • Sanitizer erhöhen die Größe der kompilierten Binärdatei. In der Automobilindustrie entspricht die Größe solcher Binärdateien in der Regel nahezu dem verfügbaren Flash-Speicher der Zielhardware. Eine zusätzliche Instrumentierung eines Sanitizers würde deshalb nicht in den Flash-Speicher passen.
    • • Aufgrund der zusätzlichen Instrumentierung von Sanitizern und der Sammlung und Verfolgung von Metadaten führt die Verwendung eines Sanitizers zu einer langsameren Laufzeit eines Binärprogramms auf der jeweiligen Hardware. Eingebettete Systeme sind stark abhängig von asynchronen Ereignissen, wie z. B. Interrupts, und daher können Sanitizer zu zeitbasierten Falsch-Positiv-Fehlern führen, d.h. ein Sanitizer kann während der Laufzeit neue Fehler einführen.
    • • Eingebettete Systeme haben in der Regel keine Benutzeroberfläche zur Anzeige von Laufzeitfehlern. Auf x86-Systemen wird beispielsweise ein Segmentierungsfehler an STDERR weitergeleitet, so dass der Benutzer den Absturz sieht. Eingebettete Systeme hingegen versagen stillschweigend, d. h. ohne dass der Benutzer es bemerkt, und starten nach einem solchen Absturz neu.
  • Gemäß verschiedenen Ausführungsformen wird deshalb eine Herangehensweise bereitgestellt, die die Verwendung einer Speicherüberwachung (d.h. einer Sanitizer-Funktionalität) für ein eingebettetes System ermöglicht, insbesondere so, dass die Speicherüberwachung für ein Debugger-gesteuertes Fuzzing verwendet werden kann. Dabei wird die Speicherüberwachung selbst mit Hilfe eines (bzw. des für das Fuzzing verwendeten) Debuggers ermöglicht.
  • Beim Debugger-basierten Fuzzing erfolgen Interaktionen zwischen dem System, das den Test durchführt (und das z.B. dem Computer 100 entspricht) und dem Zielsystem (Zielhardware, z.B. einem eingebetteten System, beispielsweise einem Zielgerät 106) über eine Debug-Verbindung (d.h. Debug-Schnittstelle), die beispielsweise von einer dedizierten Debugger-Hardware-Vorrichtung bereitgestellt wird. Die Test-Eingabedaten werden in Form eines Eingabevektors, z.B. über WiFi oder einen CAN-Bus (je nach Typ des Zielgeräts 106) an das Zielsystem 106 übertragen, d.h. das Kommunikationsnetzwerk 107 ist bei diesem Testen eine solche Debug-Verbindung (beim Verteilen der getesteten Software kann das Kommunikationsnetzwerk dann irgendein anderes Kommunikationsnetzwerk sein). Das System, das den Test durchführt, im Folgenden auch als Testsystem 100 bezeichnet, steuert die Ausführung des Zielprogramms (d.h. des zu testenden Programms) im Zielsystem über die Debug-Verbindung, d.h. startet die Ausführung und nimmt die Ausführung nach einem Interrupt (insbesondere einen Interrupt, der durch einen Daten-Watchpoint ausgelöst wurde) wieder auf.
  • Ein Debugger-gesteuerter Sanitizer benötigt keine Instrumentierung oder Emulation, sondern nur eine Debug-Schnittstelle zum Zielsystem (z.B. einem eingebetteten System, auf dem die Software ausgeführt wird) mit der Möglichkeit, Break- und Watchpoints zu setzen. Diese Art von Debug-Schnittstellen und - Fähigkeiten sind generisch und weithin verfügbar, was zu einer breiten und einfachen Anwendbarkeit der im Folgenden beschriebenen Herangehensweise führt. Außerdem wird der Speicher des Zielsystems nur wenig belastet, z. B. für Metadaten, da die meisten Sanitizer-bezogenen Informationen auf der Host-Seite des Debuggers (d.h. im testenden System 100) gesammelt und gespeichert werden. Die Größe der kompilierten Binärdatei des Zielprogramms wird nicht erhöht, da sie so wie sie für das Zielsystem 106 für den Einsatz vorgesehen ist beim Testen verwendet werden kann.
  • Ein Debugger hält das Zielsystem an, wenn ein Breakpoint erreicht wird. Daher führt die im Folgenden beschriebenen Herangehensweise nur in seltenen Fällen zu zeitbasierten Fehlalarmen. Diese Fehlalarme können auch durch andere Testtechniken ausgeschlossen werden, z. B. durch anschließende Validierung eines gefundenen Fehlers auf dem Zielsystem. Die Verwendung eines Debuggers bietet außerdem einen guten Einblick in die Interna eines Zielsystems.
  • Die im Folgenden beschriebene Herangehensweise dient zur Speicherüberwachung, d.h. der Detektion eines unerwünschten Schreibens oder Lesens von Speicherbereichen durch ein zu testendes Programm. Computerprogramme bestehen aus Anweisungen, die auf den Speicher wirken. Um die unbeabsichtigte gleichzeitige Verwendung von Speicherplätzen zu vermeiden, wird der Speicher üblicherweise in verschiedene Bereiche unterteilt, nämlich Stack, Heap und statischer Speicher.
  • Der Stack (wobei hierin der Aufruf-Stack (d.h. Aufrufstapel, engl. call stack oder procedure stack) gemeint ist) ist ein kontinuierlich wachsender Speicherbereich, der Teilprogrammen Platz für ihre lokalen Variablen bietet. Jede Funktion erhält ihren eigenen Speicherbereich auf dem Stack. Stack-Speicher wird zugewiesen, indem der Stack-Zeiger verringert wird (kontinuierlicher Speicher). Stack-Frames für aufgerufene Funktionen werden durch Verringern des Stack-Basiszeigers und des Stack-Zeigers zugewiesen.
  • Ein Speicherbereich des Heap-Speichers wird in C, z.B., durch den Aufruf der Funktionen malloc, realloc oder calloc mit der erforderlichen Speichergröße zugewiesen und der zugewiesene Speicherbereich wird mit der Funktion free wieder freigegeben und kann in einer nachfolgenden Zuweisungsanforderung wiederverwendet werden. Speicherbereiche des Heap-Speichers werden normalerweise für langlebige Variablen verwendet, die von verschiedenen Funktionen gemeinsam genutzt werden.
  • Für korrekte Programmausführungen ist es wichtig, dass die Grenzen des zugewiesenen Speichers nicht überschritten werden. Die Sicherstellung korrekter Speicherzugriffe in speicherunsicheren Sprachen wie C, C++ liegt in der Verantwortung des Programmierers. Die Vernachlässigung der Grenzen des zugewiesenen Speichers kann zu schwerwiegenden Sicherheitsvorfällen führen, z. B. zur Ausführung von Remote-Code oder zu Datenlecks.
  • Gemäß einem Ausführungsbeispiel werden zur Erkennung von Überläufen (Lesen, Schreiben oder beides) von Speicherbereichen im Heap-Speicher Allokierungen im Heap-Speicher zunächst verfolgt (d.h. detektiert). Bei Allokierung eines Speicherbereichs im Heap wird eine Schutzzone vorgegebener Größe vor und/oder dem hinter dem Speicherbereich definiert. Hierbei können sich „vor“ und „hinter“ z.B. auf ansteigende oder abfallende Adressen beziehen, d.h. eine Speicherstelle ist vor einer anderen, wenn sie eine kleinere Adresse hat, oder umgekehrt. Ein Zugriff (Lesen oder Schreiben oder beides) auf eine Speicherstelle, die zu der Schutzzone gehört, wird als fehlerhaft angesehen. Die Schutzzone kann eine vorgegebene Größe (d.h. eine gegebene Anzahl von Speicherstellen z.B. eine, zwei oder auch mehr Speicherstellen) vor und/oder hinter dem Speicherbereich beinhalten. Eine Speicherstelle speichert ein Wort mit einer Wortlänge abhängig von der jeweiligen Architektur (z.B. 32 Bit) und wird durch eine jeweilige Adresse identifiziert.
  • Beispielsweise führt das Testsystem 100 Folgendes durch:
    1. 1. Setzen von Breakpoints auf Speicherallokierungsbefehle (d.h. allgemein auf einen Speicherallokierungsbefehle) wie beispielsweise malloc, realloc und calloc
    2. 2. Bei einem Aufruf eines der Speicherallokierungsbefehle wird durch den jeweiligen gesetzten Breakpoint ein Interrupt ausgelöst und der Wert des Parameters, der die Größe des Speicherbereichs angibt, der durch den aufgerufene Speicherallokierungsbefehl allokiert werden soll (und in der Aufruf-Instruktion des Speicherallokierungsbefehls angegeben ist), wird um die vorgegebene Größe erhöht. Diese Anpassung kann durch das Testsystem 100 mittels des Debuggers erfolgen. Bei Hinzufügen der Schutzzone (oder eines Teils der Schutzzone) am Ende des zu allokierenden Speicherbereichs werden etwaige Ausrichtungserfordernisse (des Speicherbereichs im Speicher) eingehalten. Beim Hinzufügen der Schutzzone (oder eines Teils der Schutzzone) am Anfang des zu allokierenden Speicherbereichs verschiebt sich die Lage des Speicherbereichs entsprechend. In diesem Fall passt das Testsystem die Adresse, die der Speicherallokierungsbefehl an das Computerprogramm zurückliefert, geeignet an (sodass das Computerprogramm die Information über die korrekte Lage des allokierten Speicherbereichs im Speicher hat).
    3. 3. Das Testsystem 100 setzt Watchpoints auf die Speicherstellen der Schutzzone.
    4. 4. Wenn einer der Schreib-Watchpoint auslöst wird kam es zu einem ungewollten Speicherzugriff. Das Testsystem 100 zeigt in diesem Fall deshalb an, dass ein Fehler aufgetreten ist, was wiederum die Ausführung einer Sicherheitsmaßnahme auslösen kann.
  • Tabelle 1 veranschaulicht eine Schutzzone und das Setzen von Watchpoints auf eine Schutzzone um einen Speicherbereich (in diesem Beispiel für einen Buffer) im Heap-Speicher. Jede Zeile symbolisiert eine Speicherstelle Tabelle 1
    ... <- restlicher Teil des Heap-Speichers
    Schutzzone <- Hierauf wird ein Watchpoint gesetzt
    Bufferende
    ...
    Bufferanfang
    Schutzzone <- Hierauf wird ein Watchpoint gesetzt
    ... <- restlicher Teil des Heap-Speichers
  • Da die Anzahl der Breakpoints und Watchpoints begrenzt sein kann, ist es möglich, dass nicht alle Speicherbereiche auf diese Weise überwacht werden können. Ist dies der Fall, kann das Testsystem die Teilmenge der Speicherbereiche, die überwacht werden sollen, zufällig auswählen oder die Speicherbereiche werden hintereinander in mehreren Durchläufen des Zielprogramms (z.B. Fuzz-Testdurchläufen) überwacht.
  • Wird ein Watchpoint entfernt, z.B. weil er anderswo benötigt wird, kann in der Schutzzone auch ein Muster gespeichert werden, das es ermöglicht, zu überprüfen, ob Teile der Schutzzone überschrieben wurden.
  • Die Watchpoints können Watchpoints sein, die beim Schreiben, beim Lesen oder bei beidem Auslösen.
  • Gemäß verschiedenen Ausführungsformen wird der durch die Schutzzone erweiterte Speicherbereich im freien Bereich des Heap-Speichers, typischerweise anschließend an den allokierten Bereich des Heap-Speichers, allokiert. Auch die Schutzzone belegt also (zuvor freie) Speicherstellen.
  • Zusammengefasst wird gemäß verschiedenen Ausführungsformen ein Verfahren bereitgestellt, wie in 2 dargestellt.
  • 2 zeigt ein Ablaufdiagramm 200, das ein Verfahren zum Testen eines Computerprogramms gemäß einer Ausführungsform darstellt.
  • In 201 wird das (zu testende) Computerprogramm bis zum Aufruf eines Speicherallokierungsbefehls zum Allokieren eines Speicherbereichs (d.h. einen Allokierungsbefehl für dynamischen Speicher, d.h. einen Speicherbereich im Heap-Speicher des ausführenden Systems) ausgeführt.
  • In 202 wird der (zu allokierende) Speicherbereich um eine Schutzzone mit mindestens einer Speicherstelle (d.h. einer Schutzzone, die mindestens eine Speicherstelle aufweist, erweitert). Eine Speicherstelle entspricht hier einer Speicherstelle, die mit einem Watchpoint versehen werden kann (also einer Speicherstelle für ein Datenwort einer vom jeweiligen ausführenden System abhängigen Wortlänge, z.B. 32 Bit).
  • In 203 wird der (so) erweiterte Speicherbereich allokiert (im Speicher des Systems, dass das Computerprogramm ausführt).
  • In 204 wird ein Watchpoints auf jede von ein oder mehreren Speicherstellen der Schutzzone gesetzt.
  • In 205 wird die Ausführung des Computerprogramms fortgesetzt.
  • In 206 wird für jeden gesetzten Watchpoint angezeigt, dass das Computerprogramm einen Fehler hat, falls der gesetzte Watchpoint ausgelöst wird.
  • Das Verfahren von 2 kann durch einen oder mehrere Computer mit einer oder mehreren Datenverarbeitungseinheiten durchgeführt werden. Der Begriff „Datenverarbeitungseinheit“ kann als irgendein Typ von Entität verstanden werden, die die Verarbeitung von Daten oder Signalen ermöglicht. Die Daten oder Signale können beispielsweise gemäß mindestens einer (d.h. einer oder mehr als einer) speziellen Funktion behandelt werden, die durch die Datenverarbeitungseinheit durchgeführt wird. Eine Datenverarbeitungseinheit kann eine analoge Schaltung, eine digitale Schaltung, eine Logikschaltung, einen Mikroprozessor, einen Mikrocontroller, eine Zentraleinheit (CPU), eine Graphikverarbeitungseinheit (GPU), einen Digitalsignalprozessor (DSP), eine integrierte Schaltung einer programmierbaren Gatteranordnung (FPGA) oder irgendeine Kombination davon umfassen oder aus dieser ausgebildet sein. Irgendeine andere Weise zum Implementieren der jeweiligen Funktionen, die hierin genauer beschrieben werden, kann auch als Datenverarbeitungseinheit oder Logikschaltungsanordnung verstanden werden. Es können ein oder mehrere der im Einzelnen hier beschriebenen Verfahrensschritte durch eine Datenverarbeitungseinheit durch eine oder mehrere spezielle Funktionen ausgeführt (z. B. implementiert) werden, die durch die Datenverarbeitungseinheit durchgeführt werden.
  • Die Herangehensweise von 2 dient zum Testen eines Programms, beispielsweise einer Steuersoftware für eine Robotervorrichtung. Der Begriff „Robotervorrichtung“ kann als sich auf irgendein technisches System beziehend verstanden werden, wie z. B. eine computergesteuerte Maschine, ein Fahrzeug, ein Haushaltsgerät, ein Elektrowerkzeug, eine Fertigungsmaschine, einen persönlichen Assistenten oder ein Zugangssteuersystem. Die Steuersoftware kann auch für datenverarbeitende Systeme wie z.B. ein Navigationsgerät verwendet werden.
  • Das Verfahren von 2 wird beispielsweise durch eine Testanordnung (z.B. Computer 100 und Zielgerät 106 von 1) durchgeführt.
  • Obwohl spezielle Ausführungsformen hier dargestellt und beschrieben wurden, wird vom Fachmann auf dem Gebiet erkannt, dass die speziellen Ausführungsformen, die gezeigt und beschrieben sind, gegen eine Vielfalt von alternativen und/oder äquivalenten Implementierungen ausgetauscht werden können, ohne vom Schutzbereich der vorliegenden Erfindung abzuweichen. Diese Anmeldung soll irgendwelche Anpassungen oder Variationen der speziellen Ausführungsformen abdecken, die hier erörtert sind. Daher ist beabsichtigt, dass diese Erfindung nur durch die Ansprüche und die Äquivalente davon begrenzt ist.

Claims (11)

  1. Verfahren zum Testen eines Computerprogramms (105), aufweisend: Ausführen des Computerprogramms (105) bis zum Aufruf eines Speicherallokierungsbefehls zum Allokieren eines Speicherbereichs; Erweitern des Speicherbereichs um eine Schutzzone mit mindestens einer Speicherstelle; Allokieren des erweiterten Speicherbereichs; Setzen eines Watchpoints auf jede von ein oder mehreren Speicherstellen der Schutzzone; Fortsetzen des Ausführung des Computerprogramms (105); und Anzeigen, für jeden gesetzten Watchpoint, dass das Computerprogramm (105) einen Fehler hat, falls der gesetzte Watchpoint ausgelöst wird.
  2. Verfahren nach Anspruch 1, aufweisend Löschen der Watchpoints in Reaktion auf eine Freigabe des Speicherbereichs.
  3. Verfahren nach Anspruch 1 oder 2, wobei die Schutzzone mindestens eine Speicherstelle vor und mindestens eine Speicherzelle nach dem Speicherbereich enthält und mindestens ein Watchpoint auf eine Speicherstelle der Schutzzone vor dem Speicherbereich und mindestens ein Watchpoint auf eine Speicherstelle der Schutzzone nach dem Speicherbereich gesetzt wird.
  4. Verfahren nach einem der Ansprüche 1 bis 3, aufweisend Ausführen des Computerprogramms (105) auf einem eingebetteten System (106) und Setzen des Watchpoints und der Breakpoints durch ein mit dem eingebetteten System (106) verbundenes Testsystem (100).
  5. Verfahren nach einem der Ansprüche 1 bis 4, aufweisend Anpassen einer Information über die Position des Speicherbereichs im Speicher entsprechend einer Verschiebung der Position des Speicherbereichs durch Erweitern des Speicherbereichs durch die Schutzzone.
  6. Verfahren nach einem der Ansprüche 1 bis 5, aufweisend Erweitern des Speicherbereichs um die Schutzzone mittels eines Debuggers.
  7. Verfahren nach einem der Ansprüche 1 bis 6, aufweisend Testen des Computerprogramms (105) mittels Fuzzing mit mehreren Testfällen, wobei jeder Testfall eine jeweilige Menge von Speicherallokierungsbefehlen spezifiziert und für jeden Speicherallokierungsbefehl der für den Testfall spezifizierten Menge aufweist Ausführen des Computerprogramms (105) bis zum Aufruf des Speicherallokierungsbefehls zum Allokieren eines Speicherbereichs, Erweitern des Speicherbereichs um eine Schutzzone mit mindestens einer Speicherstelle, Allokieren des erweiterten Speicherbereichs, Setzen eines Watchpoints auf jede von ein oder mehreren Speicherstellen der Schutzzone, Fortsetzen des Ausführung des Computerprogramms (105); und Anzeigen, für jeden gesetzten Watchpoint, dass das Computerprogramm (105) einen Fehler hat, falls der gesetzte Watchpoint ausgelöst wird.
  8. Verfahren nach einem der Ansprüche 1 bis 7, wobei das Computerprogramm (105) ein Steuerprogramm für eine Robotervorrichtung ist und die Robotervorrichtung abhängig von einem Ergebnis des Testens des Computerprogramms (105) mit dem Computerprogramm (105) gesteuert wird.
  9. Testanordnung, die eingerichtet ist, ein Verfahren nach einem der Ansprüche 1 bis 8 durchzuführen.
  10. Computerprogramm mit Befehlen, die, wenn sie durch einen Prozessor ausgeführt werden, bewirken, dass der Prozessor ein Verfahren nach einem der Ansprüche 1 bis 8 durchführt.
  11. Computerlesbares Medium, das Befehle speichert, die, wenn sie durch einen Prozessor ausgeführt werden, bewirken, dass der Prozessor ein Verfahren nach einem der Ansprüche 1 bis 8 durchführt.
DE102023202348.2A 2023-03-15 2023-03-15 Verfahren zum Testen eines Computerprogramms Pending DE102023202348A1 (de)

Priority Applications (3)

Application Number Priority Date Filing Date Title
DE102023202348.2A DE102023202348A1 (de) 2023-03-15 2023-03-15 Verfahren zum Testen eines Computerprogramms
US18/598,291 US20240311276A1 (en) 2023-03-15 2024-03-07 Method for testing a computer program
CN202410297310.8A CN118672894A (zh) 2023-03-15 2024-03-14 用于测试计算机程序的方法

Applications Claiming Priority (1)

Application Number Priority Date Filing Date Title
DE102023202348.2A DE102023202348A1 (de) 2023-03-15 2023-03-15 Verfahren zum Testen eines Computerprogramms

Publications (1)

Publication Number Publication Date
DE102023202348A1 true DE102023202348A1 (de) 2024-09-19

Family

ID=92543990

Family Applications (1)

Application Number Title Priority Date Filing Date
DE102023202348.2A Pending DE102023202348A1 (de) 2023-03-15 2023-03-15 Verfahren zum Testen eines Computerprogramms

Country Status (3)

Country Link
US (1) US20240311276A1 (de)
CN (1) CN118672894A (de)
DE (1) DE102023202348A1 (de)

Also Published As

Publication number Publication date
US20240311276A1 (en) 2024-09-19
CN118672894A (zh) 2024-09-20

Similar Documents

Publication Publication Date Title
DE69720821T2 (de) Fehlersuchsystem für Programme mit einer graphischen Benutzerschnittstelle
DE69903629T2 (de) Prüfung der funktionsfähigkeit eines gerätetreibers
DE69510572T2 (de) Verfahren und Vorrichtung zur Run-Time-Fehlerprüfung unter Verwendung dynamischer Programmmodifikation
DE69919404T2 (de) On-line fehlerbeseitigungs- und ablaufverfolgungssytem und verfahren
DE69811474T2 (de) Rechnerarchitektur zur aufschiebung von exceptions statischer spekulativer befehle
EP1720100B1 (de) Verfahren und Vorrichtung zur Emulation einer programmierbaren Einheit
DE102008012337A1 (de) Programmcode-Trace-Signatur
CH654943A5 (de) Pruefeinrichtung fuer mikroprogramme.
DE102007006190A1 (de) Techniken zur Verwendung von Speicher-Attributen
EP1019819B1 (de) Programmgesteuerte einheit und verfahren zum debuggen derselben
DE102013021679A1 (de) Rettung von Ereignisnachverfolgungsinformationen bei Stromausfall-Unterbrechungsszenarien
DE69815006T2 (de) Datenverarbeitungseinheit mit Fehlerbeseitungsmöglichkeiten
DE102015210651B4 (de) Schaltung und Verfahren zum Testen einer Fehlerkorrektur-Fähigkeit
EP2962205B1 (de) Mehrkern-prozessorsystem mit fehleranalysefunktion
DE202016008043U1 (de) Vorrichtung zum Erzeugen, Erfassen, Speichern und Laden von Debugging-Informationen für gescheiterte Test-Skripts
EP0500973A1 (de) Initialisierungsroutine im EEPROM
DE69128908T2 (de) Verfahren zum Durchführen von erlässlichen Befehlen in einem Rechner
DE102023201815A1 (de) Verfahren zum Testen eines Computerprogramms
DE102009050161A1 (de) Verfahren und Vorrichtung zum Testen eines Systems mit zumindest einer Mehrzahl von parallel ausführbaren Softwareeinheiten
DE102023202348A1 (de) Verfahren zum Testen eines Computerprogramms
DE102009009172B4 (de) Abbildung von Adressen eines Programmcodes und von Adressen von Daten in einem Speicher
DE102014210192A1 (de) Die Erfindung betrifft ein Verfahren zur Überprüfung von Invarianten in parallelen Programmen
DE102019128156A1 (de) Verfahren zur Überprüfung eines FPGA-Programms
DE102007015507A1 (de) Prozessor mit einem ersten und einem zweiten Betriebsmodus und Verfahren zu seinem Betrieb
DE102022202338A1 (de) Verfahren zum Testen eines Computerprogramms