From 6651c3e51fb0bb3de19705bcb5b10d37f0e68f5d Mon Sep 17 00:00:00 2001 From: guenther Date: Sun, 17 Mar 2024 05:49:41 +0000 Subject: [PATCH] Use VERW to mitigate the RFDS (Register File Data Sampling) vulnerability present in Intel Atom CPUs, reordering some ASM in return-to-userspace and start/resume-vmx-guest to reduce the number of kernel values still live in registers when VERW is used. This mitigation requires updated firmware which has affected CPUs report RFDS_CLEAR in dmesg. Firmware packaging by jsg@ and sthen@ Logic for interpreting intel's flags by jsg@ after lots of discussion between him, deraadt@, and I ok deraadt@ --- sys/arch/amd64/amd64/cpu.c | 35 ++++++++++++++++++++--------- sys/arch/amd64/amd64/identcpu.c | 4 +++- sys/arch/amd64/amd64/locore.S | 19 ++++++++++++---- sys/arch/amd64/amd64/vmm_support.S | 19 +++++++++++++++- sys/arch/amd64/include/specialreg.h | 4 +++- 5 files changed, 63 insertions(+), 18 deletions(-) diff --git a/sys/arch/amd64/amd64/cpu.c b/sys/arch/amd64/amd64/cpu.c index 7f4cccf1739..c92d1e8fd41 100644 --- a/sys/arch/amd64/amd64/cpu.c +++ b/sys/arch/amd64/amd64/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.183 2024/02/25 22:33:09 guenther Exp $ */ +/* $OpenBSD: cpu.c,v 1.184 2024/03/17 05:49:41 guenther Exp $ */ /* $NetBSD: cpu.c,v 1.1 2003/04/26 18:39:26 fvdl Exp $ */ /*- @@ -299,7 +299,8 @@ replacemds(void) CPU_INFO_ITERATOR cii; void *handler = NULL, *vmm_handler = NULL; const char *type; - int has_verw, s; + int use_verw = 0, s; + uint32_t cap = 0; /* ci_mds_tmp must be 32byte aligned for AVX instructions */ CTASSERT((offsetof(struct cpu_info, ci_mds_tmp) - @@ -309,20 +310,22 @@ replacemds(void) return; replacedone = 1; - if (strcmp(cpu_vendor, "GenuineIntel") != 0 || - ((ci->ci_feature_sefflags_edx & SEFF0EDX_ARCH_CAP) && - (rdmsr(MSR_ARCH_CAPABILITIES) & ARCH_CAP_MDS_NO))) { + if (strcmp(cpu_vendor, "GenuineIntel") != 0) + goto notintel; /* VERW only needed on Intel */ + + if ((ci->ci_feature_sefflags_edx & SEFF0EDX_ARCH_CAP)) + cap = rdmsr(MSR_ARCH_CAPABILITIES); + + if (cap & ARCH_CAP_MDS_NO) { /* Unaffected, nop out the handling code */ - has_verw = 0; } else if (ci->ci_feature_sefflags_edx & SEFF0EDX_MD_CLEAR) { /* new firmware, use VERW */ - has_verw = 1; + use_verw = 1; } else { int family = ci->ci_family; int model = ci->ci_model; int stepping = CPUID2STEPPING(ci->ci_signature); - has_verw = 0; if (family == 0x6 && (model == 0x2e || model == 0x1e || model == 0x1f || model == 0x1a || model == 0x2f || model == 0x25 || @@ -395,15 +398,24 @@ replacemds(void) } } + /* Register File Data Sampling (RFDS) also has a VERW workaround */ + if ((cap & ARCH_CAP_RFDS_NO) == 0 && (cap & ARCH_CAP_RFDS_CLEAR)) + use_verw = 1; + if (handler != NULL) { printf("cpu0: using %s MDS workaround%s\n", type, ""); s = splhigh(); codepatch_call(CPTAG_MDS, handler); codepatch_call(CPTAG_MDS_VMM, vmm_handler); splx(s); - } else if (has_verw) { - /* The new firmware enhances L1D_FLUSH MSR to flush MDS too */ - if (cpu_info_primary.ci_vmm_cap.vcc_vmx.vmx_has_l1_flush_msr == 1) { + } else if (use_verw) { + /* + * The new firmware enhances L1D_FLUSH MSR to flush MDS too, + * but keep the verw if affected by RFDS + */ + if ((cap & ARCH_CAP_RFDS_NO) == 0 && (cap & ARCH_CAP_RFDS_CLEAR)) { + type = ""; + } else if (cpu_info_primary.ci_vmm_cap.vcc_vmx.vmx_has_l1_flush_msr == 1) { s = splhigh(); codepatch_nop(CPTAG_MDS_VMM); splx(s); @@ -413,6 +425,7 @@ replacemds(void) } printf("cpu0: using %s MDS workaround%s\n", "VERW", type); } else { +notintel: s = splhigh(); codepatch_nop(CPTAG_MDS); codepatch_nop(CPTAG_MDS_VMM); diff --git a/sys/arch/amd64/amd64/identcpu.c b/sys/arch/amd64/amd64/identcpu.c index 0d113e732b8..c8eb1f23949 100644 --- a/sys/arch/amd64/amd64/identcpu.c +++ b/sys/arch/amd64/amd64/identcpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: identcpu.c,v 1.138 2023/09/03 09:30:43 mlarkin Exp $ */ +/* $OpenBSD: identcpu.c,v 1.139 2024/03/17 05:49:41 guenther Exp $ */ /* $NetBSD: identcpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */ /* @@ -274,6 +274,8 @@ const struct { { ARCH_CAP_PBRSB_NO, "PBRSB_NO" }, { ARCH_CAP_GDS_CTRL, "GDS_CTRL" }, { ARCH_CAP_GDS_NO, "GDS_NO" }, + { ARCH_CAP_RFDS_NO, "RFDS_NO" }, + { ARCH_CAP_RFDS_CLEAR, "RFDS_CLEAR" }, }; int diff --git a/sys/arch/amd64/amd64/locore.S b/sys/arch/amd64/amd64/locore.S index 35311147460..c5d91e68caa 100644 --- a/sys/arch/amd64/amd64/locore.S +++ b/sys/arch/amd64/amd64/locore.S @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.S,v 1.146 2024/02/25 22:33:09 guenther Exp $ */ +/* $OpenBSD: locore.S,v 1.147 2024/03/17 05:49:41 guenther Exp $ */ /* $NetBSD: locore.S,v 1.13 2004/03/25 18:33:17 drochner Exp $ */ /* @@ -616,8 +616,15 @@ GENTRY(Xsyscall) movq TF_R13(%rsp),%r13 movq TF_R14(%rsp),%r14 movq TF_R15(%rsp),%r15 + movq TF_RBX(%rsp),%rbx + movq TF_RDX(%rsp),%rdx CODEPATCH_START + xorl %edi,%edi + xorl %esi,%esi + xorl %r11d,%r11d + xorl %eax,%eax + xorl %ecx,%ecx movw %ds,TF_R8(%rsp) verw TF_R8(%rsp) CODEPATCH_END(CPTAG_MDS) @@ -625,7 +632,6 @@ GENTRY(Xsyscall) movq TF_RDI(%rsp),%rdi movq TF_RSI(%rsp),%rsi movq TF_RBP(%rsp),%rbp - movq TF_RBX(%rsp),%rbx /* * We need to finish reading from the trapframe, then switch @@ -635,7 +641,6 @@ GENTRY(Xsyscall) * user page tables, so save it in CPUVAR(SCRATCH) across * the switch. */ - movq TF_RDX(%rsp),%rdx movq TF_RAX(%rsp),%rax movq TF_RIP(%rsp),%rcx movq TF_RFLAGS(%rsp),%r11 @@ -806,8 +811,15 @@ intr_user_exit_post_ast: movq TF_R13(%rsp),%r13 movq TF_R14(%rsp),%r14 movq TF_R15(%rsp),%r15 + movq TF_RBX(%rsp),%rbx CODEPATCH_START + xorl %edi,%edi + xorl %esi,%esi + xorl %r11d,%r11d + xorl %eax,%eax + xorl %edx,%edx + xorl %ecx,%ecx movw %ds,TF_R8(%rsp) verw TF_R8(%rsp) CODEPATCH_END(CPTAG_MDS) @@ -815,7 +827,6 @@ intr_user_exit_post_ast: movq TF_RDI(%rsp),%rdi movq TF_RSI(%rsp),%rsi movq TF_RBP(%rsp),%rbp - movq TF_RBX(%rsp),%rbx /* * To get the final value for the register that was used diff --git a/sys/arch/amd64/amd64/vmm_support.S b/sys/arch/amd64/amd64/vmm_support.S index aadfb4a9610..8da5ac88873 100644 --- a/sys/arch/amd64/amd64/vmm_support.S +++ b/sys/arch/amd64/amd64/vmm_support.S @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm_support.S,v 1.25 2024/02/25 22:33:09 guenther Exp $ */ +/* $OpenBSD: vmm_support.S,v 1.26 2024/03/17 05:49:41 guenther Exp $ */ /* * Copyright (c) 2014 Mike Larkin * @@ -247,6 +247,23 @@ skip_init: * XXX information yet to make the correct choices. */ CODEPATCH_START + xorl %eax,%eax + xorl %ebx,%ebx + xorl %ecx,%ecx + xorl %edx,%edx + xorl %esi,%esi + xorl %edi,%edi + xorl %ebp,%ebp + /* + * r8 is a boolean flagging launch or resume + * r9 is 0-2 about the CPU + */ + xorl %r10d,%r10d + xorl %r11d,%r11d + xorl %r12d,%r12d + xorl %r13d,%r13d + xorl %r14d,%r14d + xorl %r15d,%r15d subq $8, %rsp movw %ds, (%rsp) verw (%rsp) diff --git a/sys/arch/amd64/include/specialreg.h b/sys/arch/amd64/include/specialreg.h index 38edcca6148..f7d3f6efff5 100644 --- a/sys/arch/amd64/include/specialreg.h +++ b/sys/arch/amd64/include/specialreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: specialreg.h,v 1.109 2023/09/03 09:30:43 mlarkin Exp $ */ +/* $OpenBSD: specialreg.h,v 1.110 2024/03/17 05:49:41 guenther Exp $ */ /* $NetBSD: specialreg.h,v 1.1 2003/04/26 18:39:48 fvdl Exp $ */ /* $NetBSD: x86/specialreg.h,v 1.2 2003/04/25 21:54:30 fvdl Exp $ */ @@ -428,6 +428,8 @@ #define ARCH_CAP_PBRSB_NO (1 << 24) /* PBSR safe */ #define ARCH_CAP_GDS_CTRL (1 << 25) /* has GDS_MITG_DIS/LOCK */ #define ARCH_CAP_GDS_NO (1 << 26) /* GDS safe */ +#define ARCH_CAP_RFDS_NO (1 << 27) /* RFDS safe */ +#define ARCH_CAP_RFDS_CLEAR (1 << 28) /* use VERW for RFDS */ #define MSR_FLUSH_CMD 0x10b #define FLUSH_CMD_L1D_FLUSH 0x1 /* (1ULL << 0) */ #define MSR_BBL_CR_ADDR 0x116 /* PII+ only */ -- 2.20.1