Wenn ich ein Programm schreibe, das versucht, Speicher an jeder möglichen Adresse zu lesen, und es unter einem "vollen" Unix ausführe, kann es nicht auf den gesamten physischen RAM zugreifen. Aber wie verhindert das Betriebssystem dies?
Ich bin eher mit kleinen CPU-Architekturen vertraut, bei denen jeder Assembler-Code auf alles zugreifen kann. Ich verstehe nicht, wie ein Programm (der Kernel) solche böswilligen Operationen erkennen kann.
Antworten:
Es ist nicht der Kernel, der schlechte Speicherzugriffe verhindert, sondern die CPU. Die Rolle des Kernels besteht nur darin, die CPU korrekt zu konfigurieren.
Genauer gesagt ist die MMU die Hardwarekomponente, die fehlerhafte Speicherzugriffe verhindert . Wenn ein Programm auf eine Speicheradresse zugreift, wird die Adresse von der CPU basierend auf dem Inhalt der MMU decodiert. Die MMU erstellt eine Übersetzung von virtuellen Adressen in physische Adressen: Wenn die CPU eine bestimmte virtuelle Adresse lädt oder speichert, berechnet sie die entsprechende physische Adresse basierend auf dem MMU-Inhalt. Der Kernel stellt die MMU-Konfiguration so ein, dass jedes Programm nur auf den Speicher zugreifen kann, auf den es Anspruch hat. Die Speicher- und Hardwareregister anderer Programme werden im Speicher eines Programms überhaupt nicht zugeordnet: Diese physischen Adressen haben in der MMU-Konfiguration für dieses Programm keine entsprechende virtuelle Adresse.
Bei einem Kontextwechsel zwischen verschiedenen Prozessen ändert der Kernel die MMU-Konfiguration so, dass sie die gewünschte Übersetzung für den neuen Prozess enthält.
Einige virtuelle Adressen werden überhaupt nicht zugeordnet, dh die MMU übersetzt sie in einen speziellen Wert "Keine solche Adresse". Wenn der Prozessor eine nicht zugeordnete Adresse dereferenziert, führt dies zu einem Trap: Der Prozessor verzweigt zu einer vordefinierten Position im Kernelcode. Einige Fallen sind legitim; Beispielsweise könnte die virtuelle Adresse einer Seite entsprechen, die sich im Swap-Bereich befindet. In diesem Fall lädt der Kernel-Code den Seiteninhalt aus dem Swap und wechselt dann wieder zum ursprünglichen Programm, sodass die Speicherzugriffsanweisung erneut ausgeführt wird. Andere Traps sind nicht legitim. In diesem Fall empfängt der Prozess ein Signal, das das Programm standardmäßig sofort beendet (und wenn nicht, zum Signalhandler im Programm verzweigt: In jedem Fall ist der Speicherzugriffsbefehl nicht abgeschlossen).
quelle