Programmierer-Diskussion zu NX Bit Artikel

PuckPoltergeist

Grand Admiral Special
Mitglied seit
18.01.2002
Beiträge
16.734
Renomée
145
Standort
Ilmenau
Original geschrieben von rkinet
Bei IA32 nutzen die Viren aus, daß der Stack von Betriebssystemroutinen an gewissen Positionen oder wohl nach gewissen Codesequenzen zu finden ist.
Per Buffer Overflow wird der abnormal ausgeweitet und die Pseudo-Rücksprungadresse zum Virus wird von der CPU ausgeführt.

Das würde zu einem segmentation fault führen, weil das Programm in anderen denn seinen eigenen Speicherbereichen rumschreiben würde. Sowas geht schon schief, wenn man im Speicher einer anderen user-task rumpfuscht, wenn man in den Speicher des OS schreibt, wird das jeweilige Programm erst recht gnadenlos abgeschossen. Das berührt aber das OS und alle anderen Programme nicht.
 
Jep, genau.

Selbst wenn ein Task es unter absolut glücklichen Bedingungen schaffen würde den OS Stack in seinem 4GB Segment sichtbar zu machen, es würde schief gehen. Die entsprechende Page wäre dann nämlich per U/S auf Superuser gesetzt (weil zum OS gehörig) und das Programm hätte nicht das Recht auf diese Page zuzugreifen.
 
Original geschrieben von intel_hasser
Jep, genau.

Selbst wenn ein Task es unter absolut glücklichen Bedingungen schaffen würde den OS Stack in seinem 4GB Segment sichtbar zu machen,

Der müßte eigentlich immer sichtbar sein, halt nur nicht zugreifbar. Das OS liegt ja im oberen/den oberen 2GB eines jeden Prozesses.
 
So einfach ist es auch nicht, dann dürfte nämlich ein Programm den Code vom OS nicht ausführen, ergo wäre es sinnlos das OS in die oberen 2GB zu mappen.

Für sowas gibts noch Gates (ähnlich Segmenten), aber das wird dann doch zu kompliziert. In wie weit das praktisch benutzt wird oder ob es nicht doch noch einen anderen Weg gibt weis ich auch nicht, um Code in einem Segment niedriger DPL ausführen zu können bedarf es jedenfalls eines Gates.

Bei Pages gibt es sowas wie Gates nicht. Möglich, dass das OS einen Aufruf auf eine SuperUser Page per Exception abfängt und wenn da eine aus Programmsicht aufrufbare Funktion steht wird die eben ausgeführt.


Aber selbst wenn ein Programm eben wüsste am Offset abc liegt der OS Stack, verändern kann es den nicht. Nichtmal auslesen geht.
 
Original geschrieben von intel_hasser
So einfach ist es auch nicht, dann dürfte nämlich ein Programm den Code vom OS nicht ausführen, ergo wäre es sinnlos das OS in die oberen 2GB zu mappen.

Für sowas gibts noch Gates (ähnlich Segmenten), aber das wird dann doch zu kompliziert. In wie weit das praktisch benutzt wird oder ob es nicht doch noch einen anderen Weg gibt weis ich auch nicht, um Code in einem Segment niedriger DPL ausführen zu können bedarf es jedenfalls eines Gates.

Bei Pages gibt es sowas wie Gates nicht. Möglich, dass das OS einen Aufruf auf eine SuperUser Page per Exception abfängt und wenn da eine aus Programmsicht aufrufbare Funktion steht wird die eben ausgeführt.

Die Trennung ist heute so. Jeder Prozess hat auf 32bit-Maschinen einen 4GB Adressraum, der meist 2/2 oder 1/3 geteilt ist. Im oberen Bereich liegt das OS, welches die Task ja ab und an in Anspruch nehmen muß. Per Systemruf kann die Task dann in den priveligierten Modus wechseln, und führt dann Code im Kernel-Modus aus (z.B. Dateizugriffe). Wenn das nicht so wäre, sprich das OS nicht in den Adressraum der Task eingeblendet werden würde, hätte man bei jedem syscall einen Adressraumwechsel, welcher sehr teuer ist.


Aber selbst wenn ein Programm eben wüsste am Offset abc liegt der OS Stack, verändern kann es den nicht. Nichtmal auslesen geht.

Wie oben geschrieben, direkt geht es nicht. Via syscall kommt aber jede task in diesen Speicherbereich (kontrolliert).
 
Original geschrieben von PuckPoltergeist
Die Trennung ist heute so. Jeder Prozess hat auf 32bit-Maschinen einen 4GB Adressraum, der meist 2/2 oder 1/3 geteilt ist. Im oberen Bereich liegt das OS, welches die Task ja ab und an in Anspruch nehmen muß. Per Systemruf kann die Task dann in den priveligierten Modus wechseln, und führt dann Code im Kernel-Modus aus (z.B. Dateizugriffe). Wenn das nicht so wäre, sprich das OS nicht in den Adressraum der Task eingeblendet werden würde, hätte man bei jedem syscall einen Adressraumwechsel, welcher sehr teuer ist.

Nein. Also doch, klar - aber das Problem liegt woanders. Per entsprechenden Aufruf kann jedes Programm OS Routinen aufrufen, aber nun überleg mal - die Routine um eine OS Routine aufzurufen gehört zum OS oder zum Programm.

