Re: Meltdown - VMs sicher nach Hypervisor-patch?

From: Oliver Fromme <oliver(at)fromme.com>
Date: Wed, 10 Jan 2018 14:11:50 +0100 (CET)

Hallo Peter,

Peter Ross wrote:
> Ganz grob gedacht und gefragt: Wenn der Hypervisor in Sachen Hardware (und
> sicher auch CPU-Caching) das letzte Wort hat, kann Meltdown noch innerhalb
> der VM ausgenutzt werden?

Meltdown nicht – aber Spectre.

Grob gesagt: Der Meltdown-Bug (CVE-2017-5754) erlaubt es einem
Angreifer, die Trennung zwischen den Ringen [1] zu überwinden.
So kann ein normaler Benutzerprozess (Ring 3) auf den Adressraum
des Kernels oder des Hypervisors zugreifen. Vom Meltdown-Bug
sind alle (neueren) Intel-CPUs betroffen sowie einige (wenige)
ARM-Versionen, nicht aber AMD oder andere. Der Bug lässt sich
durch Work-arounds im Betriebssystem fixen, die aber einen gewissen
Performanceverlust bedeuten. Außerdem hat Intel angekündigt,
Microcode-Updates für betroffene Prozessoren herauszubringen,
die im Zusammenspiel mit (weiteren) Betriebssystem-Patches den
Performanceverlust wieder ausgleichen sollen.

[1] https://de.wikipedia.org/wiki/Ring_%28CPU%29/x86-Prozessor-Systeme

Das Spectre-Problem dagegen erlaubt das Überwinden von Zugriffs-
beschränkungen des eigenen Adressraums (Variante 1, CVE-2017-5753)
und der Trennung des Adressraums zwischen verschiedenen Prozessen
oder VMs (Variante 2, CVE-2017-5715). Das bedeutet, dass ein
Angreifer den Speicher „benachbarter“ Prozesse bzw. VMs auslesen
kann. Spectre missbraucht ein grundlegendes Problem bestimmter
Prozessor-Optimierungen (Out-of-order Execution und Speculative
Execution), daher betrifft es alle Prozessoren, die diese Features
besitzen: Intel, AMD, ARM, MIPS, Sparc, ... Dieses Problem zu
beheben, ist daher auch um einiges schwieriger. Für Variante 2
gibt es zumindest inzwischen einen vorläufigen Patch für den
Compiler LLVM:

http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20180101/513630.html

Den aktuellen Stand bei FreeBSD findet man hier:

https://lists.freebsd.org/pipermail/freebsd-security/2018-January/009719.html

Falls es jemanden interessiert, wie so ein Spectre-Angriff in
einem Programm grundsätzlich funktioniert:

1. Der Angreifer liest ein Byte an einer bestimmten Adresse aus,
   zu der er eigentlich keine Zugriffsberechtigung hat. Der
   Zugriff wird daher fehlschlagen, d.h. zu einem Memory-Fault
   führen.

2. Da ein Speicherzugriff immer etwas länger dauert, wartet der
   Prozessor das Ergebnis nicht ab, sondern führt bereits die
   nachfolgenden Anweisungen „spekulativ“ aus, bevor der Memory-
   Fault ausgelöst wird.

3. Die folgende Anweisung maskiert ein Bit des (vermeintlich)
   gelesenen Bytes heraus und greift in Abhängigkeit davon auf
   zwei verschiedene Adressen (nennen wir sie A0 und A1) zu, d.h.
   wenn das Bit 0 ist, wird auf A0 zugegriffen, und wenn es 1
   ist, wird auf A1 zugegriffen. Wo A0 und A1 liegen, spielt
   keine Rolle, sie sollten nur in unterschiedlichen Cache-Lines
   liegen. Ihr Inhalt ist auch egal und interessiert nicht.

4. Der Memory-Fault, der nun irgendwann zuschlägt, führt dazu,
   dass der Prozessor das Byte aus Schritt 1. natürlich nicht
   herausrückt, und die spekulativ ausgeführten Schritte (3.),
   die auf dem Inhalt dieses Bytes basieren, werden auch wieder
   verworfen.

5. Das Programm muss natürlich dafür sorgen, dass es trotzdem
   weiterläuft, z.B. durch einen Trap-Handler (SIGSEGV), oder
   es lässt den Thread/Prozess einfach sterben und setzt den
   Ablauf in einem Schwester-Prozess fort.

6. Obwohl der Prozessor die spekulativen Schritte verworfen hat,
   haben sie einen Seiteneffekt: Der Inhalt von A0 *oder* A1
   wurde in den Cache geholt und befindet sich noch dort.

7. Das Programm muss jetzt also nur einen kleinen Timing-Test
   machen, indem es misst, wie lange ein Zugriff auf A0 und A1
   dauert. Je nachdem, welches der beiden schneller ist, weiß
   das Programm, welche Adresse bereits vorher in den Cache
   geladen wurde, und somit, welchen Wert das fragliche Bit
   hatte.

8. Obige Schritte können beliebig oft wiederholt werden, um die
   Bits (und somit Bytes) zu erhalten, die einen interessieren,
   und auf die man eigentlich keine Zugriffsberechtigung hat.
   Das klingt jetzt nach eine Riesenaufwand für jedes einzelne
   Bit, aber in der Praxis (mit dem PoC-Code) kann man auf einer
   halbwegs schnellen CPU mehrere hundert KByte/s lesen, was
   für typische Angriffsszenarien völlig ausreichend ist.

Gruß
   Olli

-- 
Oliver Fromme, München   --   FreeBSD + DragonFly BSD
``We are all but compressed light'' - Albert Einstein
To Unsubscribe: send mail to majordomo(at)de.FreeBSD.org
with "unsubscribe de-bsd-questions" in the body of the message
Received on Wed 10 Jan 2018 - 14:11:58 CET

search this site