Kernel KVM virtualization development
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: kvm@vger.kernel.org, Sean Christopherson <seanjc@google.com>
Subject: [kvm-unit-tests PATCH] x86/emulator: Add testcases for ENTER + emulated MMIO
Date: Thu, 14 May 2026 14:15:10 -0700	[thread overview]
Message-ID: <20260514211510.1630673-1-seanjc@google.com> (raw)

Add testcases for stack pushes to emulated MMIO via the ENTER instruction
to validate a pile of KVM changes needed to fix a use-after-free due to
KVM referencing kernel stack data across a userspace exit.  Test that ENTER
is handled correctly if it splits non-MMIO => MMIO, MMIO => non-MMIO, and
MMIO => MMIO pages.

Opportunistically add a comment explaining what the collection of pages
are used for in the emulator test.

Link: https://lore.kernel.org/all/20260225012049.920665-1-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 x86/emulator.c   | 66 ++++++++++++++++++++++++++++--------------------
 x86/emulator64.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 102 insertions(+), 28 deletions(-)

diff --git a/x86/emulator.c b/x86/emulator.c
index 102e5efc..6d945d8a 100644
--- a/x86/emulator.c
+++ b/x86/emulator.c
@@ -790,8 +790,7 @@ static void test_mov_pop_ss_code_db(void)
 
 int main(void)
 {
-	void *mem;
-	void *cross_mem;
+	void *base, *mmio, *split;
 
 	if (!is_fep_available)
 		report_skip("Skipping tests that require forced emulation, "
@@ -799,45 +798,56 @@ int main(void)
 
 	setup_vm();
 
-	mem = alloc_vpages(2);
-	install_page((void *)read_cr3(), IORAM_BASE_PHYS, mem);
-	// install the page twice to test cross-page mmio
-	install_page((void *)read_cr3(), IORAM_BASE_PHYS, mem + 4096);
-	cross_mem = vmap(virt_to_phys(alloc_pages(2)), 2 * PAGE_SIZE);
+	/*
+	 * Allocate five pages in the virtual address space, with pages, 0, 3,
+	 * and 4 pointing at normal memory, and pages 1 and 2 pointing at an
+	 * emulated MMIO range.  This combination of pages allows testing basic
+	 * emulated MMIO handling, as well as a variety of multi-page and page-
+	 * split scenarios.
+	 */
+	base = alloc_vpages(5);
+	install_page((void *)read_cr3(), virt_to_phys(alloc_pages(1)), base);
+	install_page((void *)read_cr3(), IORAM_BASE_PHYS, base + PAGE_SIZE);
+	install_page((void *)read_cr3(), IORAM_BASE_PHYS, base + 2 * PAGE_SIZE);
+	install_page((void *)read_cr3(), virt_to_phys(alloc_pages(1)), base + 3 * PAGE_SIZE);
+	install_page((void *)read_cr3(), virt_to_phys(alloc_pages(1)), base + 4 * PAGE_SIZE);
 
-	test_mov(mem);
-	test_simplealu(mem);
-	test_cmps(mem);
-	test_scas(mem);
-	test_smsw(mem);
+	mmio = base + PAGE_SIZE;
+	split = base + 3 * PAGE_SIZE;
+
+	test_mov(mmio);
+	test_simplealu(mmio);
+	test_cmps(mmio);
+	test_scas(mmio);
+	test_smsw(mmio);
 	test_lmsw();
 	test_stringio();
-	test_incdecnotneg(mem);
-	test_btc(mem);
-	test_bsfbsr(mem);
-	test_imul(mem);
-	test_sse(mem);
-	test_sse_exceptions(cross_mem);
-	test_shld_shrd(mem);
-	//test_lgdt_lidt(mem);
-	//test_lldt(mem);
-	test_ltr(mem);
+	test_incdecnotneg(mmio);
+	test_btc(mmio);
+	test_bsfbsr(mmio);
+	test_imul(mmio);
+	test_sse(mmio);
+	test_sse_exceptions(split);
+	test_shld_shrd(mmio);
+	//test_lgdt_lidt(mmio);
+	//test_lldt(mmio);
+	test_ltr(mmio);
 
 	if (is_fep_available) {
-		test_smsw_reg(mem);
-		test_nop(mem);
-		test_mov_dr(mem);
+		test_smsw_reg(mmio);
+		test_nop(mmio);
+		test_mov_dr(mmio);
 		test_illegal_lea();
 	}
 
-	test_crosspage_mmio(mem);
+	test_crosspage_mmio(mmio);
 
-	test_string_io_mmio(mem);
+	test_string_io_mmio(mmio);
 	test_illegal_movbe();
 	test_mov_pop_ss_code_db();
 
 #ifdef __x86_64__
-	test_emulator_64(mem);
+	test_emulator_64(mmio);
 #endif
 	return report_summary();
 }
diff --git a/x86/emulator64.c b/x86/emulator64.c
index 6a85122f..c4df5178 100644
--- a/x86/emulator64.c
+++ b/x86/emulator64.c
@@ -116,6 +116,70 @@ static void test_pop(void *mem)
 	       && rbp == (unsigned long)stack_top - 8
 	       && stack_top[-1] == 0xaa55aa55bb66bb66ULL,
 	       "enter");
