PaX

Sicherheitspatch für den Linux-Kernel

PaX ist ein Sicherheitspatch für den Linux-Kernel, der einen „Geringste-Rechte“-Schutz (englisch least privilege) für Speicherseiten implementiert. Der Ansatz der geringsten Rechte erlaubt Computerprogrammen nur diejenigen Aktionen durchzuführen, die sie für einen ordentlichen, regulären Ablauf benötigen, und verbietet alle darüber hinausgehenden. PaX wurde 2000 erstmals veröffentlicht.

PaX markiert Datenbereiche des Speichers als nicht-ausführbar, Programmbereiche als nichtbeschreibbar und ordnet den Programmspeicher zufällig an. Das erste verhindert direkte Code-Ausführung, während das letztere sogenannte return-to-libc-Angriffe (ret2libc) stark erschwert, ein Erfolg eines solchen Angriffes hängt dann vor allem vom Zufall ab; es verhindert aber nicht das Überschreiben von Variablen und Pointern.

PaX wurde durch das PaX Team geschrieben. Der Hauptautor von PaX möchte anonym bleiben.

PaX hat eine eigene Version des Linux-Maskottchens, Tux.

Bedeutung Bearbeiten

Viele, wenn nicht fast alle, Sicherheitslücken bei Computern sind auf Fehler in Programmen zurückzuführen, die es ermöglichen, die Funktion eines Programms zu verändern, effektiv also ein „Umschreiben“ des Programms während dessen Ausführung erlauben. So zeigen die ersten 44 Ubuntu Security Notices, dass 41 % der Angriffsmöglichkeiten aus buffer overflows resultieren, 11 % aus integer overflows und 16 % von anderer, falscher Behandlung von nicht erwartungsgemäßen Daten. Diese Typen von Programmfehlern ermöglichen es oft, Schadcode einzuschleusen und auszuführen; im Beispiel machen sie 61 % aus, ohne Berücksichtigung von Überschneidungen. Die oben durchgeführte Analyse ist sehr ungenau, eine umfangreichere Untersuchung würde sicherlich andere Zahlen ergeben (sowohl höher als auch tiefer), zeigt aber grundsätzlich die Problematik.

Viele Würmer, Viren und Übernahmeversuche beruhen auf der Veränderung von Speicherinhalten, so dass Schadcode ausgeführt wird, oder auf der Ausführung von Speicherinhalten (durch Falschadressierung), die eigentlich Daten darstellen sollen. Wenn die Ausführung solcher Anweisungen verhindert werden könnte, würde solche Schadsoftware nur noch wenig bis gar keinen Schaden anrichten können, sogar nach Installation auf dem Computer; viele könnten überhaupt nicht mehr installiert werden (z. B. der Sasser-Wurm).

PaX wurde entworfen, um genau dies für eine große Anzahl möglicher Angriffe zu tun, und zwar auf einem sehr allgemeinen, breit anwendbarem Weg. Er verhindert die Ausführung von missbräuchlichem Code durch Kontrolle des Zugriffes auf den Speicher (lesen, schreiben, Zugriff auf Programmcode sowie Kombinationen davon) und dies, ohne die Ausführung von normalem Code zu verhindern. Mit einem kleinen Overhead reduziert PaX dadurch viele Exploits auf Denial of Service-Angriffe: Exploits, die dem Angreifer normalerweise root-Zugriff, Zugriff auf wichtige Daten oder anderen Schaden anzurichten erlauben würden, würden das betroffene Programm nunmehr abstürzen und das restliche System unbehelligt lassen.

Ein DoS-Angriff ist zwar unangenehm und resultiert oft in Verlust von Zeit oder anderen Ressourcen; jedoch werden meistens keine Daten kompromittiert, wenn PaX eingreift. Trotzdem kann ein DoS-Angriff in gewissen Umgebungen nicht akzeptabel sein; es gibt level-of-service-Verträge oder andere Bedingungen, die einen erfolgreichen Einbruch in ein System weniger kostenintensiv machen als die Reduktion oder Verlust der Verfügbarkeit eines Dienstes. In diesem Licht betrachtet ist der Ansatz von PaX nicht überall angemessen. In vielen Fällen jedoch ist es eine brauchbare Methode, um vertrauliche Daten vor Sicherheitsbrüchen zu schützen.

