Was ist Stack-Smashing? Kann es behoben werden?

0
214
Shutterstock/Gabor Tinz

Jede Minute Produktionsausfall kostet ein Unternehmen im Allgemeinen Geld. Wenn in Ihrer Anwendung ein schwerwiegendes Problem auftritt, das zu einem Stack-Smashing führt, haben Sie eine Chance. Erfahren Sie vorab, was Stack-Smashing ist und was man dagegen tun kann!

Was ist Stack-Smashing?

< p>Als Qualitätssicherungsingenieur wird man früher oder später auf den Begriff Stack-Smashing stoßen. Als Entwickler wird man diesen Begriff wahrscheinlich noch früher entdecken, insbesondere wenn man einen Fehler in den Code eingebaut hat, der einen zertrümmerten Stack verursacht. Es ist relativ einfach (wie in ‘etwas einfach’) für einen Entwickler, einen Fehler zu machen, der zu Stack-Smashing führt. Wenn Sie als Benutzer mehr über das Zertrümmern von Stapeln erfahren, ist der Schaden wahrscheinlich bereits angerichtet.

Stack-Smashing kann unfreiwillig passieren – zum Beispiel, wenn der Entwickler einen Fehler einführte, der zu einem Stapelzertrümmern führte – oder böswillig – ein Angreifer, der irgendwie versucht, den Stack eines Programms zu überlaufen oder zu beschädigen.

Stack-Smashing ist ein etwas locker definierter Begriff, der auf verschiedene Probleme hinweisen und aus einer Vielzahl von Quellen stammen kann. Die beiden bekanntesten Probleme, die zu einem Stack-Smashing führen können, sind: 1) zu viele Daten in einen bestimmten Teil des Stapels zu schreiben/überzuordnen, wodurch ein anderer Teil des Stapels überschrieben wird, und 2) wenn eine externe Quelle (bösartig oder nicht) den Stapel eines anderen Programms überschrieben hat, obwohl dies ist viel seltener.

Was ist also ein Stapel? Auch das ist ein locker definierter Begriff. Im Allgemeinen bezieht sich ein Stapel auf einen Programmverarbeitungsstapel, einen Stapel von Funktionen, wie er in einem bestimmten Softwareprogramm/Code definiert ist.

Werbung

Stellen Sie sich zunächst einen Stapel von Badezimmerfliesen vor, die gestapelt sind, bereit zu von einem Fliesenleger verwendet werden. Dies ist eine recht gute Darstellung eines Computerstapels mit einigen Modifikationen. Wenn jede Kachel ein wenig von der vorherigen abgesetzt wäre, wäre es ein besseres Bild, und wir werden bald sehen, warum.

Shutterstock/Piotr Debowski

Stellen Sie sich vor, dass jede gestapelte Kachel eine Funktion im Computerprogramm ist. Die grundlegendste Funktion befindet sich ganz unten und könnte beispielsweise die main()-Funktion in einem C- oder C++-Programm sein. C und C++ sind zwei Programmiersprachen, die den Stack ausgiebig nutzen.

Jede dieser Funktionen im C/C++-Programm hat einen Namen und wahrscheinlich einen Satz eingehender und ausgehender Variablen. Stellen Sie sich vereinfacht vor, wenn eine dieser Variablen eine Länge von 10 Zeichen hat und eine andere Funktion versehentlich 100 Zeichen in diese Variable geschrieben hat. Dies kann den gesamten Stapel beschädigen.

Stellen Sie sich in Bezug auf das Kachelbeispiel oben vor, dass jemand mit einem Hammer auf die erste Kachel ein wenig zu hart schlägt und dadurch alle anderen Kacheln zertrümmert. Äh voila; Stapel zerschlagen 😉

Die Analogie funktioniert, denn genau wie alle Kacheln in unserem fiktiven Erinnerungsbild jetzt kaputt sind, führt ein zertrümmerter Stapel zu ‘gebrochenen Funktionen’, wenn Sie so wollen. Jeder Kachelversatz ist eine tiefer verschachtelte Funktion – mehr zu defekten Funktionen im nächsten Abschnitt.

Debugging von Smashed Stack(s)

Wobei technisch ein Verweis auf ‘defekte Funktionen’möglicherweise nicht vollständig korrekt, dh es gibt wahrscheinlich nur eine defekte Funktion und möglicherweise sogar keine defekte Funktion, wenn ein externer Angriff oder ein fehlerhaftes Programm vorliegt, ist dies eine gute Möglichkeit, an einen zertrümmerten Stack zu denken.

Werbung

Plötzlich können Variablen- und Funktionsnamen verstümmelt werden und ein Backtrace (der Funktionsfluss, den der Computer verwendet hat, um zu einer bestimmten Funktion zu gelangen, die abgestürzt ist und (in unserem Beispiel) den Stack zerstört hat) macht keinen Sinn mehr.

Im Allgemeinen hat ein Backtrace einen klaren Fluss der aufgerufenen Funktionen. Während ein abstürzendes Programm nicht sofort als ‘gesund’ in Bezug auf Backtracing/Debugging ist dies ein ‘gesundes’ Backtrace sieht so aus:

Wenn ein Stack jedoch beschädigt ist , wird das Debuggen viel schwieriger. Der Stack könnte so aussehen:

Dies ist ein Beispiel für ein Stack-Smashing-Problem, das 2008 in MySQL, dem Datenbankserver (siehe den Anhang zu MySQL-Bug 37815 im log.txt-Anhang für die vollständige Ausgabe), aufgetreten ist und den Datenbankserver-Daemon (mysqld) beendet hat.

