From nobody Mon Feb 9 01:27:39 2026 Received: from mail-pj1-f74.google.com (mail-pj1-f74.google.com [209.85.216.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 958D0283FD7 for ; Tue, 10 Jun 2025 23:20:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749597625; cv=none; b=ETTtisy43rLgEW0f78wWYjyhMsftZ+zHw5EjxJPW+wMrFco2RqXeOPFQhOtzfKR0CIb3yp+193RHIAmT1yd47Vo7ondOG9mowptPGwDpnTOmm7Ddu+VPry29G68nl1BeOgrBwsMQn2/7ZG+OsBw+jWHGOXUPAQMAFiTU0EHdjG4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749597625; c=relaxed/simple; bh=blKNi5/eVsDYzPDTuqtVcEpW6PWWX74NKc4L5DVUPJY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=nZoOjyb3eRR/Ey7rERgE3ylN7k5PgGdtUlEpsmqWVx8oTWIPgo6vjuJRaGZvtmSvZE52IJvjSpdcRS7vMLYQ4BdoMtASTw+KkXLJwvu5Rl9KRhaZuNkFNy6g6CwyCHP5exorTDnougSJDA6ZNdLwOQK42pq/WqH8RZSPg/WkAl8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=4JqQAo08; arc=none smtp.client-ip=209.85.216.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="4JqQAo08" Received: by mail-pj1-f74.google.com with SMTP id 98e67ed59e1d1-31332dc2b59so5387074a91.0 for ; Tue, 10 Jun 2025 16:20:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1749597623; x=1750202423; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=wZCT8jtEOBxZLskW7DzyAfTB5wFIiDwQQWq62UPKKVg=; b=4JqQAo08u2hGRcks6/x6B/sQVj9InjeEo5HPxxFuvOxhgiifG1EXoWlomv9wa4Znex c7ui/WqWvhGP0eRvMDWYhETKUbyh8EokMfEzqk8dLHBjkOvJzfWw7YXwheUhOX6vRvXh uW77tBl//24PB0VVtuEKcu2kYZmWHTMxVpgRocjjni9OR32QY6ts73OiPqbucc6ty/Tq NgurfzcWM94dCN/pAKOV5FwS4mNNnQaR1pnFUreyZYL2KTUD7VamlDMzuZmdwU0zuiCh YdtfaabzywpxOhNZYOZEbxzsLTp45rVtaWpaqOwvhWfLTbgAZrnIi58yOWwvLTEkA2EI rJQA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749597623; x=1750202423; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=wZCT8jtEOBxZLskW7DzyAfTB5wFIiDwQQWq62UPKKVg=; b=YNyx3ELEDmiiaxxg1MbkoKDXBHNHi/96K0U77rSaN9EJq5aaGMzSw/p2YIwFpqGzhe EXjiO80vdA5otOBk2g5TH6lkk/AhjLjPro3VTBRuT+3XPOS/xO56W+rQ/iTaAoehFGBl SbL6zuVWaf1J43p5/9YAlVb7dENoiV0GLnIi255UVbQEVjqQcL8Btaz2MzV4mVSoyZxw fC1Atvkmk5+bai8S9dItsLs7Mq9fMRKlvsTMw576CjH9mkP311io791g4MrgBR2LT3Kp eZQh1oWzgLHJxMxdMECoJZY2gb+gfTRCHX1y3GAOPwf3DEFSogJG7sWyzhFQMzHwMCgM gmSQ== X-Forwarded-Encrypted: i=1; AJvYcCUvYINQ6R9/r/641e2mt/k+jcPNMd9EwnL/r3WNyFFme+UcdorE1n05exFULzVCviu3wzQqZ2OPawiPrAU=@vger.kernel.org X-Gm-Message-State: AOJu0YwGlIA3boekNu1DfTKjfaY96PpxLsbGSbgTJtIO5mqds0lvymZl Gfv0VsE4r22q8Sl9trT7yHLXF4sla49F/1J51aCeCur0rktj/9ZquzvXZBj1+rLKkUuVAQ7zz0b yP9LTRw== X-Google-Smtp-Source: AGHT+IEL/2DWvsmanYGnlyH/VBJzsS50gjIHQSz73qDhYyQ6YVFD4WjKbq6DoY3OuDN2ZWC6VE6hOcH0qFI= X-Received: from pjbpx2.prod.google.com ([2002:a17:90b:2702:b0:313:230:89ed]) (user=seanjc job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:4d07:b0:311:c970:c9bc with SMTP id 98e67ed59e1d1-313af21d9bfmr1797129a91.30.1749597623152; Tue, 10 Jun 2025 16:20:23 -0700 (PDT) Reply-To: Sean Christopherson Date: Tue, 10 Jun 2025 16:20:08 -0700 In-Reply-To: <20250610232010.162191-1-seanjc@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250610232010.162191-1-seanjc@google.com> X-Mailer: git-send-email 2.50.0.rc0.642.g800a2b2222-goog Message-ID: <20250610232010.162191-7-seanjc@google.com> Subject: [PATCH v6 6/8] KVM: nVMX: Check vmcs12->guest_ia32_debugctl on nested VM-Enter From: Sean Christopherson To: Sean Christopherson , Paolo Bonzini Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Adrian Hunter , Maxim Levitsky Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Maxim Levitsky Add a consistency check for L2's guest_ia32_debugctl, as KVM only supports a subset of hardware functionality, i.e. KVM can't rely on hardware to detect illegal/unsupported values. Failure to check the vmcs12 value would allow the guest to load any harware-supported value while running L2. Take care to exempt BTF and LBR from the validity check in order to match KVM's behavior for writes via WRMSR, but without clobbering vmcs12. Even if VM_EXIT_SAVE_DEBUG_CONTROLS is set in vmcs12, L1 can reasonably expect that vmcs12->guest_ia32_debugctl will not be modified if writes to the MSR are being intercepted. Arguably, KVM _should_ update vmcs12 if VM_EXIT_SAVE_DEBUG_CONTROLS is set *and* writes to MSR_IA32_DEBUGCTLMSR are not being intercepted by L1, but that would incur non-trivial complexity and wouldn't change the fact that KVM's handling of DEBUGCTL is blatantly broken. I.e. the extra complexity is not worth carrying. Cc: stable@vger.kernel.org Signed-off-by: Maxim Levitsky Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/nested.c | 12 ++++++++++-- arch/x86/kvm/vmx/vmx.c | 5 ++--- arch/x86/kvm/vmx/vmx.h | 3 +++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index b50f9c894ab8..5a6c636954eb 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -2662,7 +2662,8 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, stru= ct vmcs12 *vmcs12, if (vmx->nested.nested_run_pending && (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS)) { kvm_set_dr(vcpu, 7, vmcs12->guest_dr7); - vmcs_write64(GUEST_IA32_DEBUGCTL, vmcs12->guest_ia32_debugctl); + vmcs_write64(GUEST_IA32_DEBUGCTL, vmcs12->guest_ia32_debugctl & + vmx_get_supported_debugctl(vcpu, false)); } else { kvm_set_dr(vcpu, 7, vcpu->arch.dr7); vmcs_write64(GUEST_IA32_DEBUGCTL, vmx->nested.pre_vmenter_debugctl); @@ -3155,7 +3156,8 @@ static int nested_vmx_check_guest_state(struct kvm_vc= pu *vcpu, return -EINVAL; =20 if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS) && - CC(!kvm_dr7_valid(vmcs12->guest_dr7))) + (CC(!kvm_dr7_valid(vmcs12->guest_dr7)) || + CC(!vmx_is_valid_debugctl(vcpu, vmcs12->guest_ia32_debugctl, false))= )) return -EINVAL; =20 if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PAT) && @@ -4607,6 +4609,12 @@ static void sync_vmcs02_to_vmcs12(struct kvm_vcpu *v= cpu, struct vmcs12 *vmcs12) (vmcs12->vm_entry_controls & ~VM_ENTRY_IA32E_MODE) | (vm_entry_controls_get(to_vmx(vcpu)) & VM_ENTRY_IA32E_MODE); =20 + /* + * Note! Save DR7, but intentionally don't grab DEBUGCTL from vmcs02. + * Writes to DEBUGCTL that aren't intercepted by L1 are immediately + * propagated to vmcs12 (see vmx_set_msr()), as the value loaded into + * vmcs02 doesn't strictly track vmcs12. + */ if (vmcs12->vm_exit_controls & VM_EXIT_SAVE_DEBUG_CONTROLS) vmcs12->guest_dr7 =3D vcpu->arch.dr7; =20 diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 358c7036272a..b685e43de4e9 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2172,7 +2172,7 @@ static u64 nested_vmx_truncate_sysenter_addr(struct k= vm_vcpu *vcpu, return (unsigned long)data; } =20 -static u64 vmx_get_supported_debugctl(struct kvm_vcpu *vcpu, bool host_ini= tiated) +u64 vmx_get_supported_debugctl(struct kvm_vcpu *vcpu, bool host_initiated) { u64 debugctl =3D 0; =20 @@ -2191,8 +2191,7 @@ static u64 vmx_get_supported_debugctl(struct kvm_vcpu= *vcpu, bool host_initiated return debugctl; } =20 -static bool vmx_is_valid_debugctl(struct kvm_vcpu *vcpu, u64 data, - bool host_initiated) +bool vmx_is_valid_debugctl(struct kvm_vcpu *vcpu, u64 data, bool host_init= iated) { u64 invalid; =20 diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index b5758c33c60f..392e66c7e5fe 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -414,6 +414,9 @@ static inline void vmx_set_intercept_for_msr(struct kvm= _vcpu *vcpu, u32 msr, =20 void vmx_update_cpu_dirty_logging(struct kvm_vcpu *vcpu); =20 +u64 vmx_get_supported_debugctl(struct kvm_vcpu *vcpu, bool host_initiated); +bool vmx_is_valid_debugctl(struct kvm_vcpu *vcpu, u64 data, bool host_init= iated); + /* * Note, early Intel manuals have the write-low and read-high bitmap offse= ts * the wrong way round. The bitmaps control MSRs 0x00000000-0x00001fff and --=20 2.50.0.rc0.642.g800a2b2222-goog