[PATCH v4 27/28] KVM: TDX: Bug the VM if extending the initial measurement fails
Binbin Wu
binbin.wu at linux.intel.com
Tue Nov 4 17:16:53 AEDT 2025
On 10/31/2025 4:09 AM, Sean Christopherson wrote:
> WARN and terminate the VM if TDH_MR_EXTEND fails, as extending the
> measurement should fail if and only if there is a KVM bug, or if the S-EPT
> mapping is invalid. Now that KVM makes all state transitions mutually
> exclusive via tdx_vm_state_guard, it should be impossible for S-EPT
> mappings to be removed between kvm_tdp_mmu_map_private_pfn() and
> tdh_mr_extend().
>
> Holding slots_lock prevents zaps due to memslot updates,
> filemap_invalidate_lock() prevents zaps due to guest_memfd PUNCH_HOLE,
> vcpu->mutex locks prevents updates from other vCPUs, kvm->lock prevents
> VM-scoped ioctls from creating havoc (e.g. by creating new vCPUs), and all
> usage of kvm_zap_gfn_range() is mutually exclusive with S-EPT entries that
> can be used for the initial image.
>
> For kvm_zap_gfn_range(), the call from sev.c is obviously mutually
> exclusive, TDX disallows KVM_X86_QUIRK_IGNORE_GUEST_PAT so the same goes
> for kvm_noncoherent_dma_assignment_start_or_stop(), and
> __kvm_set_or_clear_apicv_inhibit() is blocked by virtue of holding all
> VM and vCPU mutexes (and the APIC page has its own non-guest_memfd memslot
Nit:
It sounds like TDX is using the memslot for the APIC page, but for a TD, the
memslot for the APIC page is never initialized or used?
> and so can't be used for the initial image, which means that too is
> mutually exclusive irrespective of locking).
>
> Opportunistically return early if the region doesn't need to be measured
> in order to reduce line lengths and avoid wraps. Similarly, immediately
> and explicitly return if TDH_MR_EXTEND fails to make it clear that KVM
> needs to bail entirely if extending the measurement fails.
>
> Signed-off-by: Sean Christopherson <seanjc at google.com>
Reviewed-by: Binbin Wu <binbin.wu at linux.intel.com>
> ---
> arch/x86/kvm/vmx/tdx.c | 24 +++++++++++++-----------
> 1 file changed, 13 insertions(+), 11 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> index 8bcdec049ac6..762f2896547f 100644
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
> @@ -3123,21 +3123,23 @@ static int tdx_gmem_post_populate(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
>
> put_page(src_page);
>
> - if (ret)
> + if (ret || !(arg->flags & KVM_TDX_MEASURE_MEMORY_REGION))
> return ret;
>
> - if (arg->flags & KVM_TDX_MEASURE_MEMORY_REGION) {
> - for (i = 0; i < PAGE_SIZE; i += TDX_EXTENDMR_CHUNKSIZE) {
> - err = tdh_mr_extend(&kvm_tdx->td, gpa + i, &entry,
> - &level_state);
> - if (err) {
> - ret = -EIO;
> - break;
> - }
> - }
> + /*
> + * Note, MR.EXTEND can fail if the S-EPT mapping is somehow removed
> + * between mapping the pfn and now, but slots_lock prevents memslot
> + * updates, filemap_invalidate_lock() prevents guest_memfd updates,
> + * mmu_notifier events can't reach S-EPT entries, and KVM's internal
> + * zapping flows are mutually exclusive with S-EPT mappings.
> + */
> + for (i = 0; i < PAGE_SIZE; i += TDX_EXTENDMR_CHUNKSIZE) {
> + err = tdh_mr_extend(&kvm_tdx->td, gpa + i, &entry, &level_state);
> + if (TDX_BUG_ON_2(err, TDH_MR_EXTEND, entry, level_state, kvm))
> + return -EIO;
> }
>
> - return ret;
> + return 0;
> }
>
> static int tdx_vcpu_init_mem_region(struct kvm_vcpu *vcpu, struct kvm_tdx_cmd *cmd)
More information about the Linuxppc-dev
mailing list