Systemtap: "mmap()" und TOCTTOU-Attacke

Das Tool Systemtap dient dazu, den Linux-Kernel und Anwendungen zu überwachen. Eine kürzlich entdeckte Schwachstelle erlaubt es einem Angreifer aus der Gruppe “stapusr”, eigene Befehle einzuschleusen, die dann unter Umständen mit Kernel-Rechten ausgeführt werden.

Systemtap-Anwender können Monitor-Code in einer Skriptsprache verfassen und mit dem “stap”-Tool in ein Modul übersetzen. Die Software ruft nach dem Übersetzen “staprun” auf, um das Modul zu prüfen und in den Kernel zu laden. Ein einfaches Beispielskript aus der Systemtap-Dokumentation sieht so aus:

probe syscall.open
{ printf ("%s(%d) open (%s)\n", execname(), pid(), argstr)
}
probe timer.ms(10000)
{ exit ()
}

Dieses Skript wird in “test.stp” gespeichert und mit dem Kommando “stap test.stp” kompiliert sowie in den Kernel geladen. Anschließend protokolliert es für 10 Sekunden alle “open()”-Systemaufrufe samt ein paar Zusatzinformationen.

TOCTTOU

Bei der entdeckten Sicherheitslücke handelt es sich um ein TOCTTOU-Problem. Dieser Zungenbrecher steht für “Time-of-Check-to-Time-Of-Use” und beschreibt eine spezielle Form der Race Condition in Programmcode. TOCTTOU-Schwachstellen treten immer dann auf, wenn zwischen dem Prüfen und dem Verwenden von Daten die Möglichkeit besteht, diese zu modifizieren. Dadurch können ungeprüfte Daten verarbeitet werden, was im Allgemeinen ein Sicherheitsrisiko darstellt.

Die Systemtap-Schwachstelle befindet sich im Code zum Laden des kompilierten Moduls. Dieser steckt in der Funktion “insert_module()” in der Datei “staprun_funcs.c”. Vor dem Laden des Moduls werden einige Kontrollen durchgeführt, um keinen kritischen Code in den Kernel zu laden. Um hierbei explizit TOCTTOU-Probleme zu vermeiden, wird in “insert_module()” die Modul-Datei zunächst mit der Funktion “mmap()” in den Speicher kopiert:

/* mmap in the entire module. Work with the memory mapped data from this point on to avoid a TOCTOU race between path and signature checking below and module loading. */
module_file = mmap(NULL, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, module_fd, 0);
if (module_file == MAP_FAILED) { _perr("Error mapping '%s'", module_realpath); close(module_fd); free(opts); return -1;
}

Wie der Code-Kommentar andeutet soll das verhindern, dass die Modul-Datei zwischen dem eigentlichen Laden und den vorhergehenden Prüfaktionen verändert wird. Nach dem “mmap()”-Aufruf befindet sich die Datei im Speicher an der Adresse “module_file”, und die nachfolgenden Kontrollen werden direkt auf diesem Speicherbereich durchgeführt. Nach erfolgreichem Durchlauf durch diese Routinen lädt “init_module()” das Speicherabbild der Modul-Datei in den Kernel.

Die Idee hinter diesem “mmap()”-Verfahren ist, dass selbst wenn die Modul-Datei nach den Sicherheitschecks verändert wurde, nur die im Speicher befindliche geprüfte Version in den Kernel geladen wird, und damit kein Schaden entstehen kann. Die Funktion “mmap()” wird absichtlich mit “MAP_PRIVATE” aufgerufen, um eine private Copy-on-Write-Map zu erzeugen. Dabei haben die Entwickler allerdings die Manpage von “mmap()” nicht genau gelesen und damit die Race Condition in den Code eingebaut. Das Manual besagt nämlich:

MAP_PRIVATE
Create a private copy-on-write mapping. Updates to the mapping are not visible to other processes mapping the same file, and are not carried through to the underlying file. It is unspecified whether changes made to the file after the mmap() call are visible in the mapped region.

Der letzte Satz besagt, dass nicht spezifiziert ist, ob Dateiänderungen an den gemappten Speicherbereich weitergegeben werden oder nicht. Wie sich zeigte, kann dies in der Tat geschehen, womit der gesamte “mmap()”-basierte TOCTTOU-Schutz zusammenbricht. Es ist also für einen lokalen Angreifer möglich, eine Datei einzuschleusen und damit die von ihm gewünschten Befehle auszuführen.

Das am 25. Juli im Code-Repository eingefügte Patch verabschiedet sich komplett vom “mmap()”-Einsatz und verwendet stattdessen die Funktion “read()”, um die Datei in den Speicher zu lesen. Diese hinterlässt keinerlei Verbindung mit der eigentlichen Datei, was das Problem eliminiert.

In Systemtap wurde noch ein weitere Sicherheitslücke entdeckt, durch die ein Angreifer aus der Gruppe “stapusr” ebenfalls höhere Rechte erlangen kann. Die Ursache ist ein Fehler beim Verarbeiten von Pfadangaben im Programm “staprun”. Diese Sicherheitslücke wurde ebenfalls am 25. Juli im Repository korrigiert.

Nach oben