From: Sean Christopherson <seanjc@google.com>
To: Gavin Shan <gshan@redhat.com>
Cc: kvmarm@lists.linux.dev, kvmarm@lists.cs.columbia.edu,
kvm@vger.kernel.org, maz@kernel.org, shuah@kernel.org,
catalin.marinas@arm.com, andrew.jones@linux.dev,
ajones@ventanamicro.com, bgardon@google.com, dmatlack@google.com,
will@kernel.org, suzuki.poulose@arm.com,
alexandru.elisei@arm.com, pbonzini@redhat.com, peterx@redhat.com,
oliver.upton@linux.dev, zhenyzha@redhat.com,
shan.gavin@gmail.com
Subject: Re: [PATCH v10 3/7] KVM: Support dirty ring in conjunction with bitmap
Date: Thu, 10 Nov 2022 16:46:22 +0000 [thread overview]
Message-ID: <Y20q3lq5oc2gAqr+@google.com> (raw)
In-Reply-To: <20221110104914.31280-4-gshan@redhat.com>
On Thu, Nov 10, 2022, Gavin Shan wrote:
> @@ -3305,7 +3305,10 @@ void mark_page_dirty_in_slot(struct kvm *kvm,
> struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
>
> #ifdef CONFIG_HAVE_KVM_DIRTY_RING
> - if (WARN_ON_ONCE(!vcpu) || WARN_ON_ONCE(vcpu->kvm != kvm))
> + if (WARN_ON_ONCE(vcpu && vcpu->kvm != kvm))
> + return;
> +
> + if (WARN_ON_ONCE(!kvm_arch_allow_write_without_running_vcpu(kvm) && !vcpu))
Nit, the !vcpu check should come first. 99.9% of the time @vcpu will be non-NULL,
in which case the call to kvm_arch_allow_write_without_running_vcpu() can be
avoided. And checking for !vcpu should also be cheaper than said call.
Since the below code is gaining a check on "vcpu" when using the dirty ring, and
needs to gain a check on memslot->dirty_bitmap, I think it makes sense to let KVM
continue on instead of bailing. I.e. fill the dirty bitmap if possible instead
of dropping the dirty info and potentiall corrupting guest memory.
The "vcpu->kvm != kvm" check is different; if that fails, KVM would potentially
log the dirty page into the wrong VM's context, which could be fatal to one or
both VMs.
If it's not too late to rewrite history, this could even be done as a prep patch,
e.g. with a changelog explaning that KVM should try to log to the dirty bitmap
even if KVM has a bug where a write to guest memory was triggered without a running
vCPU.
---
virt/kvm/kvm_main.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 43bbe4fde078..b1115bbd6038 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -3313,18 +3313,20 @@ void mark_page_dirty_in_slot(struct kvm *kvm,
struct kvm_vcpu *vcpu = kvm_get_running_vcpu();
#ifdef CONFIG_HAVE_KVM_DIRTY_RING
- if (WARN_ON_ONCE(!vcpu) || WARN_ON_ONCE(vcpu->kvm != kvm))
+ if (WARN_ON_ONCE(vcpu && vcpu->kvm != kvm))
return;
+
+ WARN_ON_ONCE(!vcpu);
#endif
if (memslot && kvm_slot_dirty_track_enabled(memslot)) {
unsigned long rel_gfn = gfn - memslot->base_gfn;
u32 slot = (memslot->as_id << 16) | memslot->id;
- if (kvm->dirty_ring_size)
+ if (kvm->dirty_ring_size && vcpu)
kvm_dirty_ring_push(&vcpu->dirty_ring,
slot, rel_gfn);
- else
+ else if (memslot->dirty_bitmap)
set_bit_le(rel_gfn, memslot->dirty_bitmap);
}
}
base-commit: 01b4689ee519329ce5f50ae02692e8acdaba0beb
--
> return;
> #endif
>
> @@ -3313,7 +3316,7 @@ void mark_page_dirty_in_slot(struct kvm *kvm,
> unsigned long rel_gfn = gfn - memslot->base_gfn;
> u32 slot = (memslot->as_id << 16) | memslot->id;
>
> - if (kvm->dirty_ring_size)
> + if (kvm->dirty_ring_size && vcpu)
> kvm_dirty_ring_push(vcpu, slot, rel_gfn);
> else
> set_bit_le(rel_gfn, memslot->dirty_bitmap);
Not checking memslot->dirty_bitmap will allow a malicious userspace to induce a
NULL pointer dereference, e.g. enable dirty ring without the bitmap and save the
ITS tables. The KVM_DEV_ARM_ITS_SAVE_TABLES path in patch 4 doesn't check that
kvm_use_dirty_bitmap() is true.
If requiring kvm_use_dirty_bitmap() to do KVM_DEV_ARM_ITS_SAVE_TABLES is deemed
to prescriptive, the best this code can do is:
if (kvm->dirty_ring_size && vcpu)
kvm_dirty_ring_push(&vcpu->dirty_ring,
slot, rel_gfn);
else if (memslot->dirty_bitmap)
set_bit_le(rel_gfn, memslot->dirty_bitmap);
If ARM rejects KVM_DEV_ARM_ITS_SAVE_TABLES, then this can be:
if (kvm->dirty_ring_size && vcpu)
kvm_dirty_ring_push(&vcpu->dirty_ring,
slot, rel_gfn);
else if (!WARN_ON_ONCE(!memslot->dirty_bitmap))
set_bit_le(rel_gfn, memslot->dirty_bitmap);
next prev parent reply other threads:[~2022-11-10 16:48 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-11-10 10:49 [PATCH v10 0/7] KVM: arm64: Enable ring-based dirty memory tracking Gavin Shan
2022-11-10 10:49 ` [PATCH v10 1/7] KVM: x86: Introduce KVM_REQ_DIRTY_RING_SOFT_FULL Gavin Shan
2022-11-10 10:49 ` [PATCH v10 2/7] KVM: Move declaration of kvm_cpu_dirty_log_size() to kvm_dirty_ring.h Gavin Shan
2022-11-10 10:49 ` [PATCH v10 3/7] KVM: Support dirty ring in conjunction with bitmap Gavin Shan
2022-11-10 16:46 ` Sean Christopherson [this message]
2022-11-10 23:47 ` Gavin Shan
2022-11-11 15:19 ` Marc Zyngier
2022-11-11 22:19 ` Gavin Shan
2022-11-11 23:00 ` Sean Christopherson
2022-11-11 23:43 ` Gavin Shan
2022-11-12 0:18 ` Sean Christopherson
2022-11-12 9:50 ` Gavin Shan
2022-11-11 23:02 ` Marc Zyngier
2022-11-10 10:49 ` [PATCH v10 4/7] KVM: arm64: Enable ring-based dirty memory tracking Gavin Shan
2023-01-15 11:20 ` Zenghui Yu
2023-01-15 11:56 ` Gavin Shan
2023-01-15 23:55 ` Gavin Shan
2023-01-16 4:09 ` Gavin Shan
2023-01-16 4:54 ` Zenghui Yu
2023-01-16 4:51 ` Zenghui Yu
2022-11-10 10:49 ` [PATCH v10 5/7] KVM: selftests: Use host page size to map ring buffer in dirty_log_test Gavin Shan
2022-11-10 10:49 ` [PATCH v10 6/7] KVM: selftests: Clear dirty ring states between two modes " Gavin Shan
2022-11-10 10:49 ` [PATCH v10 7/7] KVM: selftests: Automate choosing dirty ring size " Gavin Shan
2022-11-10 13:21 ` [PATCH v10 0/7] KVM: arm64: Enable ring-based dirty memory tracking Marc Zyngier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Y20q3lq5oc2gAqr+@google.com \
--to=seanjc@google.com \
--cc=ajones@ventanamicro.com \
--cc=alexandru.elisei@arm.com \
--cc=andrew.jones@linux.dev \
--cc=bgardon@google.com \
--cc=catalin.marinas@arm.com \
--cc=dmatlack@google.com \
--cc=gshan@redhat.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=kvmarm@lists.linux.dev \
--cc=maz@kernel.org \
--cc=oliver.upton@linux.dev \
--cc=pbonzini@redhat.com \
--cc=peterx@redhat.com \
--cc=shan.gavin@gmail.com \
--cc=shuah@kernel.org \
--cc=suzuki.poulose@arm.com \
--cc=will@kernel.org \
--cc=zhenyzha@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox