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 #include #include #include @@ -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 *);