iX 5/2018
S. 96
Wissen
Betriebssystemtechnik
Aufmacherbild

Die Arbeitsweise des Windows Subsystem for Linux

Auf der Fensterbank

Spielzeug oder verzweifelter Versuch, die Linux-Gemeinde anzugraben – konnte man sich 2016 fragen, als Microsoft das Windows Subsystem for Linux veröffentlichte. Heute findet die Kompatibilitätsschicht immer mehr Unterstützung.

Das Windows Subsystem for Linux (WSL), in Zusammenarbeit mit dem britischen Linux-Distributor Canonical entwickelt und 2016 für Windows 10 eingeführt, ist nicht etwa eine kleine virtuelle Maschine, sondern eine Kernel-Schnittstelle, die Linux-ELF64-Binaries (Executable and Linking Format) im User Mode starten kann. Neu und ein Hexenwerk ist ein solches Konstrukt keineswegs.

Bereits mit Windows NT gab es solche Subsysteme, etwa das POSIX-, das OS/2- und das MS-DOS-Subsystem zum Ausführen von POSIX-, OS/2- und MS-DOS-Anwendungen. Ersteres hat Microsoft mit Windows XP/2003 durch das in den Services for Unix (SFU) enthaltene Interix 3.5, kurz darauf durch das Subsystem for Unix-based Applications (SUA) oder Interix 5.2 und höher ersetzt. Der Unterschied zu den früheren Kompatibilitätsversuchen: WSL arbeitet anders. Das Herzstück bilden sogenannte Pico-Prozesse (PP) und Pico-Provider-Treiber (PT). Letztere, genauer gesagt die Windows-Kernel-Treiber lxss.sys und lxcore.sys, emulieren den Linux-Kernel. Linux-Programme laufen als Pico-Prozesse im User Mode, wo die Pico-Provider-Treiber sie auf Kernel-Level verwalten.

Ein Pico-Prozess unterscheidet sich erheblich von einem normalen Windows-Prozess. Bei letzterem ist der Windows-Kernel, den Microsoft bis heute als NT-Kernel bezeichnet, immer darüber informiert, was in diesem Prozess abläuft. Zum Beispiel darf er immer erwarten, in normalen NT- und Win32-Prozessen eine ntdll.dll, den Shared-User-Data-Bereich sowie einen Process Environment Block (PEB) vorzufinden. Außerdem enthält jeder Thread, der innerhalb eines Prozesses läuft, einen Thread Environment Block (TEB). All dies und mehr „weiß“ der Windows-Kernel und agiert entsprechend. Er kann also jederzeit eine Routine in der ntdll.dll kontaktieren, etwas in die Shared User Data schreiben oder dem Prozess mitteilen, dass er sterben soll. Denn in der Windows-Welt ist es völlig normal, dass der Kernel einen Prozess aktiv steuert.

Treiber imitiert Kernel

Bei einem Pico-Prozess ist das anders. Der Kernel hat keine Kenntnis darüber, was innerhalb solcher Prozesse abläuft. Stattdessen reicht er alle Aktionen an die Pico-Provider-Treiber weiter. Da die PT den Linux-Kernel nur emulieren, müssen sie auch die Sprache, in der Linux-Anwendungen und -Kernel miteinander kommunizieren, übersetzen. Dazu gehören die Systemcalls, die die Treiber in die entsprechenden Windows-Gegenstücke übertragen und an den NT-Kernel zurückreichen. Werden die PT etwa mit dem Systemaufruf fork() konfrontiert, ist es noch relativ einfach, weil im Windows-Kernel eine vergleichbare Operation versteckt ist, die interne NT-Kernel-APIs abbilden können (siehe Kasten „Neu und doch nicht neu – Unix-Features im Windows“).

Gelingt die Übersetzung nicht, etwa weil die Windows-Welt keinen vergleichbaren Systemaufruf kennt, können die Pico-Treiber sie selbst verarbeiten. Ein Beispiel: Linux hat ein völlig anderes Dateisystem-Rechtemodell als Windows. Nichtsdestotrotz müssen die Linux-Dateisystem-Rechteinformationen als Metadaten irgendwie in NTFS abgebildet werden. Da die PT hierfür keinen Windows-Systemaufruf bemühen können, schreiben sie die Metadaten einfach in ein erweitertes Attribut der NTFS-Datei. Dieses Attribut dient dann als Quelle für Linux-Dateisystemrechte.

Ähnlich wie der Linux-Kernel besitzen die PT nur wenige Informationen über einen PP und kontaktieren ihn nur selten. In der Regel nimmt der PP Kontakt zu den PT auf. Beim Starten eines Pico-Prozesses alloziert der PT lediglich ein vDSO (Virtual Dynamically Linked Shared Object), also einen Speicherbereich, der mit jedem Pico-Prozess angelegt wird und den alle gemeinsam nutzen. Außerdem initialisiert er beim Starten von ELF64-Binaries einen Thread-Stack und legt das Binary oder zumindest die zum Starten benötigten Teile hinein. Diese laufen dann im User Mode. Die PT agieren von da an nur selten, vielmehr reagieren sie auf die Anforderungen der PP.