Wie STACKLEAK die Sicherheit des Linux-Kernels verbessert

STACKLEAK ist eine Linux-Kernel-Sicherheitsfunktion, die ursprünglich von den Entwicklern von Grsecurity / PaX entwickelt wurde. Ich beschloss, STACKLEAK auf den offiziellen Vanille-Kernel (Linux-Kernel-Mainline) zu bringen. In diesem Artikel werden die interne Struktur, die Eigenschaften dieser Sicherheitsfunktion und ihr sehr langer, schwieriger Pfad in der Hauptzeile erläutert.





STACKLEAK schützt vor mehreren Klassen von Schwachstellen im Linux-Kernel, nämlich:

  • reduziert die für den Angreifer nützlichen Informationen, die vom Nuklearstapel in den Benutzerraum gelangen können;
  • blockiert einige Angriffe auf nicht initialisierte Variablen im Kernel-Stack;
  • Bietet dynamische Tools zur Erkennung von Stapelüberläufen.

Diese Sicherheitsfunktion passt perfekt zum Konzept des Kernel Self Protection Project (KSPP): Sicherheit ist mehr als nur das Beheben von Fehlern. Absolut alle Fehler im Code können nicht behoben werden, und daher sollte der Linux-Kernel in Fehlersituationen sicher funktionieren, auch wenn versucht wird, Schwachstellen auszunutzen. Weitere Details zu KSPP finden Sie im Projekt-Wiki .

STACKLEAK ist im grsecurity / PaX-Patch als PAX_MEMORY_STACKLEAK vorhanden. Der grsecurity / PaX-Patch wird jedoch seit April 2017 nicht mehr frei verbreitet. Daher wäre das Erscheinen von STACKLEAK im Vanillekern für Linux-Benutzer mit erhöhten Anforderungen an die Informationssicherheit von Nutzen.

Arbeitsauftrag:

  • Wählen Sie STACKLEAK aus dem grsecurity / PaX-Patch.
  • studiere den Code sorgfältig und bilde einen Patch,
  • an LKML senden, Feedback erhalten, verbessern, erneut wiederholen, bevor es in die Hauptleitung aufgenommen wird.

Zum Zeitpunkt des Schreibens (25. September 2018) wurde Version 15 einer Reihe von Patches gesendet. Es enthält ein architektonisch unabhängiges Teil und Code für x86_64 und x86_32. Die von Laura Abbott von Red Hat entwickelte STACKLEAK-Unterstützung für arm64 hat es bereits geschafft, in den Vanillekern 4.19 zu gelangen.

STACKLEAK: Sicherheitsmerkmale


Restinformationen im Kernel-Stack löschen


Diese Maßnahme reduziert die nützlichen Informationen, die einige Lecks vom Kernstapel zum Benutzerraum erzeugen können.

Ein Beispiel für einen Informationsverlust aus dem Kernel-Stack ist in Abbildung 1 dargestellt.



Schema 1.

Lecks dieses Typs werden jedoch unbrauchbar, wenn am Ende eines Systemaufrufs der verwendete Teil des Kernelstapels mit einem festen Wert gefüllt wird (Abbildung 2).



Schema 2.

Infolgedessen blockiert STACKLEAK einige Angriffe auf nicht initialisierte Variablen im Kernel-Stack. Beispiele für solche Sicherheitsanfälligkeiten: CVE-2017-17712, CVE-2010-2963. Eine Beschreibung der Ausnutzungsmethode für die Sicherheitsanfälligkeit CVE-2010-2963 finden Sie in einem Artikel von Kees Cook.

Die Essenz des Angriffs auf eine nicht initialisierte Variable im Kernel-Stack ist in Abbildung 3 dargestellt.



Schema 3.

STACKLEAK blockiert Angriffe dieses Typs, da der Wert, der den Kernstapel am Ende eines Systemaufrufs auffüllt, auf einen nicht verwendeten Bereich im virtuellen Adressraum hinweist (Abbildung 4).



Schema 4.

Eine wichtige Einschränkung besteht darin, dass STACKLEAK nicht vor ähnlichen Angriffen schützt, die in einem einzelnen Systemaufruf ausgeführt werden.

In-Kernel-Core-Stack-Überlauferkennung


Im Vanilla-Kernel (Linux-Kernel-Hauptzeile) ist STACKLEAK nur in Verbindung mit CONFIG_THREAD_INFO_IN_TASK und CONFIG_VMAP_STACK gegen einen Überlauf der Kernel-Stapeltiefe wirksam. Beide Maßnahmen werden von Andy Lutomirski umgesetzt.

Die einfachste Version zum Ausnutzen dieser Art von Sicherheitsanfälligkeit ist in Abbildung 5 dargestellt.



Schema 5.

