KVM: Absturz durch unprivilegierte Benutzer

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.

Nach oben