lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251110232642.633672-14-yosry.ahmed@linux.dev>
Date: Mon, 10 Nov 2025 23:26:41 +0000
From: Yosry Ahmed <yosry.ahmed@...ux.dev>
To: Sean Christopherson <seanjc@...gle.com>
Cc: Paolo Bonzini <pbonzini@...hat.com>,
	Kevin Cheng <chengkev@...gle.com>,
	kvm@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	Yosry Ahmed <yosry.ahmed@...ux.dev>
Subject: [PATCH v3 13/14] x86/svm: Add more LBRV test cases

Add tests exercising using LBR, disabling it, then running a guest which
enables and uses LBR but does not disable it.

Make sure that when LBRV is disabled by virtual host, the guest state
correctly leaks into virtual host, but not when LBRV is enabled.  This
also exercises KVM disabling intercepts for LBRs in L2 but re-enabling
them when exiting to L1.

Signed-off-by: Yosry Ahmed <yosry.ahmed@...ux.dev>
---
 x86/svm_tests.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 33c92b17c87db..47a2edfbb6c9b 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -3031,11 +3031,14 @@ static __always_inline void get_lbr_ips(u64 *from, u64 *to)
 
 extern u64 guest_branch0_from, guest_branch0_to;
 extern u64 guest_branch2_from, guest_branch2_to;
+extern u64 guest_branch3_from, guest_branch3_to;
 
 extern u64 host_branch0_from, host_branch0_to;
 extern u64 host_branch2_from, host_branch2_to;
 extern u64 host_branch3_from, host_branch3_to;
 extern u64 host_branch4_from, host_branch4_to;
+extern u64 host_branch5_from, host_branch5_to;
+extern u64 host_branch6_from, host_branch6_to;
 
 u64 dbgctl;
 
@@ -3095,6 +3098,23 @@ static void svm_lbrv_test_guest2(void)
 	asm volatile ("vmmcall\n");
 }
 
+static void svm_lbrv_test_guest3(void)
+{
+	/*
+	 * This guest expects LBR to be disabled, it enables LBR and does a
+	 * branch, then exits to L1 without disabling LBR or doing more
+	 * branches.
+	 */
+	dbgctl = rdmsr(MSR_IA32_DEBUGCTLMSR);
+	TEST_EXPECT_EQ(dbgctl, 0);
+
+	wrmsr(MSR_IA32_DEBUGCTLMSR, DEBUGCTLMSR_LBR);
+	DO_BRANCH(guest_branch3);
+
+	/* Do not call the vmmcall() fn to avoid overriding the last branch */
+	asm volatile ("vmmcall\n\t");
+}
+
 static void svm_lbrv_test0(void)
 {
 	u64 from_ip, to_ip;
@@ -3156,6 +3176,33 @@ static void svm_lbrv_test2(void)
 	TEST_EXPECT_EQ((u64)&guest_branch2_to, to_ip);
 }
 
+/*
+ * Test that without LBRV enabled, enabling LBR in the guest then exiting will
+ * keep LBR enabled and 'leak' state to the host correctly.
+ */
+static void svm_lbrv_test3(void)
+{
+	u64 from_ip, to_ip;
+
+	svm_setup_vmrun((u64)svm_lbrv_test_guest3);
+	vmcb->control.virt_ext = 0;
+
+	wrmsr(MSR_IA32_DEBUGCTLMSR, DEBUGCTLMSR_LBR);
+	DO_BRANCH(host_branch5);
+	wrmsr(MSR_IA32_DEBUGCTLMSR, 0);
+
+	SVM_BARE_VMRUN;
+	dbgctl = rdmsr(MSR_IA32_DEBUGCTLMSR);
+	wrmsr(MSR_IA32_DEBUGCTLMSR, 0);
+	TEST_EXPECT_EQ(dbgctl, DEBUGCTLMSR_LBR);
+
+	TEST_EXPECT_EQ(vmcb->control.exit_code, SVM_EXIT_VMMCALL);
+
+	get_lbr_ips(&from_ip, &to_ip);
+	TEST_EXPECT_EQ((u64)&guest_branch3_from, from_ip);
+	TEST_EXPECT_EQ((u64)&guest_branch3_to, to_ip);
+}
+
 /* Test that with LBRV enabled, guest LBR state doesn't leak (1) */
 static void svm_lbrv_nested_test1(void)
 {
@@ -3217,6 +3264,37 @@ static void svm_lbrv_nested_test2(void)
 	TEST_EXPECT_EQ((u64)&host_branch4_to, to_ip);
 }
 
+/*
+ * Test that with LBRV enabled, enabling LBR in the guest then exiting does not
+ * 'leak' state to the host.
+ */
+static void svm_lbrv_nested_test3(void)
+{
+	u64 from_ip, to_ip;
+
+	if (!lbrv_supported()) {
+		report_skip("LBRV not supported in the guest");
+		return;
+	}
+
+	svm_setup_vmrun((u64)svm_lbrv_test_guest3);
+	vmcb->control.virt_ext = LBR_CTL_ENABLE_MASK;
+	vmcb->save.dbgctl = 0;
+
+	wrmsr(MSR_IA32_DEBUGCTLMSR, DEBUGCTLMSR_LBR);
+	DO_BRANCH(host_branch6);
+	wrmsr(MSR_IA32_DEBUGCTLMSR, 0);
+
+	SVM_BARE_VMRUN;
+	dbgctl = rdmsr(MSR_IA32_DEBUGCTLMSR);
+	TEST_EXPECT_EQ(dbgctl, 0);
+
+	TEST_EXPECT_EQ(vmcb->control.exit_code, SVM_EXIT_VMMCALL);
+
+	get_lbr_ips(&from_ip, &to_ip);
+	TEST_EXPECT_EQ((u64)&host_branch6_from, from_ip);
+	TEST_EXPECT_EQ((u64)&host_branch6_to, to_ip);
+}
 
 // test that a nested guest which does enable INTR interception
 // but doesn't enable virtual interrupt masking works
@@ -3622,8 +3700,10 @@ struct svm_test svm_tests[] = {
 	TEST(svm_lbrv_test0),
 	TEST(svm_lbrv_test1),
 	TEST(svm_lbrv_test2),
+	TEST(svm_lbrv_test3),
 	TEST(svm_lbrv_nested_test1),
 	TEST(svm_lbrv_nested_test2),
+	TEST(svm_lbrv_nested_test3),
 	TEST(svm_intr_intercept_mix_if),
 	TEST(svm_intr_intercept_mix_gif),
 	TEST(svm_intr_intercept_mix_gif2),
-- 
2.51.2.1041.gc1ab5b90ca-goog


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