Viele Programmierfehler verursachen eine Verfälschung des Speicherinhaltes. Von den Fehlern, die dies ermöglichen und absichtlich herbeigeführt werden können, ermöglichen einige, das Programm verschiedene Dinge durchführen zu lassen, für die es nicht vorgesehen wurde, wie z. B. eine privilegierte Shell zu erhalten. Der Fokus von PaX ist nicht das Finden und Korrigieren solcher Fehler, sondern das Verhindern und Isolieren der Exploits dieser Fehler. Wie im oberen Absatz erwähnt, wird eine Untermenge dieser Fehler in ihrer Schwere heruntergestuft; Programme werden beendet, statt ihre Dienste fehlerbehaftet weiterhin anzubieten.

PaX verhindert Pufferüberläufe nicht direkt. Stattdessen verhindert es, dass viele dieser und ähnlicher Programmierfehler ausgenutzt werden, um unberechtigt Zugriff auf ein Computersystem zu erhalten. Andere Systeme wie Stack-Smashing Protector und StackGuard versuchen, Pufferüberläufe direkt zu verhindern und das entsprechende Programm bei Entdeckung zu beenden. Dieser Ansatz wird Stack-Smashing genannt und versucht, die Angriffe abzuwehren, bevor sie überhaupt durchgeführt werden können. Der allgemeinere Ansatz von PaX hingegen verhindert Schaden, nachdem der Angriff begonnen hat. Obwohl beide Methoden dieselben Ziele erreichen können, sind sie nicht völlig redundant. Dadurch wird ein Betriebssystem bei Verwendung beider Methoden prinzipiell sicherer. Es gibt bereits Linux-Distributionen, die beide Methoden benutzen.

Einschränkungen Bearbeiten

PaX kann Fehler im Design von Programmen oder des Kernels, die einen Missbrauch der angebotenen Funktionen erlauben, nicht verhindern. Diese Fehler sind im Prinzip so auch nicht feststellbar. Als Beispiel mag man einen Script-Interpreter betrachten, der Zugriff auf Dateien und Netzwerk erlaubt und diese Funktionen ungenügend schützt: Der Angreifer könnte auf Dateien von anderen Benutzern zugreifen, ohne dabei am Programm etwas „verbiegen“ zu müssen. PaX kann auch nicht alle Formatstring-Angriffe abwehren, die beliebiges Lesen und Schreiben in Datenbereiche des Speichers durch bereits existierenden Code erlauben; der Angreifer braucht weder interne Adressen zu wissen noch fremden Code einzuschleusen, um diesen Typ Angriff durchführen zu können.

Die PaX-Dokumentation beschreibt die folgenden drei Klassen von Angriffen, vor denen PaX zu schützen versucht. Sie behandelt sowohl Angriffe, die PaX abwehrt, als auch solche, die nicht abgewehrt werden. Alle setzen ein vollständiges, positionsunabhängiges Programm mit Schutz des Programmspeichers und zufälliger Anordnung des Adressbereiches voraus. Folgende Angriffe können dann blockiert werden:

  1. Angriffe, die fremden Code einschleusen und ausführen,
  2. Angriffe, die existierenden Code nicht in dem vom Programmierer vorgesehenen Ablauf ausführen (ret2libc),
  3. Angriffe, die existierenden Code mit falschen Daten ausführen
  • Die dritte Klasse ist trotz PaX möglich, wenn der Angreifer keine Kenntnis von Adressen des angegriffenen Programms benötigt.
  • Die zweite und dritte Klasse sind dann zuverlässig möglich, wenn der Angreifer zwar Kenntnis von Adressen benötigt, diese aber durch Auslesen des Adressbereiches des angegriffenen Programms erlangen kann. Dies ist möglich, wenn das Ziel einen entsprechenden sicherheitskritischen Programmierfehler hat, der den Zugriff auf diese Informationen erlaubt, z. B. wenn der Angreifer Zugriff auf /proc/(pid)/maps hat.

