From: Yan Zhao <yan.y.zhao@intel.com>
To: pbonzini@redhat.com, seanjc@google.com
Cc: rick.p.edgecombe@intel.com, linux-kernel@vger.kernel.org,
kvm@vger.kernel.org, Yan Zhao <yan.y.zhao@intel.com>
Subject: [PATCH] KVM: selftests: Wait mprotect_ro_done before write to RO in mmu_stress_test
Date: Sat, 8 Feb 2025 18:53:18 +0800 [thread overview]
Message-ID: <20250208105318.16861-1-yan.y.zhao@intel.com> (raw)
In the read-only mprotect() phase of mmu_stress_test, ensure that
mprotect(PROT_READ) has completed before the guest starts writing to the
read-only mprotect() memory.
Without waiting for mprotect_ro_done before the guest starts writing in
stage 3 (the stage for read-only mprotect()), the host's assertion of stage
3 could fail if mprotect_ro_done is set to true in the window between the
guest finishing writes to all GPAs and executing GUEST_SYNC(3).
This scenario is easy to occur especially when there are hundred of vCPUs.
CPU 0 CPU 1 guest CPU 1 host
enter stage 3's 1st loop
//in stage 3
write all GPAs
@rip 0x4025f0
mprotect(PROT_READ)
mprotect_ro_done=true
GUEST_SYNC(3)
r=0, continue stage 3's 1st loop
//in stage 4
write GPA
@rip 0x402635
-EFAULT, jump out stage 3's 1st loop
enter stage 3's 2nd loop
write GPA
@rip 0x402635
-EFAULT, continue stage 3's 2nd loop
guest rip += 3
The test then fails and reports "Unhandled exception '0xe' at guest RIP
'0x402638'", since the next valid guest rip address is 0x402639, i.e. the
"(mem) = val" in vcpu_arch_put_guest() is compiled into a mov instruction
of length 4.
Even if it could be compiled into a mov instruction of length 3, the
following execution of GUEST_SYNC(4) in guest could still cause the host
failure of the assertion of stage 3.
Signed-off-by: Yan Zhao <yan.y.zhao@intel.com>
---
tools/testing/selftests/kvm/mmu_stress_test.c | 25 +++++++++++--------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/tools/testing/selftests/kvm/mmu_stress_test.c b/tools/testing/selftests/kvm/mmu_stress_test.c
index d9c76b4c0d88..a2ccf705bb2a 100644
--- a/tools/testing/selftests/kvm/mmu_stress_test.c
+++ b/tools/testing/selftests/kvm/mmu_stress_test.c
@@ -35,11 +35,16 @@ static void guest_code(uint64_t start_gpa, uint64_t end_gpa, uint64_t stride)
GUEST_SYNC(2);
/*
- * Write to the region while mprotect(PROT_READ) is underway. Keep
- * looping until the memory is guaranteed to be read-only, otherwise
- * vCPUs may complete their writes and advance to the next stage
- * prematurely.
- *
+ * mprotect(PROT_READ) is underway. Keep looping until the memory is
+ * guaranteed to be read-only, otherwise vCPUs may complete their
+ * writes and advance to the next stage prematurely.
+ */
+ do {
+ ;
+ } while (!READ_ONCE(mprotect_ro_done));
+
+ /*
+ * Write to the region after mprotect(PROT_READ) is done.
* For architectures that support skipping the faulting instruction,
* generate the store via inline assembly to ensure the exact length
* of the instruction is known and stable (vcpu_arch_put_guest() on
@@ -47,16 +52,14 @@ static void guest_code(uint64_t start_gpa, uint64_t end_gpa, uint64_t stride)
* is low in this case). For x86, hand-code the exact opcode so that
* there is no room for variability in the generated instruction.
*/
- do {
- for (gpa = start_gpa; gpa < end_gpa; gpa += stride)
+ for (gpa = start_gpa; gpa < end_gpa; gpa += stride)
#ifdef __x86_64__
- asm volatile(".byte 0x48,0x89,0x00" :: "a"(gpa) : "memory"); /* mov %rax, (%rax) */
+ asm volatile(".byte 0x48,0x89,0x00" :: "a"(gpa) : "memory"); /* mov %rax, (%rax) */
#elif defined(__aarch64__)
- asm volatile("str %0, [%0]" :: "r" (gpa) : "memory");
+ asm volatile("str %0, [%0]" :: "r" (gpa) : "memory");
#else
- vcpu_arch_put_guest(*((volatile uint64_t *)gpa), gpa);
+ vcpu_arch_put_guest(*((volatile uint64_t *)gpa), gpa);
#endif
- } while (!READ_ONCE(mprotect_ro_done));
/*
* Only architectures that write the entire range can explicitly sync,
--
2.43.2
next reply other threads:[~2025-02-08 10:54 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-08 10:53 Yan Zhao [this message]
2025-02-11 1:03 ` Edgecombe, Rick P
2025-02-11 1:42 ` Yan Zhao
2025-02-11 18:29 ` Edgecombe, Rick P
2025-02-12 6:59 ` Yan Zhao
2025-02-26 1:53 ` Sean Christopherson
2025-02-26 2:07 ` Yan Zhao
2025-02-26 2:20 ` Sean Christopherson
2025-02-26 3:09 ` Yan Zhao
2025-02-26 1:48 ` Sean Christopherson
2025-02-26 3:08 ` Yan Zhao
2025-02-26 19:30 ` Sean Christopherson
2025-02-27 5:45 ` Yan Zhao
2025-02-27 22:18 ` Sean Christopherson
2025-02-28 10:55 ` Yan Zhao
2025-02-28 14:00 ` Sean Christopherson
2025-03-03 3:14 ` Yan Zhao
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=20250208105318.16861-1-yan.y.zhao@intel.com \
--to=yan.y.zhao@intel.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=rick.p.edgecombe@intel.com \
--cc=seanjc@google.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
all inboxes | Powered by JetHome®