Skip to contentSkip to conversation

x86: VMX: Check EPT AD bits when enabled in ept_access_paddr()

PATCH Applied Oliver Upton 2 participants 2 messages Nov 28, 2019 – Jan 21, 2020 KVM

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 x86: VMX: Check EPT AD bits when enabled in ept_access_paddr()

Modify the test helper, ept_access_paddr(), to test the correctness of the L1's EPT AD bits when enabled. After a successful guest access, assert that the accessed bit (bit 8) has been set on all EPT entries which were used in the translation of the guest-physical address.

Since ept_access_paddr() tests an EPT mapping that backs a guest paging structure, processor accesses are treated as writes and the dirty bit (bit 9) is set accordingly. Assert that the dirty bit is set on the leaf EPT entry.

---
 x86/vmx_tests.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
x86/vmx_tests.c +18 -0
index a456bd1..325dde7 100644
@@ -1135,6 +1135,11 @@ static void ept_disable_ad_bits(void)
 	vmcs_write(EPTP, eptp);
 }
 
+static int ept_ad_enabled(void)
+{
+	return eptp & EPTP_AD_FLAG;
+}
+
 static void ept_enable_ad_bits_or_skip_test(void)
 {
 	if (!ept_ad_bits_supported())
@@ -2500,6 +2505,8 @@ static void ept_access_paddr(unsigned long ept_access, unsigned long pte_ad,
 	unsigned long *ptep;
 	unsigned long gpa;
 	unsigned long orig_epte;
+	unsigned long epte;
+	int i;
 
 	/* Modify the guest PTE mapping data->gva according to @pte_ad.  */
 	ptep = get_pte_level(current_page_table(), data->gva, /*level=*/1);
@@ -2536,6 +2543,17 @@ static void ept_access_paddr(unsigned long ept_access, unsigned long pte_ad,
 		do_ept_access_op(op);
 	} else {
 		do_ept_access_op(op);
+		if (ept_ad_enabled()) {
+			for (i = EPT_PAGE_LEVEL; i > 0; i--) {
+				TEST_ASSERT(get_ept_pte(pml4, gpa, i, &epte));
+				TEST_ASSERT(epte & EPT_ACCESS_FLAG);
+				if (i == 1)
+					TEST_ASSERT(epte & EPT_DIRTY_FLAG);
+				else
+					TEST_ASSERT_EQ(epte & EPT_DIRTY_FLAG, 0);
+			}
+		}
+
 		ept_untwiddle(gpa, /*level=*/1, orig_epte);
 	}
 
Signature · 1 line
2.24.0.432.g9d3f5f5b63-goog
maintainer Applied
#1 lore raw
Quoted 49 lines · Oliver Upton

Modify the test helper, ept_access_paddr(), to test the correctness of the L1's EPT AD bits when enabled. After a successful guest access, assert that the accessed bit (bit 8) has been set on all EPT entries which were used in the translation of the guest-physical address.

Since ept_access_paddr() tests an EPT mapping that backs a guest paging structure, processor accesses are treated as writes and the dirty bit (bit 9) is set accordingly. Assert that the dirty bit is set on the leaf EPT entry.

---
 x86/vmx_tests.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
x86/vmx_tests.c +11 -0
index a456bd1..325dde7 100644
@@ -1135,6 +1135,11 @@ static void ept_disable_ad_bits(void)
 	vmcs_write(EPTP, eptp);
 }
 
+static int ept_ad_enabled(void)
+{
+	return eptp & EPTP_AD_FLAG;
+}
+
 static void ept_enable_ad_bits_or_skip_test(void)
 {
 	if (!ept_ad_bits_supported())
@@ -2500,6 +2505,8 @@ static void ept_access_paddr(unsigned long ept_access, unsigned long pte_ad,
 	unsigned long *ptep;
 	unsigned long gpa;
 	unsigned long orig_epte;
+	unsigned long epte;
+	int i;
 
 	/* Modify the guest PTE mapping data->gva according to @pte_ad.  */
 	ptep = get_pte_level(current_page_table(), data->gva, /*level=*/1);
@@ -2536,6 +2543,17 @@ static void ept_access_paddr(unsigned long ept_access, unsigned long pte_ad,
 		do_ept_access_op(op);
 	} else {
 		do_ept_access_op(op);
+		if (ept_ad_enabled()) {
+			for (i = EPT_PAGE_LEVEL; i > 0; i--) {
+				TEST_ASSERT(get_ept_pte(pml4, gpa, i, &epte));
+				TEST_ASSERT(epte & EPT_ACCESS_FLAG);

x86/vmx_tests.c static void ept_access_paddr(unsigned long ept_access, unsigned long pte_ad, · line 2559

Quoted 10 lines
x86/vmx_tests.c +7 -0
+				if (i == 1)
+					TEST_ASSERT(epte & EPT_DIRTY_FLAG);
+				else
+					TEST_ASSERT_EQ(epte & EPT_DIRTY_FLAG, 0);
+			}
+		}
+
 		ept_untwiddle(gpa, /*level=*/1, orig_epte);
 	}
 

Queued, thanks.

Paolo