accel/kvm/kvm-all.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
Legacy PCI INTx interrupts are level triggered and can, in theory, be shared.
Upon receiving such an interrupt, VFIO kernel driver masks it in a generic way,
using INTX_DISABLE bit in the PCI config space.
It then waits for the guest to signal completion (EOI) of the interrupt,
upon which VFIO re-enables the interrupt.
The completion is signaled with another eventfd.
For split irqchip mode, KVM doesn't have a notion of EOI on IOAPIC level.
Instead it signals EOI with a userspace VM exit, KVM_EXIT_IOAPIC_EOI.
Upon receiving this VM exit, Qemu manually signals the above-mentioned eventfd.
The problem that this patch resolves is that QEMU keeps these eventfds in
a linked list without any locking to prevent the list from being corrupted by
concurrent access.
Such use is possible and guest triggerable if the guest rapidly toggles
INTX mode of a VFIO device and at the same time signals EOI with an arbitrary
vector.
Fix this by protecting this list (kvm_resample_fd_list) with a mutex.
This patch was only compile tested.
Reported-by: "Vulnerability Report" <vr@darknavy.com>
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3942
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
---
accel/kvm/kvm-all.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 83cbd120a847..da3afdc68d8d 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -146,6 +146,7 @@ typedef struct KVMResampleFd KVMResampleFd;
static QLIST_HEAD(, KVMResampleFd) kvm_resample_fd_list =
QLIST_HEAD_INITIALIZER(kvm_resample_fd_list);
+static QemuMutex kvm_resample_fd_list_lock;
static QemuMutex kml_slots_lock;
#define kvm_slots_lock() qemu_mutex_lock(&kml_slots_lock)
@@ -157,6 +158,8 @@ static inline void kvm_resample_fd_remove(int gsi)
{
KVMResampleFd *rfd;
+ qemu_mutex_lock(&kvm_resample_fd_list_lock);
+
QLIST_FOREACH(rfd, &kvm_resample_fd_list, node) {
if (rfd->gsi == gsi) {
QLIST_REMOVE(rfd, node);
@@ -164,6 +167,8 @@ static inline void kvm_resample_fd_remove(int gsi)
break;
}
}
+
+ qemu_mutex_unlock(&kvm_resample_fd_list_lock);
}
static inline void kvm_resample_fd_insert(int gsi, EventNotifier *event)
@@ -173,20 +178,26 @@ static inline void kvm_resample_fd_insert(int gsi, EventNotifier *event)
rfd->gsi = gsi;
rfd->resample_event = event;
+ qemu_mutex_lock(&kvm_resample_fd_list_lock);
QLIST_INSERT_HEAD(&kvm_resample_fd_list, rfd, node);
+ qemu_mutex_unlock(&kvm_resample_fd_list_lock);
}
void kvm_resample_fd_notify(int gsi)
{
KVMResampleFd *rfd;
+ qemu_mutex_lock(&kvm_resample_fd_list_lock);
+
QLIST_FOREACH(rfd, &kvm_resample_fd_list, node) {
if (rfd->gsi == gsi) {
event_notifier_set(rfd->resample_event);
trace_kvm_resample_fd_notify(gsi);
- return;
+ break;
}
}
+
+ qemu_mutex_unlock(&kvm_resample_fd_list_lock);
}
/**
@@ -2910,6 +2921,7 @@ static int kvm_init(AccelState *as, MachineState *ms)
int type;
qemu_mutex_init(&kml_slots_lock);
+ qemu_mutex_init(&kvm_resample_fd_list_lock);
/*
* On systems where the kernel can support different base page
--
2.54.0
Queued, thanks. Paolo
© 2016 - 2026 Red Hat, Inc.