Das Überschreiben bestimmter Felder in der Struktur thread_info am unteren Rand des Kernstapels kann die Berechtigungen des Prozesses erhöhen. Wenn jedoch die Option CONFIG_THREAD_INFO_IN_TASK aktiviert ist, wird diese Struktur aus dem Nuklearstapel entfernt, wodurch die beschriebene Methode zum Ausnutzen der Sicherheitsanfälligkeit entfällt.

Eine fortgeschrittenere Version dieses Angriffs besteht darin, Daten in einem benachbarten Speicherbereich zu überschreiben, indem die Stapelgrenze überschritten wird. Mehr zu diesem Ansatz:


Diese Art von Angriff ist in Abbildung 6 dargestellt.



Schema 6.

Der Schutz ist in diesem Fall CONFIG_VMAP_STACK. Wenn diese Option aktiviert ist, wird eine spezielle Speicherseite (Schutzseite) neben dem Kernstapel platziert, auf die der Zugriff zu einer Ausnahme führt (Abbildung 7).



Schema 7.

Schließlich ist ein Angriff wie Stack Clash die interessanteste Option, um den Stapel in der Tiefe zu überfluten. Die Idee wurde bereits 2005 von Gael Delalleau vorgebracht .

Im Jahr 2017 haben Forscher der Firma Qualys darüber nachgedacht und diese Technik Stack Clash genannt. Tatsache ist, dass es eine Möglichkeit gibt, über die Schutzseite zu springen und Daten aus einem benachbarten Speicherbereich zu überschreiben (Abbildung 8). Dies erfolgt über ein Array mit variabler Länge (VLA), dessen Größe vom Angreifer gesteuert wird.



Schema 8.

Weitere Informationen zu STACKLEAK und Stack Clash finden Sie im grsecurity-Blog .

Wie schützt STACKLEAK vor Stack Clash im Nuklearstack? Vor jedem Aufruf von alloca () wird eine Überprüfung des Stapelüberlaufs in der Tiefe durchgeführt. Hier ist der entsprechende Code aus Version 14 der Patch-Serie:

void __used stackleak_check_alloca(unsigned long size) { unsigned long sp = (unsigned long)&sp; struct stack_info stack_info = {0}; unsigned long visit_mask = 0; unsigned long stack_left; BUG_ON(get_stack_info(&sp, current, &stack_info, &visit_mask)); stack_left = sp - (unsigned long)stack_info.begin; if (size >= stack_left) { /* * Kernel stack depth overflow is detected, let's report that. * If CONFIG_VMAP_STACK is enabled, we can safely use BUG(). * If CONFIG_VMAP_STACK is disabled, BUG() handling can corrupt * the neighbour memory. CONFIG_SCHED_STACK_END_CHECK calls * panic() in a similar situation, so let's do the same if that * option is on. Otherwise just use BUG() and hope for the best. */ #if !defined(CONFIG_VMAP_STACK) && defined(CONFIG_SCHED_STACK_END_CHECK) panic("alloca() over the kernel stack boundary\n"); #else BUG(); #endif } } 

Diese Funktionalität wurde jedoch von Version 15 ausgeschlossen. Dies war hauptsächlich auf das umstrittene Verbot von Linus Torvalds zurückzuführen, BUG_ON () in Linux-Kernel-Sicherheitspatches zu verwenden.

Darüber hinaus führte die 9. Version der Patch-Serie zu einer Diskussion, weshalb beschlossen wurde, alle variablen Arrays aus dem Mainline-Kernel zu entfernen. Ungefähr 15 Entwickler waren an dieser Arbeit beteiligt und sie wird bald abgeschlossen sein.

Auswirkungen auf die STACKLEAK-Leistung


Ich gebe die Ergebnisse von Leistungstests auf x86_64. Ausstattung: Intel Core i7-4770, 16 GB RAM.

Test Nr. 1, attraktiv: Aufbau eines Linux-Kernels auf einem einzelnen Prozessorkern

  # time make   4.18: real 12m14.124s user 11m17.565s sys 1m6.943s   4.18+stackleak: real 12m20.335s (+0.85%) user 11m23.283s sys 1m8.221s 

Test Nr. 2, unattraktiv:

  # hackbench -s 4096 -l 2000 -g 15 -f 25 -P    4.18: 9.08     4.18+stackleak: 9.47  (+4.3%) 

Daher hängt die Auswirkung von STACKLEAK auf die Systemleistung von der Art der Last ab. Insbesondere eine große Anzahl von kurzen Systemaufrufen erhöht den Overhead. T.O. Die STACKLEAK-Leistung muss vor der Produktion für die geplante Ladung bewertet werden.

Internes Gerät STACKLEAK


STACKLEAK besteht aus:

  • Der Code, der den Kernel-Stack am Ende des Systemaufrufs löscht (ursprünglich in Assembler geschrieben),
  • GCC-Plugin zur instrumentellen Kompilierung von Kernel-Code.

Das Löschen des Kernel-Stacks erfolgt in der Funktion stackleak_erase (). Diese Funktion wird erfüllt, bevor nach einem Systemaufruf zum Benutzerbereich zurückgekehrt wird. Das STACKLEAK_POISON (-0xBEEF) wird in den verwendeten Teil des Thread-Stacks geschrieben. Die niedrigste_Stack-Variable, die in stackleak_track_stack () ständig aktualisiert wird, zeigt auf den Bereinigungsstartpunkt.

Die Stufen von stackleak_erase () spiegeln sich in den Schemata 9 und 10 wider.



Schema 9.



Schema 10.

T.O. stackleak_erase () löscht nur den verwendeten Teil des Kernstapels. Deshalb ist STACKLEAK so schnell. Wenn Sie am Ende jedes Systemaufrufs alle 16 kB des Kernel-Stacks auf x86_64 löschen, zeigt Hackbench einen Leistungsabfall von 40%.

Die Instrumentierung des Kernel-Codes in der Kompilierungsphase erfolgt im STACKLEAK GCC-Plugin.

GCC-Plugins sind projektspezifische herunterladbare Module für den GCC-Compiler. Sie registrieren neue Pässe beim GCC Pass Manager und stellen Rückrufe für diese Pässe bereit.

Für den vollständigen Betrieb von STACKLEAK werden Aufrufe von stackleak_track_stack () mit einem großen Stapelrahmen (Stapelrahmen) in den Funktionscode eingefügt. Außerdem wird vor jeder alloca () ein Aufruf des bereits erwähnten stackleak_check_alloca () eingefügt, und danach wird ein Aufruf von stackleak_track_stack () eingefügt.

Wie bereits erwähnt, wurde in Version 15 der Patch-Serie das Einfügen von Aufrufen von stackleak_check_alloca () aus dem GCC-Plugin ausgeschlossen.

Pfad in der Linux-Kernel-Hauptzeile


Der STACKLEAK-Pfad in der Hauptlinie ist sehr lang und schwierig (Abbildung 11).



Schema 11. Fortschritte bei der Implementierung von STACKLEAK in der Linux-Kernel-Hauptlinie.

Im April 2017 haben die Entwickler von grsecurity ihre Patches für die Community geschlossen und damit begonnen, sie nur auf kommerzieller Basis zu vertreiben. Im Mai 2017 habe ich beschlossen, STACKLEAK in den Vanillekern einzuführen. So begann eine Reise länger als ein Jahr. Die Firma Positive Technologies, in der ich arbeite, gibt mir die Möglichkeit, mich für einen Teil meiner Arbeitszeit mit dieser Aufgabe zu befassen. Aber im Grunde verbringe ich "Freizeit" damit.

Seit letztem Mai wurde meine Patch-Serie mehrfach überprüft, hat wesentliche Änderungen erfahren und wurde zweimal von Linus Torvalds kritisiert. Ich wollte das Ganze oft verlassen. Aber zu einem bestimmten Zeitpunkt gab es einen festen Wunsch, das Ende zu erreichen. Zum Zeitpunkt des Schreibens (25. September 2018) befindet sich die 15. Version der Patch-Serie im Linux-Next-Zweig, erfüllt alle angegebenen Anforderungen von Linus und ist bereit für das Zusammenführungsfenster des 4.20 / 5.0-Kernels.

Vor einem Monat hielt ich auf dem Linux Security Summit einen Vortrag über diese Arbeit. Ich biete Links zu Folien und Videos :


Fazit


STACKLEAK ist eine sehr nützliche Sicherheitsfunktion für den Linux-Kernel, die die Ausnutzung mehrerer Arten von Sicherheitslücken gleichzeitig blockiert. Darüber hinaus konnte der ursprüngliche Autor von PaX Team es schnell und schön in der Technik machen. Daher wäre das Erscheinen von STACKLEAK im Vanillekern für Linux-Benutzer mit erhöhten Anforderungen an die Informationssicherheit von Nutzen. Darüber hinaus lenkt die Arbeit in dieser Richtung die Aufmerksamkeit der Linux-Entwicklergemeinde auf Kernel-Selbstverteidigungstools.

PS


STACKLEAK wurde schließlich vom Linux 4.20-Kernel übernommen:
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2d6bb6adb714b133db92ccd4bfc9c20f75f71f3f

Die unterstützten Architekturen sind x86_64, x86_32 und arm64.

Darüber hinaus wurden die Arbeiten zum Entfernen von Arrays variabler Länge aus dem Linux-Kernel-Code abgeschlossen. Die Gcc-Compiler-Warnung "-Wvla" ist in der Kernel-Version 4.20 enthalten: lkml.org/lkml/2018/10/28/189

Source: https://habr.com/ru/post/de424633/


All Articles