untrusted comment: verify with openbsd-62-base.pub
RWRVWzAMgtyg7qzw4VveMn4sB0Z+53XXhwJYnwZ2dzrKOoof5cSuBSNLlyFQMd9HhYSXLxbMjtTJ/UQiTHX+F+6vAZDoTjfK9gc=
OpenBSD 6.2 errata 023, August 24, 2018:
The Intel L1TF bug allows a vmm guest to read host memory.
The 6.2 release lacked firmware updates, so a BIOS update is
required to receive the accelerated L1 cache solution.
Apply by doing:
signify -Vep /etc/signify/openbsd-62-base.pub -x 023_vmml1tf.patch.sig \
-m - | (cd /usr/src && patch -p0)
And then rebuild and install a new kernel:
KK=`sysctl -n kern.osversion | cut -d# -f1`
cd /usr/src/sys/arch/`machine`/compile/$KK
make obj
make config
make
make install
Index: sys/arch/amd64/amd64/identcpu.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/identcpu.c,v
retrieving revision 1.87.2.3
diff -u -p -r1.87.2.3 identcpu.c
--- sys/arch/amd64/amd64/identcpu.c 30 Jul 2018 14:44:23 -0000 1.87.2.3
+++ sys/arch/amd64/amd64/identcpu.c 21 Aug 2018 21:45:29 -0000
@@ -207,6 +207,7 @@ const struct {
}, cpu_seff0_edxfeatures[] = {
{ SEFF0EDX_IBRS, "IBRS,IBPB" },
{ SEFF0EDX_STIBP, "STIBP" },
+ { SEFF0EDX_L1DF, "L1DF" },
/* SEFF0EDX_ARCH_CAP (not printed) */
}, cpu_tpm_eaxfeatures[] = {
{ TPM_SENSOR, "SENSOR" },
@@ -1031,6 +1032,28 @@ cpu_check_vmm_cap(struct cpu_info *ci)
CPUID(CPUID_AMD_SVM_CAP, dummy, dummy, dummy, cap);
if (cap & AMD_SVM_NESTED_PAGING_CAP)
ci->ci_vmm_flags |= CI_VMM_RVI;
+ }
+
+ /*
+ * Check "L1 flush on VM entry" (Intel L1TF vuln) semantics
+ */
+ if (!strcmp(cpu_vendor, "GenuineIntel")) {
+ if (ci->ci_feature_sefflags_edx & SEFF0EDX_L1DF)
+ ci->ci_vmm_cap.vcc_vmx.vmx_has_l1_flush_msr = 1;
+ else
+ ci->ci_vmm_cap.vcc_vmx.vmx_has_l1_flush_msr = 0;
+
+ /*
+ * Certain CPUs may have the vulnerability remedied in
+ * hardware, check for that and override the setting
+ * calculated above.
+ */
+ if (ci->ci_feature_sefflags_edx & SEFF0EDX_ARCH_CAP) {
+ msr = rdmsr(MSR_ARCH_CAPABILITIES);
+ if (msr & ARCH_CAPABILITIES_SKIP_L1DFL_VMENTRY)
+ ci->ci_vmm_cap.vcc_vmx.vmx_has_l1_flush_msr =
+ VMX_SKIP_L1D_FLUSH;
+ }
}
}
#endif /* NVMM > 0 */
Index: sys/arch/amd64/amd64/vmm.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/vmm.c,v
retrieving revision 1.170.2.1
diff -u -p -r1.170.2.1 vmm.c
--- sys/arch/amd64/amd64/vmm.c 22 Jun 2018 13:05:33 -0000 1.170.2.1
+++ sys/arch/amd64/amd64/vmm.c 21 Aug 2018 21:45:29 -0000
@@ -43,6 +43,8 @@
/* #define VMM_DEBUG */
+void *l1tf_flush_region;
+
#ifdef VMM_DEBUG
#define DPRINTF(x...) do { printf(x); } while(0)
#else
@@ -363,22 +365,38 @@ vmm_attach(struct device *parent, struct
rw_init(&sc->vm_lock, "vmlistlock");
if (sc->nr_ept_cpus) {
- printf(": VMX/EPT\n");
+ printf(": VMX/EPT");
sc->mode = VMM_MODE_EPT;
} else if (sc->nr_vmx_cpus) {
- printf(": VMX\n");
+ printf(": VMX");
sc->mode = VMM_MODE_VMX;
} else if (sc->nr_rvi_cpus) {
- printf(": SVM/RVI\n");
+ printf(": SVM/RVI");
sc->mode = VMM_MODE_RVI;
} else if (sc->nr_svm_cpus) {
- printf(": SVM\n");
+ printf(": SVM");
sc->mode = VMM_MODE_SVM;
} else {
- printf(": unknown\n");
+ printf(": unknown");
sc->mode = VMM_MODE_UNKNOWN;
}
+ if (sc->mode == VMM_MODE_EPT || sc->mode == VMM_MODE_VMX) {
+ if (!(curcpu()->ci_vmm_cap.vcc_vmx.vmx_has_l1_flush_msr)) {
+ l1tf_flush_region = km_alloc(VMX_L1D_FLUSH_SIZE,
+ &kv_any, &vmm_kp_contig, &kd_waitok);
+ if (!l1tf_flush_region) {
+ printf(" (failing, no memory)");
+ sc->mode = VMM_MODE_UNKNOWN;
+ } else {
+ printf(" (using slow L1TF mitigation)");
+ memset(l1tf_flush_region, 0xcc,
+ VMX_L1D_FLUSH_SIZE);
+ }
+ }
+ }
+ printf("\n");
+
if (sc->mode == VMM_MODE_SVM || sc->mode == VMM_MODE_RVI) {
sc->max_vpid = curcpu()->ci_vmm_cap.vcc_svm.svm_max_asid;
} else {
@@ -3874,7 +3892,8 @@ vcpu_run_vmx(struct vcpu *vcpu, struct v
KERNEL_UNLOCK();
ret = vmx_enter_guest(&vcpu->vc_control_pa,
- &vcpu->vc_gueststate, resume);
+ &vcpu->vc_gueststate, resume,
+ curcpu()->ci_vmm_cap.vcc_vmx.vmx_has_l1_flush_msr);
/*
* On exit, interrupts are disabled, and we are running with
Index: sys/arch/amd64/amd64/vmm_support.S
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/vmm_support.S,v
retrieving revision 1.9
diff -u -p -r1.9 vmm_support.S
--- sys/arch/amd64/amd64/vmm_support.S 30 May 2017 17:49:47 -0000 1.9
+++ sys/arch/amd64/amd64/vmm_support.S 21 Aug 2018 21:45:29 -0000
@@ -16,6 +16,7 @@
*/
#include "assym.h"
+#include <machine/param.h>
#include <machine/asm.h>
#include <machine/psl.h>
#include <machine/specialreg.h>
@@ -137,6 +138,7 @@ _C_LABEL(invept):
_C_LABEL(vmx_enter_guest):
movq %rdx, %r8 /* resume flag */
+ movq %rcx, %r9 /* L1DF MSR support */
testq %r8, %r8
jnz skip_init
@@ -221,6 +223,62 @@ skip_init:
movq %rsp, %rax
vmwrite %rax, %rdi /* Host RSP */
+ /*
+ * Intel L1TF vulnerability fix
+ *
+ * Certain Intel CPUs are broken and allow guest VMs to bypass
+ * EPT entirely as their address harvesting logic treats guest
+ * PTEs as host physical addresses. Flush L1 Dcache to prevent
+ * information leakage by command MSR or manually reading a
+ * bunch of junk in order to fill sizeof(L1 Dcache)*2.
+ *
+ * %r9 (inherited from parameter 4 in %rcx earlier)
+ * determines the flushing requirements
+ * 0 - use manual "junk read" flush
+ * 1 - use MSR command
+ * 2 (VMX_SKIP_L1D_FLUSH) - no flush required on this CPU
+ */
+ cmpq $VMX_SKIP_L1D_FLUSH, %r9
+ je done_flush
+
+ testq %r9, %r9
+ jz no_l1df_msr
+
+ /* CPU has command MSR */
+ movq $MSR_FLUSH_CMD, %rcx
+ xorq %rdx, %rdx
+ movq $FLUSH_CMD_L1D_FLUSH, %rax
+ wrmsr
+ jmp done_flush
+
+no_l1df_msr:
+ xorq %r9, %r9
+l1df_tlb_loop:
+ /* XXX get the right L1 size from cpuid */
+ cmpq $VMX_L1D_FLUSH_SIZE, %r9
+ je l1df_tlb_done
+ movb l1tf_flush_region(%r9), %al
+ addq $PAGE_SIZE, %r9
+ jmp l1df_tlb_loop
+
+l1df_tlb_done:
+ /*
+ * Serialize: ensure previous TLB loads don't pull PTDs
+ * or other PA-containing data into the L1D.
+ */
+ xorq %rax, %rax
+ cpuid
+
+ xorq %r9, %r9
+l1df_load_cache:
+ movb l1tf_flush_region(%r9), %al
+ /* XXX get the right cacheline size from cpuid */
+ addq $0x40, %r9
+ cmpq $VMX_L1D_FLUSH_SIZE, %r9
+ jne l1df_load_cache
+ lfence
+
+done_flush:
testq %r8, %r8
jnz do_resume
@@ -234,6 +292,10 @@ skip_init:
movq 0x50(%rsi), %r11
movq 0x48(%rsi), %r10
movq 0x40(%rsi), %r9
+ movq %rsi, %r8
+ /* XXX get the right cacheline size from cpuid */
+ addq $0x40, %r8
+ clflush (%r8)
movq 0x38(%rsi), %r8
movq 0x30(%rsi), %rbp
movq 0x28(%rsi), %rdi
@@ -241,6 +303,7 @@ skip_init:
movq 0x18(%rsi), %rcx
movq 0x10(%rsi), %rbx
movq 0x08(%rsi), %rax
+ clflush (%rsi)
movq 0x00(%rsi), %rsi
vmlaunch
@@ -256,6 +319,10 @@ do_resume:
movq 0x50(%rsi), %r11
movq 0x48(%rsi), %r10
movq 0x40(%rsi), %r9
+ movq %rsi, %r8
+ /* XXX get the right cacheline size from cpuid */
+ addq $0x40, %r8
+ clflush (%r8)
movq 0x38(%rsi), %r8
movq 0x30(%rsi), %rbp
movq 0x28(%rsi), %rdi
@@ -263,7 +330,9 @@ do_resume:
movq 0x18(%rsi), %rcx
movq 0x10(%rsi), %rbx
movq 0x08(%rsi), %rax
+ clflush (%rsi)
movq 0x00(%rsi), %rsi
+
vmresume
fail_launch_or_resume:
/* Failed launch/resume (fell through) */
Index: sys/arch/amd64/include/cpu.h
===================================================================
RCS file: /cvs/src/sys/arch/amd64/include/cpu.h,v
retrieving revision 1.114.4.2
diff -u -p -r1.114.4.2 cpu.h
--- sys/arch/amd64/include/cpu.h 22 Jun 2018 13:05:33 -0000 1.114.4.2
+++ sys/arch/amd64/include/cpu.h 21 Aug 2018 21:45:29 -0000
@@ -71,6 +71,7 @@ struct vmx {
uint32_t vmx_msr_table_size;
uint32_t vmx_cr3_tgt_count;
uint64_t vmx_vm_func;
+ uint8_t vmx_has_l1_flush_msr;
};
/*
Index: sys/arch/amd64/include/specialreg.h
===================================================================
RCS file: /cvs/src/sys/arch/amd64/include/specialreg.h,v
retrieving revision 1.61.4.2
diff -u -p -r1.61.4.2 specialreg.h
--- sys/arch/amd64/include/specialreg.h 22 Jun 2018 13:05:33 -0000 1.61.4.2
+++ sys/arch/amd64/include/specialreg.h 21 Aug 2018 21:45:29 -0000
@@ -217,6 +217,7 @@
/* SEFF EDX bits */
#define SEFF0EDX_IBRS 0x04000000 /* IBRS / IBPB Speculation Control */
#define SEFF0EDX_STIBP 0x08000000 /* STIBP Speculation Control */
+#define SEFF0EDX_L1DF 0x10000000 /* L1D_FLUSH */
#define SEFF0EDX_ARCH_CAP 0x20000000 /* Has IA32_ARCH_CAPABILITIES MSR */
/*
@@ -330,6 +331,7 @@
#define MSR_SPEC_CTRL 0x048 /* Speculation Control IBRS / STIBP */
#define SPEC_CTRL_IBRS (1ULL << 0)
#define SPEC_CTRL_STIBP (1ULL << 1)
+#define SPEC_CTRL_SSBD (1ULL << 2)
#define MSR_PRED_CMD 0x049 /* Speculation Control IBPB */
#define PRED_CMD_IBPB (1ULL << 0)
#define MSR_BIOS_UPDT_TRIG 0x079
@@ -346,6 +348,12 @@
#define MTRRcap_SMRR 0x800 /* bit 11 - SMM range reg supported */
#define MSR_ARCH_CAPABILITIES 0x10a
#define ARCH_CAPABILITIES_RDCL_NO (1 << 0) /* Meltdown safe */
+#define ARCH_CAPABILITIES_IBRS_ALL (1 << 1) /* enhanced IBRS */
+#define ARCH_CAPABILITIES_RSBA (1 << 2) /* RSB Alternate */
+#define ARCH_CAPABILITIES_SKIP_L1DFL_VMENTRY (1 << 3)
+#define ARCH_CAPABILITIES_SSB_NO (1 << 4) /* Spec St Byp safe */
+#define MSR_FLUSH_CMD 0x10b
+#define FLUSH_CMD_L1D_FLUSH (1ULL << 0)
#define MSR_BBL_CR_ADDR 0x116 /* PII+ only */
#define MSR_BBL_CR_DECC 0x118 /* PII+ only */
#define MSR_BBL_CR_CTL 0x119 /* PII+ only */
@@ -1208,6 +1216,9 @@
#define IA32_VMX_MSR_LIST_SIZE_MASK (7ULL << 25)
#define IA32_VMX_CR3_TGT_SIZE_MASK (0x1FFULL << 16)
+
+#define VMX_SKIP_L1D_FLUSH 2
+#define VMX_L1D_FLUSH_SIZE (64 * 1024)
/*
* SVM
Index: sys/arch/amd64/include/vmmvar.h
===================================================================
RCS file: /cvs/src/sys/arch/amd64/include/vmmvar.h,v
retrieving revision 1.47
diff -u -p -r1.47 vmmvar.h
--- sys/arch/amd64/include/vmmvar.h 20 Aug 2017 21:15:32 -0000 1.47
+++ sys/arch/amd64/include/vmmvar.h 21 Aug 2018 21:45:29 -0000
@@ -851,7 +851,7 @@ int vmwrite(uint64_t, uint64_t);
int vmread(uint64_t, uint64_t *);
void invvpid(uint64_t, struct vmx_invvpid_descriptor *);
void invept(uint64_t, struct vmx_invept_descriptor *);
-int vmx_enter_guest(uint64_t *, struct vcpu_gueststate *, int);
+int vmx_enter_guest(uint64_t *, struct vcpu_gueststate *, int, uint8_t);
int svm_enter_guest(uint64_t, struct vcpu_gueststate *,
struct region_descriptor *);
void start_vmm_on_cpu(struct cpu_info *);