Es existiert hierfür ein Patch, der alle Werte für Adressbereiche und Inodes in jeder Informationsquelle, die vom Userland erreichbar ist, ausnullt. Dieser Patch ist zurzeit jedoch nicht in PaX enthalten.

  • Die zweite und dritte Klasse sind mit geringer Erfolgswahrscheinlichkeit möglich, wenn der Angreifer Kenntnis von Adressen benötigt, diese aber nicht erhalten kann (brute-force und raten ausgenommen). Die ASLR-Dokumentation[1] beschreibt, wie man die geringe Erfolgswahrscheinlichkeit genauer messen kann.
  • Die erste Klasse ist möglich, wenn der Angreifer das Programm benutzen kann, um eine Datei anzulegen, zu beschreiben und via mmap() in den Speicher einblenden kann. Dies verlangt jedoch, dass die Angriffsmethoden der zweiten Klasse möglich sind; es gelten also dieselben Bedingungen wie ebenda beschrieben. Obwohl nicht Teil von PaX, wird unter anderem empfohlen, dass produktive Systeme Kontrollmechanismen einsetzen, die solche Angriffe verhindern.

Verantwortungsvolle Systemadministration ist trotz PaX immer noch notwendig. PaX verhindert oben beschriebene Angriffe, dennoch besteht die Möglichkeit eines erfolgreichen Angriffes.

Geschichte Bearbeiten

Dies ist eine, noch nicht vervollständigte Liste der Geschichte von PaX, sie sollte bearbeitet werden, soweit neue Informationen gegeben sind.

  • Oktober, 2000: PaX Erstveröffentlichung mit normaler PAGEEXEC-Methode
  • November, 2000: erste Integration von MPROTECT veröffentlicht
  • Juni, 2001: ASLR (mmap randomization) implementiert, nicht veröffentlicht
  • Juli, 2001: ASLR veröffentlicht
  • August, 2001: ASLR mit zusätzlichem Stapelspeicher (stack) und PIE randomization veröffentlicht
  • Juli, 2002: VMA Mirroring und RANDEXEC veröffentlicht
  • Oktober, 2002: SEGMEXEC veröffentlicht
  • Oktober, 2002: ASLR mit zusätzlicher Kernel Stack randomization veröffentlicht
  • Februar, 2003: EI_PAX ELF Markierungsmethode eingeführt
  • April, 2003: KERNEXEC (nicht-ausführbare kernel pages) veröffentlicht
  • Juli, 2003: ASLR mit zusätzlicher brk randomization veröffentlicht
  • Februar, 2004: PT_PAX_FLAGS ELF Markierungsmethode eingeführt
  • Mai, 2004: PAGEEXEC mit Code-Segment-Limit-Tracking für verbesserte Leistung erweitert
  • 4. März, 2005: VMA Mirroring Schwachstelle angekündigt, neue Version von PaX und grsecurity veröffentlicht, alle vorherigen Versionen mit SEGMEXEC und RANDEXEC haben eine Rechteausweitung als Schwachstelle
  • 1. April, 2005: Wegen der Schwachstelle sollte das PaX Projekt einen neuen Entwickler bekommen, doch da sich niemand fand, hat der alte Entwickler das Projekt in Wartung gestellt.

Was PaX bietet Bearbeiten

Schutz des Programmspeichers Bearbeiten

 
Fig. 1 Speichersegmente eines Programms. Blaue Segmente bezeichnen Code, grüne Daten.

Einer der Hauptmerkmale von PaX ist der Schutz von Programmbereichen des Speichers. Dieser Schutz verwendet das NX-Bit auf bestimmten Prozessoren, um die Ausführung von fremden Code zu verhindern; dies fängt Angriffe ab, die auf Injektion von fremden Code oder Shellcode beruhen. Auf IA-32-CPUs ist das NX-Bit nicht vorhanden, PaX kann in diesem Fall dessen Funktionalität auf verschiedenen Wegen emulieren.

Viele Betriebssysteme, einschließlich Linux, nutzen auf x86-Prozessoren dessen NX-Bit, falls vorhanden, um korrekte Einschränkungen auf den Speicher anzuwenden. Fig. 1 zeigt eine einfache Zusammenstellung von Speichersegmenten in einem Programm mit einer geladenen Bibliothek; grüne Segmente sind dabei Daten, blaue sind Programmcode. Unter normalen Umständen sieht der Adressbereich auf AMD64 und anderen derartigen Prozessoren ähnlich wie dieses Bild aus, mit klar definierten Daten- und Codesegmenten. Unglücklicherweise verwehrt Linux standardmäßig einem Programm nicht, seinen Speicherschutz zu ändern; jedes Programm kann Codesegmente als beschreibbar und Datensegmente als ausführbar kennzeichnen. PaX verhindert solche Änderungen, sowie es auch möglichst hohe Einschränkungen garantiert, die eine normale Ausführung erlauben.

Wenn die verschiedenen Schutzvorkehrungen des Programmspeichers aktiviert sind, einschließlich der mprotect()-Einschränkungen, garantiert PaX, dass keinerlei Speicherzuordnungen in irgendeiner Weise als ausführbarer Programmcode markiert werden können, nachdem es möglich gewesen wäre, den Zustand dieser Bereiche zu ändern. Der Effekt dieser Maßnahme ist, dass es unmöglich wird, Speicherbereiche auszuführen, während oder nachdem sie verändert werden können, bis diese Bereiche schließlich wieder freigegeben werden; und damit, dass kein Code in das Programm eingeführt werden kann, ob nun schädlich oder nicht, weder von einer internen noch einer externen Quelle.

Die Tatsache, dass Programme Datenbereiche nicht ausführen können, obwohl die dort gespeicherten Daten dafür vorgesehen wären, stellt ein unüberwindliches Problem für ebendiese Programme dar. Ein Beispiel hierfür sind die Just-in-time-Compiler für Java; jedoch können viele dieser Programme vom Programmierer so geändert werden, dass sie nicht auf dieser Funktionalität beruhen. Die anderen können durch den Systemadministrator gekennzeichnet werden, PaX wendet dann die Einschränkungen für diese nicht an.

Das PaX-Team musste einige Entscheidungen im Bezug auf die Behandlung des mmap()-Aufrufes treffen. Diese Funktion wird dazu verwendet, gemeinsamen Speicher (Shared Memory) abzubilden oder dynamische Bibliotheken (shared libraries) zu laden. Daher benötigt der Aufruf beschreibbare oder ausführbare Speicherbereiche, abhängig von den jeweiligen Bedingungen.

Die aktuelle Implementierung von PaX unterstützt beschreibbare anonyme Speicherabbildungen standardmäßig; beschreibbare Abbildungen einer Datei sind nur beschreibbar, wenn der mmap()-Aufruf das Schreibrecht angibt. Es werden jedoch nie Abbildungen zurückgegeben, die beschreib- und ausführbar sind; sogar wenn der Aufruf diese Rechte explizit angibt.

Distributionen, die PaX verwenden Bearbeiten

  • Gentoo mit gepatchtem Kernel (sys-kernel/hardened-sources).
  • Alpine nutzte bis Version 3.8 einen mit PaX gepatchten Kernel und bot passende Gnome Pakete[2].

Referenzen Bearbeiten

Weblinks Bearbeiten

Einzelnachweise Bearbeiten

  1. Address Space Layout Randomization. In: pax.grsecurity.net, abgerufen am 7. Juni 2021.
  2. About Alpine Linux. In: alpinelinux.org, 2021, abgerufen am 7. Juli 2021.