cimerp:5000_informationen_cimdata:0020_news_archiv:0150_2018:65
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| cimerp:5000_informationen_cimdata:0020_news_archiv:0150_2018:65 [29.03.2023 17:29:45] – angelegt - Externe Bearbeitung 127.0.0.1 | cimerp:5000_informationen_cimdata:0020_news_archiv:0150_2018:65 [30.03.2023 14:29:15] (aktuell) – [Was ist die Lösung für Spectre?] oesterle | ||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| + | ====== Sicherheitslücken Meltdown und Spectre ====== | ||
| + | |||
| + | Im Juni 2017 wurde Intel vom Google Project Zero, welches sich mit dem Finden von unbekannten Lücken in Computern beschäftigt, | ||
| + | |||
| + | Momentan werden sowohl von den Betriebssystemherstellern als auch von den Prozessorherstellern Intel, AMD und Nvidia Patches für diese Lücke gebaut, getestet und ausgeliefert. Diese Patches haben aber wahrscheinlich eine merkbare Reduzierung der Performance der Systeme zur Folge. Momentan pendelt sich der erwartete Verlust an Geschwindigkeit zwischen 1% und 5% ein. Dies kann man natürlich nie genau sagen, da es sehr davon abhängt, welche Art von Arbeit der Prozessor tatsächlich durchführt. | ||
| + | |||
| + | Für diejenigen, die technische Hintergründe im Detail interessieren, | ||
| + | |||
| + | ====== Sicherheitslücke Meltdown ====== | ||
| + | {{https:// | ||
| + | |||
| + | Dieser Angriff nutzt das Zusammenspiel von vier essentiellen Systemen in modernen Computern aus. Diese Systeme sind keine Programme, sondern wirklich in Silizium gegossene Hardware. Deshalb ist eine einfache Anpassung der Systeme sehr kompliziert! | ||
| + | |||
| + | ==== 1. Die Memory Management Unit (MMU) des Prozessors | ||
| + | |||
| + | Die MMU sorgt für eine Trennung zwischen sogenanntem virtuellen Arbeitsspeicher und pyhsikalischem Arbeitsspeicher. Der physikalische Arbeitsspeicher sind die RAM-Riegel, die Sie in Ihrem Computer eingebaut haben. Diese haben 4 GB, 8 GB, 16 GB und zusammen vielleicht 32 GB, weil es mehrere sein können. | ||
| + | |||
| + | Der virtuelle Arbeitsspeicher ist ein vorgetäuschter Arbeitsspeicher, | ||
| + | |||
| + | Was aber nun, wenn ein Programm erwartet, dass es alle möglichen Adressen, die mit 32Bit adressiert werden können, von 0x0000 0000 - 0xFFFF FFFF haben kann? Oder wenn mehrere Programme die Adresse 0x0000 1000 verwenden wollen? | ||
| + | |||
| + | Klar könnten wir jedem Programm vorher sagen "Du bekommst die Adressen von X bis Y." und erwarten, dass es sich daran hält. Dann haben wir aber noch keine Lösung gefunden zu verhindern, dass es trotzdem von anderen Adressen liest und somit andere Programme ausspioniert. Dies war früher tatsächlich normal. Zu Zeiten von MS-DOS konnte jedes Programm jederzeit jeden Speicher beschreiben. | ||
| + | |||
| + | Die Lösung für all diese Probleme ist nun die MMU. Die MMU ist eine Hardware-Einheit auf dem Prozessor, die nicht nur sehr schnell virtuelle Adressen in physikalische Adressen umwandeln kann, sondern sie kann die Adressen zudem auch noch mit Berechtigungen versehen. Bei Linux ist es nun zum Beispiel so, dass jeder Prozess mit den Adressen 0x0000 0000 - 0xBFFF FFFF tun und lassen kann was er will. Die Adressen 0xC000 0000 - 0xFFFF FFFF hat aber auch jeder Prozess. Diese gehören jedoch dem Betriebssystem (Linux Kernel) und sind trotzdem aus Geschwindigkeitsgründen von jedem Prozess aus zugreifbar. Das war vor Meltdown nie ein Problem, denn die MMU verwaltet die Berechtigungen auf die Speicheradressen des Kernels. Möchte also ein Prozess wissen, welches Passwort der aktuelle Benutzer hat (solche Sachen merkt sich der Kernel), so kann er einfach alle Adressen des Kernels durchsuchen bis er das Passwort gefunden hat. Er kommt hier aber nicht weit, denn beim ersten Zugriff auf eine Speicherseite, | ||
| + | |||
| + | ==== 2. Der Prozessor-Cache | ||
| + | |||
| + | Der physikalische Arbeitsspeicher ist zwar schon sehr schnell, man kann ihn aber noch schneller bauen - er wird dann nur deutlich teurer. Außerdem kann man ihn auch noch näher an den Prozessor bauen, denn auch die Lichtgeschwindigkeit, | ||
| + | |||
| + | ==== 3. Out of Order Execution | ||
| + | |||
| + | Im Gegensatz zu uns Menschen, die mit zwei Armen eher dürftig ausgestattet sind, hat ein Prozessor nicht nur viele Kerne, sondern auch in seinen Kernen viele Bauteile mehrfach verfügbar. Die Recheneinheit zum Beispiel, die Arithmetisch-logische Einheit (ALU), welche mathematische Berechnungen durchführt, | ||
| + | |||
| + | Wir nehmen folgenden Beispielprogrammcode: | ||
| + | |||
| + | 1. a = 5 + 1 | ||
| + | |||
| + | 2. b = a + 4 | ||
| + | |||
| + | 3. c = 10 | ||
| + | |||
| + | 4. d = a + 4 | ||
| + | |||
| + | So hat der Prozessor, auch wenn er momentan an Zeile 1 steht, keinerlei Probleme, die Zeile 3 schonmal gleichzeitig auszuführen. Sobald er an Zeile 2 steht, hat a auch einen festen Wert und Zeile 4 kann schon einmal berechnet werden. Prozessoren machen das dauerhaft und auch wenn der Programmierer denkt, es wird jeder Programmcode Zeile für Zeile abgearbeitet, | ||
| + | |||
| + | ==== 4. Branch Prediction Unit ==== | ||
| + | |||
| + | In jedem Programm gibt es Tausende und Abertausende von Entscheidungen. Der Prozessor muss ständig Entscheidungen abarbeiten, die sein können: "Wenn Eingabe größer 0, dann berechne den Wert." oder "Wenn der eingegebene Name länger als 10 Zeichen ist, dann springe zu einer Fehlermeldung." | ||
| + | |||
| + | Im Programmcode sieht das zum Beispiel so aus: | ||
| + | |||
| + | 1. x = Eingabe des Users | ||
| + | |||
| + | 2. Wenn x > 0 gehe zu 4. | ||
| + | |||
| + | 3. Fehlermeldung "x ist zu klein" | ||
| + | |||
| + | 4. Ergebnis = x + 10 | ||
| + | |||
| + | Hier kann der Prozessor in Zeile 2 entweder einfach mit Zeile 3 weitermachen, | ||
| + | |||
| + | Diese 4 Punkte beenden unseren Crashkurs über das Innenleben eines modernen Prozessors. Mit diesem Wissen können wir problemlos die Meltdown Attacke erklären: | ||
| + | |||
| + | Wie wir mittlerweile wissen, könnte es einen Prozess geben, der die virtuellen Adressen 0x0000 0000 - 0xB000 0000 belegt. In " | ||
| + | |||
| + | Nun machen wir Folgendes: | ||
| + | |||
| + | 1. Wir leeren den kompletten Prozessorcache. Dafür gibt es einen speziellen Befehl. | ||
| + | |||
| + | 2. Wir merken uns einen Speicherbereich, | ||
| + | |||
| + | 3. Wir lesen von der verbotenen Adresse 0xB000 0001. Das Ergebnis ist 0x15, welches wir uns merken. Dieser Schritt ist natürlich nicht erlaubt! Er wird vom Prozessor nicht ausgeführt werden, weil die MMU weiß, dass wir keine Leserechte auf diesen Speicherbereich haben. Außerdem wird das Programm hier abgebrochen werden. | ||
| + | |||
| + | 4. Wir addieren nun das Ergebnis vom Punkt 3 (0x15) zu unserer Adresse (0x1000) und schreiben dort einen beliebigen Wert hin. Auch eine 0 ist vollkommen ausreichend. | ||
| + | |||
| + | 5. Obwohl wir die Anweisung 3 nicht ausführen dürfen und wir deshalb sofort von der MMU gestoppt werden, hat die Out of Order Execution des Prozessors die Anweisungen 3 + 4 bereits vollständig ausgeführt. Der Knackpunkt hierbei ist, dass in Anweisung 4 an die Adresse 0x1015 tatsächlich eine 0 geschrieben wurde - und zwar von der Out of Order Execution Einheit des Prozessors. Der Prozessor sorgt zwar quasi im Nachhinein dafür, dass die 0 nicht wirklich an die Speicheradresse geschrieben wird, aber die Speicheradresse wurde aus Performancegründen trotzdem in den Cache geladen.\\ | ||
| + | \\ | ||
| + | 6. Ich kann nun Stück für Stück die Speicheradressen 0x1000 - 0x10FF auslesen und die Zeit messen, wie schnell das Ergebnis kommt. Bewegt sich die Zeit für den Zugriff zwischen 400 und 500 Prozessorzyklen, | ||
| + | |||
| + | ====== Was ist nun der Unterschied zwischen Spectre und Meltdown? ====== | ||
| + | {{https:// | ||
| + | |||
| + | Spectre trainiert die Branch Prediction Einheit, so dass immer ein Sprung genommen (oder nicht genommen) wird. Wenn dann das Gegenteil erfolgt, kann man sicher sein, dass die Out of Order Execution trotzdem den Programmcode ausführen wird, der bislang immer ausgeführt wurde. Auch hier kann ich somit Programmcode ausführen, den das Programm eigentlich nicht ausführen wollte. | ||
| + | |||
| + | Wenn in diesem Programmcode User Eingaben verarbeitet werden, die ich kontrollieren kann, kann ich hier schon eine ganze Menge geheime Daten aus dem Speicher des Programmes auslesen. Auch hier nutze ich das Messen der Zugriffszeit auf die Speicheradressen, | ||
| + | |||
| + | Das ganze Vorgehen bezeichnet man übrigens als Seitenkanal-Attacke. Das ist quasi so, als würde ich nicht durch die hoch gesicherte Eingangstür gehen, sondern das offen stehende Fenster daneben zum Einbruch nutzen! | ||
| + | |||
| + | ====== Patches der Sicherheitslücken ====== | ||
| + | |||
| + | ==== Was ist die Lösung für Meltdown? | ||
| + | |||
| + | Für Linux ist die erste Lösung der sogenannte KAISER Patch (kernel address isolation to have side-channels efficiently removed). Dieser macht nichts anderes, als für jeden Prozess die Adressen des Betriebssystems (0xC000 0000 - 0xFFFF FFFF) aus der MMU zu entfernen - und zwar jedesmal, wenn dieser Prozess ausgeführt wird. Das kann viele hundert Mal in der Sekunde sein. Dies kostet Performance und macht das System langsamer. | ||
| + | |||
| + | ==== Was ist die Lösung für Spectre? | ||
| + | |||
| + | Hier helfen nur Patches, die den Prozessor betreffen. Prozessoren werden teilweise auch mit sogenanntem Microcode programmiert. Diese Programmierung kann angepasst werden. | ||
| + | |||
| + | Eine kreative Lösung hat hier übrigens der Webbrowser Mozilla Firefox eingebaut - er macht einfach seine Zeitmessungen ungenauer. Damit kann man nicht mehr zwischen einem Zugriff vom Arbeitsspeicher oder Cache unterscheiden. Dass das aber keine dauerhafte Lösung ist, sollte klar sein! Was ist, wenn ich so kurze Zeiträume einmal messen muss? | ||
| + | |||
| + | Was wurde in dieser Erklärung vereinfacht? | ||
| + | |||
| + | Es wird normalerweise beim Testen und Speichern der Adressen nicht +1 gerechnet, sondern +4096, denn der Prozessor cacht nicht einzelne Bytes, sondern immer gleich ganze Seiten. Und eine Seite ist 4096 Bytes groß. Außerdem geht der Adressraum eines Prozessors heutzutage nicht mehr von 0x0000 0000 bis 0xFFFF FFFF (32 Bit), sondern ist auf modernen 64 Bit Betriebssystemen deutlich größer. | ||
| + | |||
| + | Quelle Meltdown: [[https:// | ||
| + | |||
| + | Quelle Spectre: [[https:// | ||
| + | |||
