[kvm-unit-tests PATCH 2/2] Test VM-entry in MOVSS shadow

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



VM-entry is disallowed in the shadow of a MOV-to-SS instruction. When
the current-VMCS is valid, check that the instruction pointer falls
through to the next instruction, the ALU flags are set to ZF
(VMfailValid), and the VM-instruction error field contains 26 ("VM
entry with events blocked by MOV SS.").

Signed-off-by: Jim Mattson <jmattson@xxxxxxxxxx>
---
 lib/x86/processor.h | 16 +++++----
 x86/unittests.cfg   |  6 ++++
 x86/vmx_tests.c     | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 111 insertions(+), 7 deletions(-)

diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index 895d992a6943..631aa843b65e 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -30,13 +30,15 @@
 #define X86_CR4_SMAP   0x00200000
 #define X86_CR4_PKE    0x00400000
 
-#define X86_EFLAGS_CF  0x00000001
-#define X86_EFLAGS_PF  0x00000004
-#define X86_EFLAGS_AF  0x00000010
-#define X86_EFLAGS_ZF  0x00000040
-#define X86_EFLAGS_SF  0x00000080
-#define X86_EFLAGS_OF  0x00000800
-#define X86_EFLAGS_AC  0x00040000
+#define X86_EFLAGS_CF    0x00000001
+#define X86_EFLAGS_FIXED 0x00000002
+#define X86_EFLAGS_PF    0x00000004
+#define X86_EFLAGS_AF    0x00000010
+#define X86_EFLAGS_ZF    0x00000040
+#define X86_EFLAGS_SF    0x00000080
+#define X86_EFLAGS_IF    0x00000200
+#define X86_EFLAGS_OF    0x00000800
+#define X86_EFLAGS_AC    0x00040000
 
 #define X86_IA32_EFER          0xc0000080
 #define X86_EFER_LMA           (1UL << 8)
diff --git a/x86/unittests.cfg b/x86/unittests.cfg
index 5ab46671d631..c5b35e7eee3e 100644
--- a/x86/unittests.cfg
+++ b/x86/unittests.cfg
@@ -494,6 +494,12 @@ extra_params = -cpu host,+vmx -m 2048 -append ept_access_test_force_2m_page
 arch = x86_64
 groups = vmx
 
+[vmx_vmentry_movss_shadow_test]
+file = vmx.flat
+extra_params = -cpu host,+vmx -m 2048 -append vmentry_movss_shadow_test
+arch = x86_64
+groups = vmx
+
 [debug]
 file = debug.flat
 arch = x86_64
diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index 03e4ad43eba3..68ce0e09531a 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -2916,6 +2916,101 @@ static void ept_access_test_force_2m_page(void)
 	ept_misconfig_at_level_mkhuge(true, 2, EPT_PRESENT, EPT_WA);
 }
 
+static bool valid_vmcs_for_vmentry(void)
+{
+	struct vmcs *current_vmcs = NULL;
+
+	if (vmcs_save(&current_vmcs))
+		return false;
+
+	return current_vmcs && !(current_vmcs->revision_id >> 31);
+}
+
+static void try_vmentry_in_movss_shadow(void)
+{
+	u32 vm_inst_err;
+	u32 flags;
+	bool early_failure = false;
+	u32 expected_flags = X86_EFLAGS_FIXED;
+	bool valid_vmcs = valid_vmcs_for_vmentry();
+
+	expected_flags |= valid_vmcs ? X86_EFLAGS_ZF : X86_EFLAGS_CF;
+
+	/*
+	 * Indirectly set VM_INST_ERR to 12 ("VMREAD/VMWRITE from/to
+	 * unsupported VMCS component").
+	 */
+	vmcs_write(~0u, 0);
+
+	__asm__ __volatile__ ("mov %[host_rsp], %%edx;"
+			      "vmwrite %%rsp, %%rdx;"
+			      "mov 0f, %%rax;"
+			      "mov %[host_rip], %%edx;"
+			      "vmwrite %%rax, %%rdx;"
+			      "mov $-1, %%ah;"
+			      "sahf;"
+			      "mov %%ss, %%ax;"
+			      "mov %%ax, %%ss;"
+			      "vmlaunch;"
+			      "mov $1, %[early_failure];"
+			      "0: lahf;"
+			      "movzbl %%ah, %[flags]"
+			      : [early_failure] "+r" (early_failure),
+				[flags] "=&a" (flags)
+			      : [host_rsp] "i" (HOST_RSP),
+				[host_rip] "i" (HOST_RIP)
+			      : "rdx", "cc", "memory");
+	vm_inst_err = vmcs_read(VMX_INST_ERROR);
+
+	report("Early VM-entry failure", early_failure);
+	report("RFLAGS[8:0] is %x (actual %x)", flags == expected_flags,
+	       expected_flags, flags);
+	if (valid_vmcs)
+		report("VM-instruction error is %d (actual %d)",
+		       vm_inst_err == VMXERR_ENTRY_EVENTS_BLOCKED_BY_MOV_SS,
+		       VMXERR_ENTRY_EVENTS_BLOCKED_BY_MOV_SS, vm_inst_err);
+}
+
+static void vmentry_movss_shadow_test(void)
+{
+	struct vmcs *orig_vmcs;
+
+	TEST_ASSERT(!vmcs_save(&orig_vmcs));
+
+	/*
+	 * Set the launched flag on the current VMCS to verify the correct
+	 * error priority, below.
+	 */
+	test_set_guest(v2_null_test_guest);
+	enter_guest();
+
+	/*
+	 * With bit 1 of the guest's RFLAGS clear, VM-entry should
+	 * fail due to invalid guest state (if we make it that far).
+	 */
+	vmcs_write(GUEST_RFLAGS, 0);
+
+	/*
+	 * "VM entry with events blocked by MOV SS" takes precedence over
+	 * "VMLAUNCH with non-clear VMCS."
+	 */
+	report_prefix_push("valid current-VMCS");
+	try_vmentry_in_movss_shadow();
+	report_prefix_pop();
+
+	/*
+	 * VMfailInvalid takes precedence over "VM entry with events
+	 * blocked by MOV SS."
+	 */
+	TEST_ASSERT(!vmcs_clear(orig_vmcs));
+	report_prefix_push("no current-VMCS");
+	try_vmentry_in_movss_shadow();
+	report_prefix_pop();
+
+	TEST_ASSERT(!make_vmcs_current(orig_vmcs));
+	vmcs_write(GUEST_RFLAGS, X86_EFLAGS_FIXED);
+}
+
 #define TEST(name) { #name, .v2 = name }
 
 /* name/init/guest_main/exit_handler/syscall_handler/guest_regs */
@@ -2977,5 +3072,6 @@ struct vmx_test vmx_tests[] = {
 	TEST(ept_access_test_paddr_read_execute_ad_enabled),
 	TEST(ept_access_test_paddr_not_present_page_fault),
 	TEST(ept_access_test_force_2m_page),
+	TEST(vmentry_movss_shadow_test),
 	{ NULL, NULL, NULL, NULL, NULL, {0} },
 };
-- 
2.13.2.932.g7449e964c-goog




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux