[SRU][Trusty][Xenial][PATCH] UBUNTU: SAUCE: x86/speculation: Fix the IBRS synchronization

Gavin Guo gavin.guo at canonical.com
Thu Nov 22 14:09:32 UTC 2018


BugLink: https://launchpad.net/bugs/1764956

Ubuntu v4.4 kernel uses the in-house patches for IBRS. The backports
still have some issues causing the IBRS status wrong when
context-switching between the VM and host. For example, the IBRS would
be mistakenly enabled in the host when the switching from an IBRS-enabled
VM and that causes the performance overhead in the host. The other
condition could also mistakenly disables the IBRS in VM when
context-switching from the host. And this could be considered a CVE host.

The detail different situations analysis:

The reproducing environment:
Guest kernel version: 4.4.0-138.164
Host kernel version: 4.4.0-140.166

(host IBRS, guest IBRS)

- 1). (0, 1).
The case can be reproduced by the following instructions:
guest$ echo 1 | sudo tee /proc/sys/kernel/ibrs_enabled
1

<Several minutes later...>

host$ cat /proc/sys/kernel/ibrs_enabled
0
host$ for i in {0..55}; do sudo rdmsr 0x48 -p $i; done
11111111111111000000000000000000010010100000000000000000

Some of the IBRS bit inside the SPEC_CTRL MSR are mistakenly
enabled.

host$ taskset -c 5 stress-ng -c 1 --cpu-ops 2500
stress-ng: info:  [11264] defaulting to a 86400 second run per stressor
stress-ng: info:  [11264] dispatching hogs: 1 cpu
stress-ng: info:  [11264] cache allocate: default cache size: 35840K
stress-ng: info:  [11264] successful run completed in 33.48s

The host kernel didn't notice the IBRS bit is enabled. So, the situation
is the same as "echo 2 > /proc/sys/kernel/ibrs_enabled" in the host.
And running the stress-ng is a pure userspace CPU capability
calculation. So, the performance downgrades to about 1/3. Without the
IBRS enabled, it needs about 10s.

- 2). (1, 1) disables IBRS in host -> (0, 1) actually it becomes (0, 0).
The guest IBRS has been mistakenly disabled.

guest$ echo 2 | sudo tee /proc/sys/kernel/ibrs_enabled
guest$ for i in {0..55}; do sudo rdmsr 0x48 -p $i; done
11111111111111111111111111111111111111111111111111111111

host$ echo 2 | sudo tee /proc/sys/kernel/ibrs_enabled
host$ for i in {0..55}; do sudo rdmsr 0x48 -p $i; done
11111111111111111111111111111111111111111111111111111111
host$ echo 0 | sudo tee /proc/sys/kernel/ibrs_enabled
host$ for i in {0..55}; do sudo rdmsr 0x48 -p $i; done
00000000000000000000000000000000000000000000000000000000

guest$ for i in {0..55}; do sudo rdmsr 0x48 -p $i; done
00000000000000000000000000000000000000000000000000000000

Fixes: 4d8d3dbed275 ("UBUNTU: SAUCE: x86/bugs, KVM: Support the combination ...")
Fixes: f676aa34b402 ("x86/kvm: add MSR_IA32_SPEC_CTRL and MSR_IA32_PRED_CMD ...")
Signed-off-by: Gavin Guo <gavin.guo at canonical.com>
---
 arch/x86/kernel/cpu/bugs.c |  7 +++++++
 arch/x86/kvm/vmx.c         | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index 86d08522a721..09c328275c2b 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -185,6 +185,13 @@ x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest)
 		guestval = hostval & ~x86_spec_ctrl_mask;
 		guestval |= guest_spec_ctrl & x86_spec_ctrl_mask;
 
+		/*
+		 * Check the host IBRS status to make IBRS regsiter update
+		 * correctly.
+		 */
+		if (ibrs_enabled)
+			hostval |= SPEC_CTRL_IBRS;
+
 		/* SSBD controlled in MSR_SPEC_CTRL */
 		if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD))
 			hostval |= ssbd_tif_to_spec_ctrl(ti->flags);
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 22012bcc4ef6..b1e3f64f4aee 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1840,6 +1840,32 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
 	vmcs_write32(EXCEPTION_BITMAP, eb);
 }
 
+/*
+ * Check if MSR is intercepted for currently loaded MSR bitmap.
+ */
+static bool msr_write_intercepted(struct kvm_vcpu *vcpu, u32 msr)
+{
+	/*
+	 * The longmode_only = "false" for MSR_IA32_SPEC_CTRL MSR register in
+	 * hardware_setup function. So, the vmx_msr_bitmap_legacy bitmap is
+	 * used. Refer to vmx_disable_intercept_for_msr function for the detail.
+	 */
+	unsigned long *msr_bitmap = vmx_msr_bitmap_legacy;
+	int f = sizeof(unsigned long);
+
+	if (!cpu_has_vmx_msr_bitmap())
+		return true;
+
+	if (msr <= 0x1fff) {
+		return !!test_bit(msr, msr_bitmap + 0x800 / f);
+	} else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) {
+		msr &= 0x1fff;
+		return !!test_bit(msr, msr_bitmap + 0xc00 / f);
+	}
+
+	return true;
+}
+
 static void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx,
 		unsigned long entry, unsigned long exit)
 {
@@ -9011,6 +9037,17 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 #endif
 	      );
 
+	/*
+	 * In Ubuntu v4.4, the MSR_IA32_SPEC_CTRL trap is disabled in
+	 * hardware_setup function. The guest SPEC_CTRL register needs to be
+	 * saved to make the status correct. Refer to "commit f676aa34b402
+	 * x86/kvm: add MSR_IA32_SPEC_CTRL and MSR_IA32_PRED_CMD to kvm" The
+	 * related upstream commit is "commit 28b387fb74d KVM/VMX: Allow direct
+	 * access to MSR_IA32_SPEC_CTRL"
+	 */
+	if (!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))
+		vcpu->arch.spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL);
+
 	x86_spec_ctrl_restore_host(vcpu->arch.spec_ctrl, 0);
 
 	/* Eliminate branch target predictions from guest mode */
-- 
2.7.4




More information about the kernel-team mailing list