Eine Schwäche in der Kernel Virtual Machine (KVM) macht es möglich, Gast-Betriebssysteme zum Absturz zu bringen.
Anwendungen kommunizieren mit dem Linux-Kernel durch Syscalls. Unter Linux wird ein Systemcall auf Assembler-Ebene typischerweise über einen Software-Interrupt mit Nummer 0x80 ausgelöst, wobei die Nummer des Syscalls im EAX-Register abgelegt wird. Weitere Parameter werden ebenfalls in Registern abgelegt. Daneben bieten Intel- und AMD-Prozessoren auch die Möglichkeit, den Syscall-Befehl zu verwenden (Opcode 0F 05), um ohne den Overhead eines Interrupts die Kontrolle an das Betriebssystem zu übergeben.
Laut offizieller Intel-Dokumentation ist dieser Opcode auf 32-Bit-Systemen jedoch nicht implementiert. Genau dies wird aber von KVM nicht richtig erkannt.
Das Problem lässt sich sehr leicht demonstrieren, indem man via “nasm” ein kleines Assembler-Programm bastelt (“crash_guest.asm”):
[bits 32] global _start SECTION .text _start: syscall
Die Kommandos “nasm -felf crash_guest.asm” und “ld -o crash_guest.o crash_guest.asm” liefern die ausführbare Datei “crash_guest”. Wer diese in einem 32-Bit KVM-Gast-System startet, bringt das Gast-System zum Absturz.
Das Patch für diese Schwachstelle besteht darin, den Syscall-Opcode im KVM-Quelltext korrekt abzufangen. Hierzu muss man die Funktion “em_syscall()” etwas erweitern, und zwar in dem Teil, der prüft, in welchem Modus das System läuft:
/* syscall is not available in real mode */ + /* + "0f05" is also not available in + all non-64-bit protected modes (16& + 32bit) or virtual 8086 mode + Only 64bit longmode supports this opcode + */ if (ctxt->mode == X86EMUL_MODE_REAL || + ctxt->mode == X86EMUL_MODE_PROT16 || + ctxt->mode == X86EMUL_MODE_PROT32 || ctxt->mode == X86EMUL_MODE_VM86) return emulate_ud(ctxt);
In all diesen Fällen wird die Funktion “emulate_ud()” aufgerufen, die wiederum “emulate_exception()” aufruft. Mit dieser kleinen Korrektur tritt kein Absturz beim Ausführen des oben dargestellten Codes mehr ein.

