Linux 5.10: Kommende Kernel-Version bricht mit fast 30-jährigem Erbe

Das allmähliche Ausrangieren einer unsicheren Funktion soll den Kernelspace ab Linux 5.10 besser schützen. Wir gehen der Änderung auf den Grund.

In Pocket speichern vorlesen Druckansicht 111 Kommentare lesen

(Bild: Gordon Leggett / Wikimedia Commons / CC BY-SA 4.0)

Lesezeit: 8 Min.
Von
  • Oliver Müller
Inhaltsverzeichnis

Mit dem ersten Release Candidate von Linux 5.10 kündigte Linus Torvalds Ende Oktober eine historische Änderung an: Der bereits seit 1991 vorhandene set_fs()-Mechanismus soll mit der kommenden Kernel-Version wenn schon nicht auf allen, so doch zumindest auf einigen CPU-Architekturen ausgemustert werden.

Der Aufruf von set_fs() ermöglicht nachfolgenden Userspace-Zugriffsfunktionen typischerweise den Zugriff auf den geschützten Speicherbereich des Kernels – oder nimmt ihnen diese Möglichkeit wieder. Das Erbe aus alten 386er-Tagen sorgte in der Vergangenheit allerdings auch für schwerwiegende Sicherheitsprobleme. In diesem Artikel schauen wir uns die Funktionsweise von set_fs(), die der Funktion innewohnenden Gefahren und die sich aus dem Wegfall ergebenden Konsequenzen ein wenig näher an.

Die Kernelfunktion set_fs() war seit dem Release 0.10, also seit Ende 1991, fester Bestandteil des Linux-Kernels. Linux war damals noch auf den 80386-Prozessor zugeschnitten und nutzte zwangsläufig das, was diese CPU bot.

Das Betriebssystem verwendete das FS-Register des 386ers, um für aufzurufende Funktionen jeweils Kernel- oder Userspace zugänglich zu machen. Logische Speicheradressen setzen sich aus einem Segmentselektor und einem Offset zusammen. Der Segmentselektor im FS-Register zeigt unter normalen Umständen auf den Userspace. Durch das Setzen des FS-Registers durch set_fs() auf den Kernelspace können Userspace-Zugriffsfunktionen wie get_user_byte() auf den Kernelspace zugreifen. Das kommt einem Umdeklarieren gleich: Es lassen sich auf diese Weise Zeiger zwischen Userspace und Kernelspace direkt austauschen.

Gedacht war dieser Mechanismus, um effizient aus dem Kernelspace heraus Funktionen anzusprechen, die sonst auf den Userspace beschränkt sind. Ein Beispiel aus jenen Tagen ist das UMSDOS-Dateisystem. Es bildet ein Unix-Dateisystem auf einem darunterliegenden MS-DOS-Dateisystem ab und greift über Systemfunktionen auf den MS-DOS-Dateisystemtreiber zu. Da beide – UMSDOS- und MS-DOS-Dateisystemtreiber – im Kernelspace liegen, bedient(e) man sich des set_fs()-Tricks, um den Funktionen "vorzugaukeln", aus dem Userspace zu kommen.

Die Namen der Funktionen set_fs(), get_fs() und Co. sind gleichgeblieben – das FS-Register verwendet der Kernel bei ihrem Aufruf heute aber nicht mehr. An seine Stelle trat ab Version 2.2 die plattformunabhängige globale Variable addr_limit, deren Wert die Grenze zwischen User- und Kernelspace anzeigt. Alles unterhalb ist Userspace, alles darüber Kernelspace. Im Vergleich zum FS-Register ermöglicht addr_limit eine wesentlich einfachere Prüfung einer Adresse auf Gültigkeit. Es genügt ein arithmetischer Vergleich mit dem Variablenwert, um festzustellen, ob die Adresse im User- oder im Kernelspace beheimatet ist.

Die Kernelfunktion access_ok() prüft beispielsweise eine Adresse gegen addr_limit, um sie allgemein dem User- oder Kernelspace zuordnen und den Zugriff zu bewerten. Den weiteren Zugriffsschutz überlässt der Kernel mittlerweile der Memory Management Unit (MMU) des Prozessors.