Ring (CPU)
Der Ring, auch Domain genannt, bezeichnet (im Umfeld der Betriebssystem-Programmierung und des Multitaskings) eine Privilegierungs- bzw. Sicherheitsstufe des gerade laufenden Programmcodes. Es handelt sich um eine Funktion der Hardware, durch die der auf der CPU nutzbare Befehlssatzes und der verwendbare Speicherbereich dynamisch eingeschränkt werden kann. Die Nutzung von Privilegierungsebenen ist sinnvoll, um die Hardware zu abstrahieren und um Prozesse voneinander und vom Betriebssystem und Treibern abzuschotten.
Ringe
Es gibt verschiedene Ringmodelle. Für Hypervisoren führten Intel und AMD auf neueren CPUs einen zusätzlichen „Ring -1“ ein und es gibt Ringmodelle mit mehr als vier Ringen (wie bei x86-Systemen).
x86
Auf x86-Systemen sind die Sicherheitsstufen in vier Ringe aufgeteilt, wobei Ring 0 der privilegierteste Ring ist. Die beiden Ringe 1 und 2 werden auf dieser Systemfamilie nicht verwendet. Alle Anwendungen laufen im Ring 3 und müssen über den Kernel mit z. B. der Hardware kommunizieren (Systemaufrufe).
Ring 0 (Kernel-Mode)
Im innersten Ring (höchste Berechtigungsstufe; privilegierte Ebene; System-Ebene; Kern-Ebene) läuft meist das Betriebssystem, evtl. sogar nur dessen Kernel und damit dessen Bestandteile wie Prozessverwaltung, Speicherverwaltung, Geräteverwaltung, Dateisysteme und Schnittstellen zur Hardware. Das Betriebssystem „darf alles“, insbesondere direkte Hardwarezugriffe und das Eingreifen in die RAM-Bereiche anderer Prozesse. Auch sich im Kernel befindliche Treiber werden in Ring 0 ausgeführt.
Code auf dieser Ebene darf...
- alle CPU Anweisungen ausführen
- auf jeden Speicherbereich zugreifen
- auf E-/A-Geräte zugreifen (über Treiber)
Ring 1 und 2
Von den verbreitetsten Rechnerarchitekturen besitzt nur die x86-Familie diese Zwischenstufen zwischen Kernel-Mode und User-Mode. In den Betriebssystemen Windows und Linux werden diese Zwischenstufen nicht verwendet.
Ring 3 (User-Mode)
Anwendungsprogramme sind üblicherweise auf den äußersten Ring beschränkt (niedrigste Berechtigungsstufe). Für Operationen, welche einen Hardwarezugriff erfordern, müssen Anwendungsprogramme Betriebssystem-Dienste beauftragen.
Ring -1 (Hypervisor-Mode)
Von den meisten aktuelle Rechnerarchitekturen wird gefordert, dass übliche Betriebssysteme, die für einen Betrieb in Ring 0 ausgelegt sind, Hardware-unterstützt virtualisiert ausgeführt werden können. Dazu muss es eine Berechtigungsstufe „oberhalb“ von Ring 0 geben, die oft „Ring -1“ oder „Hypervisor-Mode“ genannt wird.
Umsetzung
Der Befehlssatz wird für unprivilegierte Prozesse („Userland“) derart eingeschränkt, dass sie nicht direkt auf die Hardware zugreifen können und sich auch nicht aus ihrer Privilegierungsebene befreien können. Der Zugriff auf den Speicherbereich anderer Prozesse wird meist durch Speichervirtualisierung verhindert. Somit wird gewährleistet, dass Programmcode in äußeren Ringen nicht eigenmächtig auf Programmcode oder Daten des Kernels und anderer Systemdienste in inneren Ringen zugreifen kann. Die gleiche Speichervirtualisierung wird üblicherweise auch eingesetzt, um unterschiedliche Prozesse voneinander zu isolieren. Da die unprivilegierten Prozesse auf Hardware nicht direkt zugreifen können, existieren sogenannte „Gates“, mit denen Programmcode aus äußeren Ringen Programmcode aus inneren Ringen aufrufen kann, insbesondere ist so die Programmierschnittstelle des Kernels erreichbar, um die notwendigen Aktionen anzufordern.
Die meisten Prozessor-Architekturen bieten nur zwei Ringe: Programmcode im Ring 0 befindet sich im Kernelmodus (engl. „kernel mode“), Kernelraum (engl. „kernel space“) oder ist Superuser-Code (engl. „super user code“) – alle anderen im Benutzermodus (engl. „user mode“) oder Benutzerraum (engl. „user space“).
Ablauf eines Betriebssystemaufrufs
Ein (mit niedriger Berechtigung laufender) Prozess wählt durch geeignetes Setzen von CPU-Registern und Speicherbereichen die auszuführende Funktion des Betriebssystems und setzt die benötigten Parameter. Anschließend löst er per CPU-Befehl einen Softwareinterrupt aus. Der Prozess wird dadurch unterbrochen, die CPU wechselt in den innersten Ring („Kernel mode“) und setzt die Ausführung mit einer speziellen Betriebssystem-Routine fort. Diese sichert zunächst weitere (CPU-)Zustände, die nicht von der CPU selbst im Rahmen des Softwareinterrupts bereits gesichert wurden, um beispielsweise freie Register für das eigene Ablaufen zu haben. Anschließend agiert sie gemäß dem angeforderten Auftrag: Sie übergibt ihn an den zuständigen Treiber, reiht ihn in eine Warteschlange zur Abarbeitung durch einen Kernel-Thread ein oder kann evtl. den Auftrag selbst ausführen. In den ersten beiden Fällen wird anschließend meist ein vollständiger Kontextwechsel zu einem anderen Prozess durchgeführt, da der aufrufende Prozess erst weiter laufen kann, wenn das Betriebssystem den Auftrag vollständig abgearbeitet hat. Sobald der Auftrag vollständig abgearbeitet wurde, legt die Betriebssystem-Routine die Rückgabewerte in die Speicherbereiche des Prozesses ab und vermerkt ggf. weitere Rückgabewerte für bestimmte CPU-Register in dessen Prozesskontext. Der anfordernde Prozess wird als „bereit“ markiert und später im Rahmen des regulären Schedulings wieder (mittels Kontextwechsel) fortgesetzt: Eine spezielle CPU-Instruktion schließt den Kontextwechsel ab, die CPU „kehrt aus dem Softwareinterrupt zurück“, wodurch die CPU wieder in den User-Mode (äußerster Ring) zurück wechselt und die Ausführung des niedrig-berechtigten Prozesses direkt nach der Unterbrechungsstelle fortsetzt.
Voraussetzung
In der CPU und ggf. MMU müssen Schaltungen bestehen, die bei jedem Befehl bzw. Speicherzugriff prüfen, ob dieser im aktuellen Ring erlaubt ist. Falls ein Prozess etwas nicht Erlaubtes durchführen möchte, wird er unterbrochen und eine Betriebssystem-Routine aufgerufen, deren Aufgabe es ist, entsprechend zu reagieren.
x86-Prozessor-Systeme
Intel-80286-kompatible Prozessoren unterscheiden vier Privilegierungsstufen: Ring 0, 1, 2 und 3. Dabei stellt Ring 0, genannt „supervisor mode“, die höchste Privilegierungsstufe dar, die bis zur Stufe 3 (Ring 3) immer weiter eingeschränkt wird. Beispiele für Assembler-Anweisungen, die im Ring 0, jedoch nicht im Ring 3 ausgeführt werden dürfen sind z. B. „cli“ und „sti“. Mit diesen Anweisungen wird die Behandlung von (maskierbaren) Hardwareinterrupts ab- bzw. eingeschaltet. Ursprünglich waren die Ringe für den Kernel (Ring 0), Treiber (Ring 1), Systemdienste (Ring 2) und Anwendungsprogramme (Ring 3) vorgesehen.
Um Prozesse in einem geschützten Bereich (Ring > 0) ablaufen zu lassen, wird der physikalische Arbeitsspeicher in virtuelle Speicherseiten aufgeteilt. Zu jeder Speicherseite existiert eine Tabelle, in der unter anderem gespeichert ist, in welchem Level (Ring) der Programmcode, der innerhalb dieser Speicherseite gespeichert ist, ausgeführt wird. Diese Auswertung nimmt die MMU meist extern vor.
Mit der Einführung des AMD64-Opcodes, den auch Intel für einige seiner Prozessoren als Intel 64 übernommen hat, existiert im Speicherseitendeskriptor zusätzlich das NX-Flag (engl. „No eXecution“), das eine Unterscheidung zwischen Daten und Programmcode ermöglicht, um so Sicherheitslücken durch Pufferüberläufe vorzubeugen. Der Pufferüberlauf wird zwar nicht direkt verhindert, Programmcode in Datenseiten kann dabei aber nicht ausgeführt werden.
Wechsel zwischen den Ringen
Für einen Wechsel des Rings stehen drei Gate-Typen zur Verfügung, die bei ihrer Verwendung unterschiedlich viel Rechenzeit in Anspruch nehmen, da jeder Wechsel von einem Ring zum anderen auch einen Kontextwechsel zumindest einiger Zustände in der CPU darstellt:
- Call-Gates für den direkten Aufruf von Programmcode aus höheren Privilegierungsebenen. Das Call-Gate bestimmt dabei, an welcher Stelle und mit welchen Privilegien der aufgerufene Programmcode laufen wird. Aus Sicherheitsgründen wird hierbei dem Programmcode aus der höheren Privilegierungsebene ein eigener Stapel zugewiesen, die Aufrufparameter vom Stapel des aufrufenden Codes werden in den neuen Stapel kopiert. Im übrigen läuft der privilegierte Code im Kontext des aufrufenden Codes.
- Interrupt-Gates werden zum einen beim Auslösen eines so genannten Software-Interrupts verwendet, aber auch Hardware-Interrupts erfordern ein Interrupt-Gate. Zusätzlich zu allen Schritten, die beim Benutzen eines Call-Gates durchgeführt werden, wird zusätzlich das Flags-Register auf dem Stapel gespeichert und weitere Interrupts bis zur Rückkehr der Interrupt-Routine gesperrt.
- Task-Gates erlauben die Kontrolle an einen anderen Prozess abzugeben. Dies stellt die aufwändigste Form eines Kontextwechsels dar, da hier der vollständige Prozessorzustand des aufrufenden Prozesses gespeichert und des aufgerufenen Prozesses geladen werden muss.
Betriebssysteme auf x86
Die verbreiteten Betriebssysteme für x86 Linux und Windows (sowie macOS für x64 und DOS mit EMM386.EXE-Speichermanager) nutzen lediglich zwei der vier möglichen CPU-Ringe. Im Ring 0 werden der Kernel und alle Hardwaretreiber ausgeführt, während die Anwendungssoftware im unprivilegierten Ring 3 arbeitet. Damit bleibt die Portabilität des Betriebssystems auch auf Prozessorarchitekturen gewährleistet, die nur zwei Ringe unterscheiden können. OS/2 benutzt allerdings Ring 2 für Grafiktreiber.[1] Eine speziell angepasste Version des Speichermanagers EMM386 aus dem Entwicklungskit für DOS Protected Mode Services (für Novell DOS 7, OpenDOS 7.01 und DR-DOS 7.02 und höher) lässt DPMS auf Ring 1 statt auf Ring 0 laufen und erleichtert so die Fehlersuche bei Software, die DPMS nutzt.
Die verstärkt verwendeten Virtualisierungslösungen verwenden auch Ring 1. Hierbei wird der Betriebssystemkern aus Ring 0 in Ring 1 verschoben, der Hypervisor residiert dann als darüberliegende Schicht in Ring 0 und verwaltet einen oder mehrere in Ring 1 laufende Betriebssystemkerne. Dies kann allerdings auch durch Rootkits ausgenutzt werden, um Schadcode unbemerkt vom Anwender auf dem Ring 0 ausführen zu lassen (siehe auch Virtual Machine Based Rootkit).
Um die Verwendung von Hypervisoren zu vereinfachen, führen neuere CPUs von Intel und AMD einen neuen „Ring -1“ ein, so dass der Betriebssystemkern in Ring 0 verbleibt, während der Hypervisor als darüberliegende Schicht in Ring -1 residiert. Dabei verwaltet er einen oder mehrere Betriebssystemkerne in Ring 0.
Nicht-x86-Systeme
Die bei x86-Prozessoren vorgenommene Einteilung in vier Ringe wurde schon früher eingesetzt, z. B. bei der VAX. Der Alpha-Prozessor unterstützt einen zusätzlichen geschützten Bereich für dessen PAL-Code, welcher als Ring −1 aufgefasst werden könnte. Die Honeywell 6180, das erste System mit Hardware-Unterstützung für dieses Konzept, kannte acht Ringe.
Bei vielen aktuellen Prozessoren wird oft nur zwischen Supervisor- („alles ist erlaubt“) und User-Modus (eingeschränkte Zugriffe auf Speicherbereiche/Systemressourcen/CPU-Register) unterschieden. Der Schutz des Arbeitsspeichers erfolgt über die Seitenverwaltungseinheit MMU der CPU.
Dieses Prinzip lässt sich auch auf x86-Systemen anwenden, indem der Speicher über die Segmentierung als Flat Memory angelegt wird. Dabei läuft die CPU nur in den Privilegierungsstufen 0 und 3.
Einzelnachweise
- Presentation Device Driver Reference for OS/2 (Memento des Originals vom 16. Juni 2013 im Internet Archive) Info: Der Archivlink wurde automatisch eingesetzt und noch nicht geprüft. Bitte prüfe Original- und Archivlink gemäß Anleitung und entferne dann diesen Hinweis. auf warpspeed.com (englisch)