< p>Während die Bibliothek libc.so.6 des Betriebssystems in diesem Fall das Stack-Smashing ziemlich gut gehandhabt zu haben scheint (unter Verwendung einiger Fortify-Funktionalität in der __fortify_fail-Funktion), existierte das Problem irgendwo im Code und hat inzwischen behoben.

Beachten Sie auch, dass wir in diesem Fall keine aufgelösten Funktionsnamen sehen, sondern nur den binären Namen (interessanterweise scheint das Problem im Client (mysql) aufgetreten zu sein, was dazu führt, dass der Server (mysqld) beendet wird), was mysql ist. zusammen mit einer Speicheradresse der Funktion: mysql[0x8051565], mysql[0x80525c7] und mysql(main+0x4f8)[0x8053198].

Werbung

Normalerweise, wenn wir Debug-Symbole verwenden (siehe unten für einen Artikel über GDB, der im Detail erklärt, was Debug-Symbole sind), würden wir Funktionsnamen mit Variablen sehen, und selbst mit einigen Stufen der binären Optimierung/Verkleinerung würden wir es zumindest tun Funktionsnamen sehen, genau wie im ersten ‘healthy’ Backtrace oben.

Bei einem zertrümmerten Stack ist die Ausgabe der Funktionsnamen, Variablennamen oder Werte jedoch nie garantiert und oft kompletter Quatsch 🙂 Wir sehen vielleicht sogar unterschiedliche Funktionsnamen oder a komplett verstümmelter Stack (ein weiterer Jargon, der oft von IT-Leuten verwendet wird) verschiedener Funktionsnamen, die nicht viel Sinn machen (und wahrscheinlich fiktiv/unwahr sind, da der Stack irgendwie überschrieben wurde).

Dies macht es sowohl für den Testingenieur (der viele verschiedene Ergebnisse für einen einzelnen Fehler haben kann, was die Handhabung bekannter Fehlerfiltermechanismen erschwert) als auch für den Entwickler (der wahrscheinlich eine schrittweise Verfolgung oder ein Reverse-Execution-Debugger wie RR, um den vorliegenden Fehler zu entdecken).

Was tun bei Stack-Smashing?

Wenn Sie auf Stack-Smashing stoßen, möchten Sie zunächst das Problem und die Umgebung ein wenig besser verstehen, um die Quelle zu kennen. Wenn Sie einen beliebten Webserver im Internet mit vielen Gaming-Benutzern haben, die versuchen, ein Turnier zu gewinnen, während der Server auch Bitcoin abbaut, sollten Sie die Möglichkeit eines Foulspiels annehmen und herausfinden, ob sich jemand mit der server.

In den meisten Fällen handelt es sich jedoch nur um einen Anwendungsfehler. Während ich sage ‘nur’, kann das Problem sehr schwerwiegend sein, zu Ausfallzeiten von Diensten führen, viel Geld kosten und schließlich nicht behoben werden können. Zum Beispiel kann ein Datenbankserver beim Start dauerhaft abstürzen, weil sich die Daten in einem bestimmten Zustand in Kombination mit einem Mangel oder einer Einschränkung im Code befinden.

Wenn eine solche Situation dadurch verschlimmert wird, dass kein Stack-Smashing vorliegt, oder anders ausgedrückt, keine saubere Rückverfolgung des Problems erstellt werden kann, wird das Debuggen komplizierter und manchmal fast unmöglich. Fürchte dich jedoch nicht, dass das gleiche grundlegende Debugging wie bei jedem Fehler oder Anwendungsfehler/Absturz/Problem gleich bleibt.

Werbung

Lesen Sie jedes Bit der Protokolldateien sorgfältig vor, während und nach dem Problem aufgetreten. Erstellen Sie einige Backups und wiederholen Sie den Vorgang. Scheitert es wieder oder nicht? Untersuchen Sie die Fehler, Teile des Stapels und sogar die Frames (dh einzelne angezeigte Stapelfunktionen, wie die do_the_maths-Funktion in unserem ursprünglichen ‘gesunden’-Stack-Trace) können in Ihre bevorzugten Suchmaschinen eingegeben werden.

Wenn Sie (mit einem Leerzeichen) die selektivsten (obersten) abstürzenden Frames verketten und online nach denselben suchen, finden Sie häufig einen vorhandenen Fehlerbericht für das Problem, mit dem Sie konfrontiert sind. Beim Stack-Smashing werden diese Frames (Funktionsnamen) jedoch wahrscheinlich verstümmelt und sind daher nicht mehr in der gleichen Weise verwendbar. Wenn Sie eine Assertion-Nachricht sehen (eine vom Entwickler im Code eingeführte Assertion), suchen Sie auch danach.

Loggen Sie immer einen neuen Fehlerbericht ein, wenn das Problem noch nicht online protokolliert zu sein scheint (Sie helfen möglicherweise anderen, die das Gleiche sehen!) und geben Sie so viele Informationen zu dem Problem an, wie Sie finden können. Tausende von Fehlerberichten für ebenso viele Anwendungen werden täglich online protokolliert. Hoffentlich ist das Support-Team für Ihre Stack-Smashing-Anwendung zur Stelle, um schnell zu helfen.

Sie können auch unseren nächsten Artikel Debugging mit GDB: Erste Schritte lesen, da er weiter auf C- und C++-Programmen aufbaut (und andere) können mit dem GDB-Debugger debuggt werden. Außerdem werden die Konzepte eines Stapels im Detail erläutert.