diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2022-06-15 11:05:06 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2022-06-24 12:53:37 -0400 |
commit | 35ab3b77a0ae76246dd2666d4f8190c824392fb4 (patch) | |
tree | 6f17260e675b1f6c80ee64fa7358293c6c071e6c | |
parent | 0f87ac234d98c68e4b2bfde6a8bcdeef3d3f54b7 (diff) | |
download | lwn-35ab3b77a0ae76246dd2666d4f8190c824392fb4.tar.gz lwn-35ab3b77a0ae76246dd2666d4f8190c824392fb4.zip |
KVM: x86: drop PIO from unregistered devices
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>
-rw-r--r-- | arch/x86/kvm/x86.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 524a96d26399..5a56d39bd81f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -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; } |