+
+	stack_top = mem + 8192 + 4;
+	stack_top[-1] = -1ull;
+	rbp = 0x1122334455667788ULL;
+	rsp = (unsigned long)stack_top;
+	asm volatile("mov %[rsp], %%r8 \n\t"
+		     "mov %[rbp], %%r9 \n\t"
+		     "xchg %%rsp, %%r8 \n\t"
+		     "xchg %%rbp, %%r9 \n\t"
+		     "enter $0x1234, $0 \n\t"
+		     "xchg %%rsp, %%r8 \n\t"
+		     "xchg %%rbp, %%r9 \n\t"
+		     "xchg %%r8, %[rsp] \n\t"
+		     "xchg %%r9, %[rbp]"
+		     : [rsp]"+a"(rsp), [rbp]"+b"(rbp) : : "memory", "r8", "r9");
+
+	report(rsp == (unsigned long)stack_top - 8 - 0x1234 &&
+	       rbp == (unsigned long)stack_top - 8 &&
+	       stack_top[-1] == 0x1122334455667788ULL,
+	       "enter");
+
+	stack_top = mem + 4096 + 4;
+	stack_top[-1] = -1ull;
+	rbp = 0x1122334455667788ULL;
+	rsp = (unsigned long)stack_top;
+	asm volatile("mov %[rsp], %%r8 \n\t"
+		     "mov %[rbp], %%r9 \n\t"
+		     "xchg %%rsp, %%r8 \n\t"
+		     "xchg %%rbp, %%r9 \n\t"
+		     "enter $0x1234, $0 \n\t"
+		     "xchg %%rsp, %%r8 \n\t"
+		     "xchg %%rbp, %%r9 \n\t"
+		     "xchg %%r8, %[rsp] \n\t"
+		     "xchg %%r9, %[rbp]"
+		     : [rsp]"+a"(rsp), [rbp]"+b"(rbp) : : "memory", "r8", "r9");
+
+	report(rsp == (unsigned long)stack_top - 8 - 0x1234,
+	       "ENTER RSP = %lx, wanted %lx", rsp, (unsigned long)stack_top - 8 - 0x1234);
+	report(rbp == (unsigned long)stack_top - 8,
+	       "ENTER RSP = %lx, wanted %lx", rbp, (unsigned long)stack_top - 8);
+	report(stack_top[-1] == 0x1122334455667788ULL,
+	       "ENTER val = %lx, wanted 0x1122334455667788", stack_top[-1]);
+
+	stack_top = mem + 4;
+	stack_top[-1] = -1ull;
+	rbp = 0x8877665544332211ULL;
+	rsp = (unsigned long)stack_top;
+	asm volatile("mov %[rsp], %%r8 \n\t"
+		     "mov %[rbp], %%r9 \n\t"
+		     "xchg %%rsp, %%r8 \n\t"
+		     "xchg %%rbp, %%r9 \n\t"
+		     "enter $0x1234, $0 \n\t"
+		     "xchg %%rsp, %%r8 \n\t"
+		     "xchg %%rbp, %%r9 \n\t"
+		     "xchg %%r8, %[rsp] \n\t"
+		     "xchg %%r9, %[rbp]"
+		     : [rsp]"+a"(rsp), [rbp]"+b"(rbp) : : "memory", "r8", "r9");
+
+	report(rsp == (unsigned long)stack_top - 8 - 0x1234,
+	       "ENTER RSP = %lx, wanted %lx", rsp, (unsigned long)stack_top - 8 - 0x1234);
+	report(rbp == (unsigned long)stack_top - 8,
+	       "ENTER RSP = %lx, wanted %lx", rbp, (unsigned long)stack_top - 8);
+	report(stack_top[-1] == 0x8877665544332211ULL,
+	       "ENTER val = %lx, wanted 0x8877665544332211", stack_top[-1]);
 }
 
 static void test_ljmp(void *mem)

base-commit: 9eb6c57313060d34f7e5b2ac6f90bb5873bbe2ff
-- 
2.54.0.563.g4f69b47b94-goog


                 reply	other threads:[~2026-05-14 21:15 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=20260514211510.1630673-1-seanjc@google.com \
    --to=seanjc@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=pbonzini@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