On 3/17/26 15:12, Kalyazin, Nikita 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]. The only place where > a gmem folio can be allocated without being mapped anywhere is > kvm_gmem_populate(), where handling potential failures of direct map > removal is not possible (by the time direct map removal is attempted, > the folio is already marked as prepared, meaning attempting to re-try > kvm_gmem_populate() would just result in -EEXIST without fixing up the > direct map state). These folios are then removed form the direct map > upon kvm_gmem_get_pfn(), e.g. when they are mapped into the guest later. > > Signed-off-by: Patrick Roy <[email protected]>
I you changed this patch significantly, you should likely add a Co-developed-by: Nikita Kalyazin <[email protected]> above your sob. (applies to other patches as well, please double check) > Signed-off-by: Nikita Kalyazin <[email protected]> > --- > Documentation/virt/kvm/api.rst | 21 ++++++----- > include/linux/kvm_host.h | 3 ++ > include/uapi/linux/kvm.h | 1 + > virt/kvm/guest_memfd.c | 67 ++++++++++++++++++++++++++++++++-- > 4 files changed, 79 insertions(+), 13 deletions(-) > > diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst > index 032516783e96..8feec77b03fe 100644 > --- a/Documentation/virt/kvm/api.rst > +++ b/Documentation/virt/kvm/api.rst > @@ -6439,15 +6439,18 @@ a single guest_memfd file, but the bound ranges must > not overlap). > The capability KVM_CAP_GUEST_MEMFD_FLAGS enumerates the `flags` that can be > specified via KVM_CREATE_GUEST_MEMFD. Currently defined flags: > > - ============================ > ================================================ > - GUEST_MEMFD_FLAG_MMAP Enable using mmap() on the guest_memfd file > - descriptor. > - GUEST_MEMFD_FLAG_INIT_SHARED Make all memory in the file shared during > - KVM_CREATE_GUEST_MEMFD (memory files created > - without INIT_SHARED will be marked private). > - Shared memory can be faulted into host > userspace > - page tables. Private memory cannot. > - ============================ > ================================================ > + ============================== > ================================================ > + GUEST_MEMFD_FLAG_MMAP Enable using mmap() on the guest_memfd file > + descriptor. > + GUEST_MEMFD_FLAG_INIT_SHARED Make all memory in the file shared during > + KVM_CREATE_GUEST_MEMFD (memory files created > + without INIT_SHARED will be marked private). > + Shared memory can be faulted into host > userspace > + page tables. Private memory cannot. > + GUEST_MEMFD_FLAG_NO_DIRECT_MAP The guest_memfd instance will unmap the > memory > + backing it from the kernel's address space > + before passing it off to userspace or the > guest. > + ============================== > ================================================ > > When the KVM MMU performs a PFN lookup to service a guest fault and the > backing > guest_memfd has the GUEST_MEMFD_FLAG_MMAP set, then the fault will always be > diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h > index ce8c5fdf2752..c95747e2278c 100644 > --- a/include/linux/kvm_host.h > +++ b/include/linux/kvm_host.h > @@ -738,6 +738,9 @@ static inline u64 kvm_gmem_get_supported_flags(struct kvm > *kvm) > if (!kvm || kvm_arch_supports_gmem_init_shared(kvm)) > flags |= GUEST_MEMFD_FLAG_INIT_SHARED; > > + if (!kvm || kvm_arch_gmem_supports_no_direct_map(kvm)) > + flags |= GUEST_MEMFD_FLAG_NO_DIRECT_MAP; > + > return flags; > } > #endif > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h > index 80364d4dbebb..d864f67efdb7 100644 > --- a/include/uapi/linux/kvm.h > +++ b/include/uapi/linux/kvm.h > @@ -1642,6 +1642,7 @@ struct kvm_memory_attributes { > #define KVM_CREATE_GUEST_MEMFD _IOWR(KVMIO, 0xd4, struct > kvm_create_guest_memfd) > #define GUEST_MEMFD_FLAG_MMAP (1ULL << 0) > #define GUEST_MEMFD_FLAG_INIT_SHARED (1ULL << 1) > +#define GUEST_MEMFD_FLAG_NO_DIRECT_MAP (1ULL << 2) > > struct kvm_create_guest_memfd { > __u64 size; > diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c > index 651649623448..c9344647579c 100644 > --- a/virt/kvm/guest_memfd.c > +++ b/virt/kvm/guest_memfd.c > @@ -7,6 +7,7 @@ > #include <linux/mempolicy.h> > #include <linux/pseudo_fs.h> > #include <linux/pagemap.h> > +#include <linux/set_memory.h> > > #include "kvm_mm.h" > > @@ -76,6 +77,35 @@ static int __kvm_gmem_prepare_folio(struct kvm *kvm, > struct kvm_memory_slot *slo > return 0; > } > > +#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) > +{ > + u64 gmem_flags = GMEM_I(folio_inode(folio))->flags; > + int r = 0; > + > + if (kvm_gmem_folio_no_direct_map(folio) || !(gmem_flags & > GUEST_MEMFD_FLAG_NO_DIRECT_MAP)) The function is only called when kvm_gmem_no_direct_map(folio_inode(folio)) Does it really make sense to check for GUEST_MEMFD_FLAG_NO_DIRECT_MAP again? If, at all, it should be a warning if GUEST_MEMFD_FLAG_NO_DIRECT_MAP is not set? Further, kvm_gmem_folio_zap_direct_map() uses the folio lock to synchronize, right? Might be worth pointing that out somehow (e.g., lockdep check if possible). > + 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) > +{ kvm_gmem_folio_zap_direct_map() is allowed to be called on folios that already have the directmap remove, kvm_gmem_folio_restore_direct_map() cannot be called if the directmap was already restored. Should we make that more consistent? Hoping Sean can find some time to review -- Cheers, David

