From c8f2683ff0dca031f7cd407f2be95f661bf9d680 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Wed, 18 Feb 2026 09:19:05 +0100 Subject: [PATCH] VMM: HM - toggle CR4.CET around toggling CR0.WP if needed CET enabled systems need to disable CR4.CET prior to attempting to toggle CR0.WP to avoid triggering a #GP(0). This is needed in VMMR0.r0 for PaX's r/o GDT handling. Enhance the r/o GDT handling to toggle CR4.CET as well in case it's enabled. Signed-off-by: Mathias Krause --- src/VBox/VMM/VMMR0/target-x86/HMR0A-x86.asm | 33 +++++++++++++++++++ src/VBox/VMM/VMMR0/target-x86/HMR0VMX-x86.cpp | 5 +++ src/VBox/VMM/include/HMInternal.h | 3 +- src/VBox/VMM/include/HMInternal.mac | 3 +- 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/VBox/VMM/VMMR0/target-x86/HMR0A-x86.asm b/src/VBox/VMM/VMMR0/target-x86/HMR0A-x86.asm index 31c37fa0370..31aca4a0252 100644 --- a/src/VBox/VMM/VMMR0/target-x86/HMR0A-x86.asm +++ b/src/VBox/VMM/VMMR0/target-x86/HMR0A-x86.asm @@ -405,6 +405,7 @@ BEGINPROC VMXRestoreHostState pushfq cli ; (see above) +.restore_fs_after_cli: test edi, VMX_RESTORE_HOST_CAN_USE_WRFSBASE_AND_WRGSBASE jz .restore_fs_using_wrmsr @@ -440,6 +441,8 @@ ALIGNCODE(8) .gdt_readonly_or_need_writable: test edi, VMX_RESTORE_HOST_GDT_NEED_WRITABLE jnz .gdt_readonly_need_writable + test edi, VMX_RESTORE_HOST_CET_ENABLED + jnz .gdt_readonly_cet .gdt_readonly: mov rcx, cr0 mov r9, rcx @@ -451,6 +454,36 @@ ALIGNCODE(8) mov cr0, r9 jmp .restore_fs +.gdt_readonly_cet: + ; + ; CR4.CET, when enabled, needs to be disabled around toggling CR0.WP to + ; not #GP(0). + ; + ; We need to disable interrupts while doing so to ensure the kernel + ; sees a consistent state, i.e. no intermediate values of CR4 which + ; will be in conflict with the CR4 shadow. + ; + pushfq + cli + mov rcx, cr4 + mov r8, rcx + and rcx, ~X86_CR4_CET + mov cr4, rcx + mov rcx, cr0 + mov r9, rcx + add rax, qword [rsi + VMXRESTOREHOST.HostGdtr + 2] ; xAX <- descriptor offset + GDTR.pGdt. + and rcx, ~X86_CR0_WP + mov cr0, rcx + and dword [rax + 4], ~RT_BIT(9) ; clear the busy flag in TSS desc (bits 0-7=base, bit 9=busy bit) + ltr dx + mov cr0, r9 + mov cr4, r8 + ; + ; Keep in sync with test at .restore_fs! + test edi, VMX_RESTORE_HOST_SEL_FS | VMX_RESTORE_HOST_SEL_GS + jnz .restore_fs_after_cli + jmp .restore_flags + ALIGNCODE(8) .gdt_readonly_need_writable: add rax, qword [rsi + VMXRESTOREHOST.HostGdtrRw + 2] ; xAX <- descriptor offset + GDTR.pGdtRw diff --git a/src/VBox/VMM/VMMR0/target-x86/HMR0VMX-x86.cpp b/src/VBox/VMM/VMMR0/target-x86/HMR0VMX-x86.cpp index c9c0f16c005..2b0b3673f3f 100644 --- a/src/VBox/VMM/VMMR0/target-x86/HMR0VMX-x86.cpp +++ b/src/VBox/VMM/VMMR0/target-x86/HMR0VMX-x86.cpp @@ -3581,7 +3581,12 @@ static int hmR0VmxExportHostSegmentRegs(PVMCPUCC pVCpu, uint64_t uHostCr4) /* If the host has made GDT read-only, we would need to temporarily toggle CR0.WP before writing the GDT. */ if (g_fHmHostKernelFeatures & SUPKERNELFEATURES_GDT_READ_ONLY) + { fRestoreHostFlags |= VMX_RESTORE_HOST_GDT_READ_ONLY; + /* If CET is enabled, it needs to be disabled around toggling CR0.WP. */ + if (uHostCr4 & X86_CR4_CET) + fRestoreHostFlags |= VMX_RESTORE_HOST_CET_ENABLED; + } if (g_fHmHostKernelFeatures & SUPKERNELFEATURES_GDT_NEED_WRITABLE) { /* The GDT is read-only but the writable GDT is available. */ diff --git a/src/VBox/VMM/include/HMInternal.h b/src/VBox/VMM/include/HMInternal.h index e97cd4287c0..c3a5dddf5c4 100644 --- a/src/VBox/VMM/include/HMInternal.h +++ b/src/VBox/VMM/include/HMInternal.h @@ -682,6 +682,7 @@ AssertCompileSizeAlignment(SVMNESTEDVMCBCACHE, 8); #define VMX_RESTORE_HOST_GDT_READ_ONLY RT_BIT(7) #define VMX_RESTORE_HOST_GDT_NEED_WRITABLE RT_BIT(8) #define VMX_RESTORE_HOST_CAN_USE_WRFSBASE_AND_WRGSBASE RT_BIT(9) +#define VMX_RESTORE_HOST_CET_ENABLED RT_BIT(10) /** * This _must_ be the top most bit, so that we can easily check that it and * something else is set w/o having to do two checks like this: @@ -694,7 +695,7 @@ AssertCompileSizeAlignment(SVMNESTEDVMCBCACHE, 8); * if (pVCpu->hm.s.vmx.fRestoreHostFlags > VMX_RESTORE_HOST_REQUIRED) * @endcode */ -#define VMX_RESTORE_HOST_REQUIRED RT_BIT(10) +#define VMX_RESTORE_HOST_REQUIRED RT_BIT(11) /** @} */ /** diff --git a/src/VBox/VMM/include/HMInternal.mac b/src/VBox/VMM/include/HMInternal.mac index a651083a5ac..042b96732a8 100644 --- a/src/VBox/VMM/include/HMInternal.mac +++ b/src/VBox/VMM/include/HMInternal.mac @@ -111,7 +111,8 @@ endstruc %define VMX_RESTORE_HOST_GDT_READ_ONLY 0080h ;RT_BIT(7) %define VMX_RESTORE_HOST_GDT_NEED_WRITABLE 0100h ;RT_BIT(8) %define VMX_RESTORE_HOST_CAN_USE_WRFSBASE_AND_WRGSBASE 0200h ;RT_BIT(9) -%define VMX_RESTORE_HOST_REQUIRED 0400h ;RT_BIT(10) - must be the highest bit! +%define VMX_RESTORE_HOST_CET_ENABLED 0400h ;RT_BIT(10) +%define VMX_RESTORE_HOST_REQUIRED 0800h ;RT_BIT(11) - must be the highest bit! struc VMXRESTOREHOST .uHostSelDS resw 1 .uHostSelES resw 1