Skip to content

Commit 03c0304

Browse files
dwmw2bonzini
authored andcommitted
KVM: Warn if mark_page_dirty() is called without an active vCPU
The various kvm_write_guest() and mark_page_dirty() functions must only ever be called in the context of an active vCPU, because if dirty ring tracking is enabled it may simply oops when kvm_get_running_vcpu() returns NULL for the vcpu and then kvm_dirty_ring_get() dereferences it. This oops was reported by "butt3rflyh4ck" <[email protected]> in https://lore.kernel.org/kvm/CAFcO6XOmoS7EacN_n6v4Txk7xL7iqRa2gABg3F7E3Naf5uG94g@mail.gmail.com/ That actual bug will be fixed under separate cover but this warning should help to prevent new ones from being added. Signed-off-by: David Woodhouse <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 05a0ff3 commit 03c0304

File tree

3 files changed

+6
-16
lines changed

3 files changed

+6
-16
lines changed

include/linux/kvm_dirty_ring.h

-6
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,6 @@ static inline int kvm_dirty_ring_alloc(struct kvm_dirty_ring *ring,
4343
return 0;
4444
}
4545

46-
static inline struct kvm_dirty_ring *kvm_dirty_ring_get(struct kvm *kvm)
47-
{
48-
return NULL;
49-
}
50-
5146
static inline int kvm_dirty_ring_reset(struct kvm *kvm,
5247
struct kvm_dirty_ring *ring)
5348
{
@@ -78,7 +73,6 @@ static inline bool kvm_dirty_ring_soft_full(struct kvm_dirty_ring *ring)
7873

7974
u32 kvm_dirty_ring_get_rsvd_entries(void);
8075
int kvm_dirty_ring_alloc(struct kvm_dirty_ring *ring, int index, u32 size);
81-
struct kvm_dirty_ring *kvm_dirty_ring_get(struct kvm *kvm);
8276

8377
/*
8478
* called with kvm->slots_lock held, returns the number of

virt/kvm/dirty_ring.c

-9
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,6 @@ static bool kvm_dirty_ring_full(struct kvm_dirty_ring *ring)
3636
return kvm_dirty_ring_used(ring) >= ring->size;
3737
}
3838

39-
struct kvm_dirty_ring *kvm_dirty_ring_get(struct kvm *kvm)
40-
{
41-
struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
42-
43-
WARN_ON_ONCE(vcpu->kvm != kvm);
44-
45-
return &vcpu->dirty_ring;
46-
}
47-
4839
static void kvm_reset_dirty_gfn(struct kvm *kvm, u32 slot, u64 offset, u64 mask)
4940
{
5041
struct kvm_memory_slot *memslot;

virt/kvm/kvm_main.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -3152,12 +3152,17 @@ void mark_page_dirty_in_slot(struct kvm *kvm,
31523152
const struct kvm_memory_slot *memslot,
31533153
gfn_t gfn)
31543154
{
3155+
struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
3156+
3157+
if (WARN_ON_ONCE(!vcpu) || WARN_ON_ONCE(vcpu->kvm != kvm))
3158+
return;
3159+
31553160
if (memslot && kvm_slot_dirty_track_enabled(memslot)) {
31563161
unsigned long rel_gfn = gfn - memslot->base_gfn;
31573162
u32 slot = (memslot->as_id << 16) | memslot->id;
31583163

31593164
if (kvm->dirty_ring_size)
3160-
kvm_dirty_ring_push(kvm_dirty_ring_get(kvm),
3165+
kvm_dirty_ring_push(&vcpu->dirty_ring,
31613166
slot, rel_gfn);
31623167
else
31633168
set_bit_le(rel_gfn, memslot->dirty_bitmap);

0 commit comments

Comments
 (0)