KVM: x86: drop PIO from unregistered devices
authorPaolo Bonzini <pbonzini@redhat.com>
Wed, 15 Jun 2022 15:05:06 +0000 (11:05 -0400)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 24 Jun 2022 16:53:37 +0000 (12:53 -0400)
KVM protects the device list with SRCU, and therefore different calls
to kvm_io_bus_read()/kvm_io_bus_write() can very well see different
incarnations of kvm->buses.  If userspace unregisters a device while
vCPUs are running there is no well-defined result.  This patch applies
a safe fallback by returning early from emulator_pio_in_out().  This
corresponds to returning zeroes from IN, and dropping the writes on
the floor for OUT.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/x86.c

index 524a96d..5a56d39 100644 (file)
@@ -7593,8 +7593,19 @@ static int emulator_pio_in_out(struct kvm_vcpu *vcpu, int size,
                        r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, port, size, data);
                else
                        r = kvm_io_bus_write(vcpu, KVM_PIO_BUS, port, size, data);
-               if (r)
-                       goto userspace_io;
+
+               if (r) {
+                       if (i == 0)
+                               goto userspace_io;
+
+                       /*
+                        * Userspace must have unregistered the device while PIO
+                        * was running.  Drop writes / read as 0 (the buffer
+                        * was zeroed in __emulator_pio_in).
+                        */
+                       break;
+               }
+
                data += size;
        }
        return 1;
@@ -7606,7 +7617,6 @@ userspace_io:
        vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
        vcpu->run->io.count = count;
        vcpu->run->io.port = port;
-
        return 0;
 }