Re: [PATCH] x86/hyper-v: Don't WARN on VM-Enter if eVMCS sees VMFUNC[63:32] != 0

From: Sean Christopherson

Date: Tue Oct 20 2026 - 18:56:48 EST


On Tue, Oct 20, 2026, Manuel Andreas wrote:
> With the necessary Hyper-V extensions for eVMCS enabled, an L1 guest can
> trivially fire a WARN_ON_ONCE in nested_evmcs_check_controls.
> While vmcs12->vm_function_control is technically already sanity checked in
> nested.c, that check is only performed if VMFUNC functionality is at all enabled
> in the secondary processor controls of vmcs12.
>
> vmcs12->vm_function_control seems to only be utilized in the handling
> of a VMFUNC initiated from L2, but here a function other than 0 will
> just end up in a failure case either way, regardless of whether or not
> it is permissive in vmcs12->vm_function_control.
> Therefore, the check has no reason to trigger a warning at all.
>
> This patch simply removes the WARN_ON_ONCE and keeps the check.
>
> Fixes: 3ff8a13d41b2 ("KVM: nVMX: WARN once and fail VM-Enter if eVMCS sees VMFUNC[63:32] != 0")
> Signed-off-by: Manuel Andreas <manuel.andreas@xxxxxx>
> ---
> arch/x86/kvm/vmx/hyperv.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c
> index fa41d036acd4..008a06924eb4 100644
> --- a/arch/x86/kvm/vmx/hyperv.c
> +++ b/arch/x86/kvm/vmx/hyperv.c
> @@ -186,7 +186,7 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12)
> * controls in bits 63:32, i.e. dropping those bits on the consistency
> * check is intentional.
> */
> - if (WARN_ON_ONCE(vmcs12->vm_function_control >> 32))

I think the WARN is correct, this code is broken. Unless I'm missing some eVMCS
magic/quirk, this, and the secondary controls check, should be conditioned on the
field actually being used.

This, over two patches?

diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c
index fa41d036acd4..a1daf8f2ec5a 100644
--- a/arch/x86/kvm/vmx/hyperv.c
+++ b/arch/x86/kvm/vmx/hyperv.c
@@ -169,7 +169,8 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12)
vmcs12->cpu_based_vm_exec_control)))
return -EINVAL;

- if (CC(!nested_evmcs_is_valid_controls(EVMCS_2NDEXEC,
+ if (nested_cpu_has(vmcs12, CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) &&
+ CC(!nested_evmcs_is_valid_controls(EVMCS_2NDEXEC,
vmcs12->secondary_vm_exec_control)))
return -EINVAL;

@@ -186,11 +187,10 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12)
* controls in bits 63:32, i.e. dropping those bits on the consistency
* check is intentional.
*/
- if (WARN_ON_ONCE(vmcs12->vm_function_control >> 32))
- return -EINVAL;
-
- if (CC(!nested_evmcs_is_valid_controls(EVMCS_VMFUNC,
- vmcs12->vm_function_control)))
+ if (nested_cpu_has_vmfunc(vmcs12) &&
+ (WARN_ON_ONCE(vmcs12->vm_function_control >> 32) ||
+ CC(!nested_evmcs_is_valid_controls(EVMCS_VMFUNC,
+ vmcs12->vm_function_control))))
return -EINVAL;

return 0;


> + if (vmcs12->vm_function_control >> 32)
> return -EINVAL;
>
> if (CC(!nested_evmcs_is_valid_controls(EVMCS_VMFUNC,