race condition in hw/input/pckbd.c causes wrong data to be read on interrupts
I was tempted to chalk this up to a bug in my own guest code, but after reproducing it under a Linux guest in multiple builds of QEMU, as well as a cursory review of the relevant source, I have reached the unfortunate conclusion that this is a bug in QEMU that has been around for some time: A race condition in hw/input/pckbd.c
allows for the pending status of the mouse or keyboard buffers to change between an interrupt being fired and the data being read from the PS/2 controller, causing the wrong data to be provided to a guest attempting to read from the data port during the respective interrupt. I have examined a wide range of real hardware with remnant PC PS/2 controllers as well as other virtual machines and none of have demonstrated the behavior that QEMU is producing in these circumstances.
This situation can be reliably reproduced with clear user-visible effects in a guest OS which does not support the vmmouse
: Simply move the mouse while simultaneously typing and the mouse jumps wildly across the screen while also clicking randomly as the guest driver becomes out of sync and produces invalid packets from the garbage data. Further, if the guest OS uses scancode translation or directly enables the legacy scancode set for the keyboard, the issue can be seen to affect both devices: With vmmouse
support, 0x08
is regularly read from the buffer on a keyboard interrupt, yielding a 7
key press; without vmmouse
support, the data in the buffer erroneously read by the keyboard interrupt is far more interesting, causing a variety of keys to be pressed.
Guests using the "standard" scancode set 2 in combination with the vmmouse
suffer no ill effects - the guest's vmmouse
driver will receive data directly from the vmport
and the data erroneously received by the guest keyboard driver will occasionally contain 0x08
from the fake mouse packet, which is a no-op for that scan code set.
This issue has been reproduced successfully in multiple versions, including 4.2-3ubuntu6.16
shipped with Ubuntu 20.04 LTS and a build of 6.0.0
from source. Several guest OSes were used to demonstrate the problem, including a live CD ISO of Ubuntu 20.04, which exhibited the issue under the GTK and VNC display frontends but was unable to reproduce the problem with the SDL frontend. The SDL frontend did exhibit the issue under other guests. The issue was considerably less apparent under TCG in the Ubuntu guest, but was still present in others.
When testing with the Ubuntu guest, the following arguments were used:
qemu-system-x86_64 -cdrom ~/Downloads/ubuntu-20.04.2.0-desktop-amd64.iso -machine vmport=off -enable-kvm -m 3G -display gtk
A guest OS exhibiting the issue with the SDL frontend was run as follows:
qemu-system-x86_64 -cdrom ~/Downloads/sortix-1.1dev-x86_64.iso -m 3G -enable-kvm -sdl