Gehört sie zum OS darf das Programm diese Routine garnicht aufrufen, weil die Routine dann entweder ein einer Superuser Page und/oder in einem Segment mit DPL 0 liegt (das Programm dagegen in einer Userpage mit DPL 3).

Gehört die Routine zum Programm, liegt also in einem DPL3 Segment und in einer Userpage darf diese Routine auch bloß keine OS Funktion aufrufen.



Verstehst du?


Dafür gibts bei Segmenten sog. Gates. Damit kann man einen Bereich definieren, in dem Programme mit hoher DPL Code in einer niedrigen DPL ausführen können. Also angenommen ich hab Segment 32 als Gate definiert und springe Code in diesem Segment aus einem DPL 3 Programm an ist das gültig und der Code wird dann mit DPL 0 oder so ausgeführt (kann ich als Betriebssystem vorher festlegen).

Das dumme an der Sache ist aber, dass das Gate schon über die gesamten 4GB gehen müsste - dann könnte das Programm sich selbst aber auch als DPL 0 ausführen (es gibt noch eine andere Bezeichnung, das DPL unter dem ein Programm gerade läuft wird afair CPL genannt - Current Privilege Level). Also das Programm selbst könnte sich dann auch mit einem CPL von 0 ausführen und dann nach belieben die Page Table ändern, neue Segmente definieren etc.

Also muss man das irgendwie anders realisieren. Am besten über Pages - wie genau das da geht weis ich aber auch net.
 
Original geschrieben von intel_hasser
Also muss man das irgendwie anders realisieren. Am besten über Pages - wie genau das da geht weis ich aber auch net.

Ich spreche die ganze Zeit vom paging, segmentation wird ja praktisch nicht mehr genutzt. Der syscall gehört zum OS, und wird von der task aufgerufen. Damit wechselt die task in den kernel-mode. Logisch gesehen läuft die task, es ist aber Kernel-Code, der ausgeführt wird. Das ging nicht so einfach, wenn das OS sich nicht im selben Adressraum wie das Programm befinden würde.

PS: Ganz ohne segmentation geht es auf IA32 noch nicht. Der Kernel hat z.B. eigene Segmente.
 
Original geschrieben von PuckPoltergeist
Ich spreche die ganze Zeit vom paging, segmentation wird ja praktisch nicht mehr genutzt. Der syscall gehört zum OS, und wird von der task aufgerufen. Damit wechselt die task in den kernel-mode. Logisch gesehen läuft die task, es ist aber Kernel-Code, der ausgeführt wird. Das ging nicht so einfach, wenn das OS sich nicht im selben Adressraum wie das Programm befinden würde.

PS: Ganz ohne segmentation geht es auf IA32 noch nicht. Der Kernel hat z.B. eigene Segmente.

Du hast es immernoch nicht verstanden.

Angenommen ein Programm will etwas Speicher vom OS - normalerweise passiert das per malloc() oder etwas in der Art. Involviert ist da aber der gesamte Speichermanager vom OS.

Also Programm(User) -> malloc(User) -> OS Routine(Superuser) -> Speichermanager vom OS(Superuser)

Das dumme an der Sache ist aber, dass etwas in einer User-Page keinen Code in einer Superuser-Page ausführen kann.

Also das Programm kann auf Teufel komm raus dem OS nicht sagen, dass es Speicher will weil selbiges in einer Superuser Page liegt! Überhaupt kann das Programm nie Code in einer Superuser Page ausführen, der Speichermanager liegt aber definitiv in einer Superuser Page.

Da kannst du nicht allgemein mit Paging oder Segmentierung rangehen, weil das Problem nunmal x86 speziefisch ist. Und wenn du Segmentierung und Paging von x86 nicht genau kennst kannst du dazu keine Aussage machen.


Bei Segmenten würde man das wie beschrieben über ein Gate lösen. Also das OS bietet dem Programm ein Gate an in dem die OS Funktionen liegen. Das Programm (CPL 3) führt den Code im Gate aus (-> CPL 0) und der Code im Gate (der zum OS gehört) kann machen was er will (ich bin root, ich darf alles - CPL 0 eben).
Der CPL 0 Code kann auch auf Superuser Pages zugreifen, weil man das mit CPL 0 nunmal darf.

Bei Pages sieht es aber anders aus. Da gibt es keine 'Gates'. Und da ein Programm immer mit CPL 3 ausgeführt wird kann das nicht einfach so auf Superuser Pages zugreifen, geschweige denn ohne Gate in den CPL 0 wechseln.

Man kann aber auch nicht einfach ein Gate über den gesamten linearen Adressraum definieren, weil sich ein Programm dann selbst dann im CPL 0 ausführen könnte und mit dem OS machen könnte was es wollte.

Wenn man ein Gate aber nur über die OS Routinen legt kann man die nicht mehr so ohne weiteres ausführen, weil dann die Offsets nicht mehr stimmen.


Eine Möglichkeit wäre wenn das Programm trotzdem auf die Superuser Page zugreift - das gibt eine Exception, der Exception Handler (der zum OS gehört) wird aufgerufen und ändert wenn er gute Laune hat (das Programm den entsprechenden Code in der Superuser Page rein rechtlich ausführen darf) entsprechend das TSS vom Programm - voila.

Das wäre aber andererseits ziemlich langsam.


@Mods

Das Thema hat jetzt nix mehr mit dem Artikel zu tun, wäre nett, wenn das jemand in einen anderen Thread schieben könnte :).
 
Zuletzt bearbeitet:
Zurück
Oben Unten