On Fri, Apr 10, 2026, Nikita Kalyazin wrote:
> From: Patrick Roy <[email protected]>
> 
> Add GUEST_MEMFD_FLAG_NO_DIRECT_MAP flag for KVM_CREATE_GUEST_MEMFD()
> ioctl. When set, guest_memfd folios will be removed from the direct map
> after preparation, with direct map entries only restored when the folios
> are freed.
> 
> To ensure these folios do not end up in places where the kernel cannot
> deal with them, set AS_NO_DIRECT_MAP on the guest_memfd's struct
> address_space if GUEST_MEMFD_FLAG_NO_DIRECT_MAP is requested.
> 
> Note that this flag causes removal of direct map entries for all
> guest_memfd folios independent of whether they are "shared" or "private"
> (although current guest_memfd only supports either all folios in the
> "shared" state, or all folios in the "private" state if
> GUEST_MEMFD_FLAG_MMAP is not set). The usecase for removing direct map
> entries of also the shared parts of guest_memfd are a special type of
> non-CoCo VM where, host userspace is trusted to have access to all of
> guest memory, but where Spectre-style transient execution attacks
> through the host kernel's direct map should still be mitigated.  In this
> setup, KVM retains access to guest memory via userspace mappings of
> guest_memfd, which are reflected back into KVM's memslots via
> userspace_addr. This is needed for things like MMIO emulation on x86_64
> to work.
> 
> Direct map entries are zapped right before guest or userspace mappings
> of gmem folios are set up, e.g. in kvm_gmem_fault_user_mapping() or
> kvm_gmem_get_pfn() [called from the KVM MMU code].

...

> +#define KVM_GMEM_FOLIO_NO_DIRECT_MAP BIT(0)
> +
> +static bool kvm_gmem_folio_no_direct_map(struct folio *folio)
> +{
> +     return ((u64)folio->private) & KVM_GMEM_FOLIO_NO_DIRECT_MAP;
> +}
> +
> +static int kvm_gmem_folio_zap_direct_map(struct folio *folio)
> +{
> +     int r = 0;
> +
> +     VM_WARN_ON_FOLIO(!folio_test_locked(folio), folio);
> +
> +     if (WARN_ON_ONCE(!(GMEM_I(folio_inode(folio))->flags & 
> GUEST_MEMFD_FLAG_NO_DIRECT_MAP)))
> +             return -EINVAL;
> +
> +     if (kvm_gmem_folio_no_direct_map(folio))
> +             goto out;
> +
> +     r = folio_zap_direct_map(folio);
> +     if (!r)
> +             folio->private = (void *)((u64)folio->private | 
> KVM_GMEM_FOLIO_NO_DIRECT_MAP);
> +
> +out:
> +     return r;
> +}
> +
> +static void kvm_gmem_folio_restore_direct_map(struct folio *folio)
> +{
> +     folio_restore_direct_map(folio);
> +     folio->private = (void *)((u64)folio->private & 
> ~KVM_GMEM_FOLIO_NO_DIRECT_MAP);
> +}

Making guest_memfd responsible for zapping and restoring the direct map on a 
per-
folio basis feels wrong given the addition of AS_NO_DIRECT_MAP.  I especially 
don't
like that the "rules" for when an AS_NO_DIRECT_MAP folio has a direct map will 
vary
based on the owner, and even within an owner (e.g. guest_memfd) will be ad hoc.

E.g. as per the series to add guest_memfd write() support[*]:

  When direct map removal is implemented [2]
   - write() will not be allowed to access pages that have already
     been removed from direct map
   - on completion, write() will remove the populated pages from
     direct map

That's pretty gross ABI, because with KVM_GMEM_FOLIO_NO_DIRECT_MAP, userspace 
can
write() exactly once.  To re-write memory, I assume userspace would need to do a
PUNCH_HOLE or truncate.

What's preventing us from handling this automagically in e.g. 
filemap_add_folio()
and filemap_remove_folio()?  Then the usage rules are pretty straightforward: 
the
kernel must *always* assume the direct map is invalid for folios from
AS_NO_DIRECT_MAP mappings.

Then if KVM needs to utilize a kernel mapping, e.g. in kvm_gmem_populate(), KVM
could use dedicated variants of kmap_local_xxx() to deal with a local mapping 
for
a folio/page without a direct map.  Or, KVM could simply disallow the specific
sequence that would require KVM to do the memcpy (I'm pretty sure we can do that
with in-place shared=>private conversion support).

I realize that could throw a big wrench into write() performance, but IMO, 
before
merging either series, we need a complete story for exactly how this will all 
fit
together, in a maintainable fashion and with sane ABI.

[*] https://lore.kernel.org/all/[email protected]

Reply via email to