diff --git a/resources/hiding_ci/build_and_install_kernel.sh b/resources/hiding_ci/build_and_install_kernel.sh index 967f644e35a..74bbb979906 100755 --- a/resources/hiding_ci/build_and_install_kernel.sh +++ b/resources/hiding_ci/build_and_install_kernel.sh @@ -86,10 +86,7 @@ apply_patch_or_series() { *.patch) apply_patch_file $1 ;; *.mbox) apply_series_mbox $1 ;; *.lore) apply_series_link $1 ;; - *) - echo "Uknown patch file: "$1 - exit 1 - ;; + *) echo "Skipping non-patch file" $1 ;; esac } @@ -146,7 +143,7 @@ update_boot_config() { KERNEL_URL=$(cat kernel_url) KERNEL_COMMIT_HASH=$(cat kernel_commit_hash) -KERNEL_PATCHES_DIR=$(pwd)/patches +KERNEL_PATCHES_DIR=$(pwd)/linux_patches KERNEL_CONFIG_OVERRIDES=$(pwd)/kernel_config_overrides TMP_BUILD_DIR=$(mktemp -d -t kernel-build-XXXX) diff --git a/resources/hiding_ci/linux_patches/0001-mm-Consolidate-freeing-of-typed-folios-on-final-foli.patch b/resources/hiding_ci/linux_patches/0001-mm-Consolidate-freeing-of-typed-folios-on-final-foli.patch new file mode 100644 index 00000000000..0986dfacfeb --- /dev/null +++ b/resources/hiding_ci/linux_patches/0001-mm-Consolidate-freeing-of-typed-folios-on-final-foli.patch @@ -0,0 +1,109 @@ +From f9ca710b51263ce8317cc2fa02232e456fa1f39c Mon Sep 17 00:00:00 2001 +From: Fuad Tabba +Date: Tue, 18 Mar 2025 16:18:15 +0000 +Subject: [PATCH 01/34] mm: Consolidate freeing of typed folios on final + folio_put() + +Some folio types, such as hugetlb, handle freeing their own +folios. Moreover, guest_memfd will require being notified once a +folio's reference count reaches 0 to facilitate shared to private +folio conversion, without the folio actually being freed at that +point. + +As a first step towards that, this patch consolidates freeing +folios that have a type. The first user is hugetlb folios. Later +in this patch series, guest_memfd will become the second user of +this. + +Suggested-by: David Hildenbrand +Acked-by: Vlastimil Babka +Acked-by: David Hildenbrand +Signed-off-by: Fuad Tabba +--- + include/linux/page-flags.h | 15 +++++++++++++++ + mm/swap.c | 23 ++++++++++++++++++----- + 2 files changed, 33 insertions(+), 5 deletions(-) + +diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h +index 36d283552f80..6dc2494bd002 100644 +--- a/include/linux/page-flags.h ++++ b/include/linux/page-flags.h +@@ -953,6 +953,21 @@ static inline bool page_has_type(const struct page *page) + return page_mapcount_is_type(data_race(page->page_type)); + } + ++static inline int page_get_type(const struct page *page) ++{ ++ return page->page_type >> 24; ++} ++ ++static inline bool folio_has_type(const struct folio *folio) ++{ ++ return page_has_type(&folio->page); ++} ++ ++static inline int folio_get_type(const struct folio *folio) ++{ ++ return page_get_type(&folio->page); ++} ++ + #define FOLIO_TYPE_OPS(lname, fname) \ + static __always_inline bool folio_test_##fname(const struct folio *folio) \ + { \ +diff --git a/mm/swap.c b/mm/swap.c +index fc8281ef4241..47bc1bb919cc 100644 +--- a/mm/swap.c ++++ b/mm/swap.c +@@ -94,6 +94,19 @@ static void page_cache_release(struct folio *folio) + unlock_page_lruvec_irqrestore(lruvec, flags); + } + ++static void free_typed_folio(struct folio *folio) ++{ ++ switch (folio_get_type(folio)) { ++#ifdef CONFIG_HUGETLBFS ++ case PGTY_hugetlb: ++ free_huge_folio(folio); ++ return; ++#endif ++ default: ++ WARN_ON_ONCE(1); ++ } ++} ++ + void __folio_put(struct folio *folio) + { + if (unlikely(folio_is_zone_device(folio))) { +@@ -101,8 +114,8 @@ void __folio_put(struct folio *folio) + return; + } + +- if (folio_test_hugetlb(folio)) { +- free_huge_folio(folio); ++ if (unlikely(folio_has_type(folio))) { ++ free_typed_folio(folio); + return; + } + +@@ -966,13 +979,13 @@ void folios_put_refs(struct folio_batch *folios, unsigned int *refs) + if (!folio_ref_sub_and_test(folio, nr_refs)) + continue; + +- /* hugetlb has its own memcg */ +- if (folio_test_hugetlb(folio)) { ++ if (unlikely(folio_has_type(folio))) { ++ /* typed folios have their own memcg, if any */ + if (lruvec) { + unlock_page_lruvec_irqrestore(lruvec, flags); + lruvec = NULL; + } +- free_huge_folio(folio); ++ free_typed_folio(folio); + continue; + } + folio_unqueue_deferred_split(folio); + +base-commit: 4701f33a10702d5fc577c32434eb62adde0a1ae1 +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0002-KVM-guest_memfd-Handle-final-folio_put-of-guest_memf.patch b/resources/hiding_ci/linux_patches/0002-KVM-guest_memfd-Handle-final-folio_put-of-guest_memf.patch new file mode 100644 index 00000000000..b9f4f83f442 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0002-KVM-guest_memfd-Handle-final-folio_put-of-guest_memf.patch @@ -0,0 +1,182 @@ +From 9a4d7cd855d14e1522f363e3e04ebb9fa0a90ff0 Mon Sep 17 00:00:00 2001 +From: Fuad Tabba +Date: Tue, 18 Mar 2025 16:18:16 +0000 +Subject: [PATCH 02/34] KVM: guest_memfd: Handle final folio_put() of + guest_memfd pages + +Before transitioning a guest_memfd folio to unshared, thereby +disallowing access by the host and allowing the hypervisor to +transition its view of the guest page as private, we need to be +sure that the host doesn't have any references to the folio. + +This patch introduces a new type for guest_memfd folios, which +isn't activated in this series but is here as a placeholder and +to facilitate the code in the subsequent patch series. This will +be used in the future to register a callback that informs the +guest_memfd subsystem when the last reference is dropped, +therefore knowing that the host doesn't have any remaining +references. + +This patch also introduces the configuration option, +KVM_GMEM_SHARED_MEM, which toggles support for mapping +guest_memfd shared memory at the host. + +Signed-off-by: Fuad Tabba +Acked-by: Vlastimil Babka +Acked-by: David Hildenbrand +--- + include/linux/kvm_host.h | 4 ++++ + include/linux/page-flags.h | 16 ++++++++++++++++ + mm/debug.c | 1 + + mm/swap.c | 29 +++++++++++++++++++++++++++++ + virt/kvm/Kconfig | 4 ++++ + virt/kvm/guest_memfd.c | 8 ++++++++ + 6 files changed, 62 insertions(+) + +diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h +index f34f4cfaa513..3ad0719bfc4f 100644 +--- a/include/linux/kvm_host.h ++++ b/include/linux/kvm_host.h +@@ -2571,4 +2571,8 @@ long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, + struct kvm_pre_fault_memory *range); + #endif + ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM ++void kvm_gmem_handle_folio_put(struct folio *folio); ++#endif ++ + #endif +diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h +index 6dc2494bd002..daeee9a38e4c 100644 +--- a/include/linux/page-flags.h ++++ b/include/linux/page-flags.h +@@ -933,6 +933,7 @@ enum pagetype { + PGTY_slab = 0xf5, + PGTY_zsmalloc = 0xf6, + PGTY_unaccepted = 0xf7, ++ PGTY_guestmem = 0xf8, + + PGTY_mapcount_underflow = 0xff + }; +@@ -1082,6 +1083,21 @@ FOLIO_TYPE_OPS(hugetlb, hugetlb) + FOLIO_TEST_FLAG_FALSE(hugetlb) + #endif + ++/* ++ * guestmem folios are used to back VM memory as managed by guest_memfd. Once ++ * the last reference is put, instead of freeing these folios back to the page ++ * allocator, they are returned to guest_memfd. ++ * ++ * For now, guestmem will only be set on these folios as long as they cannot be ++ * mapped to user space ("private state"), with the plan of always setting that ++ * type once typed folios can be mapped to user space cleanly. ++ */ ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM ++FOLIO_TYPE_OPS(guestmem, guestmem) ++#else ++FOLIO_TEST_FLAG_FALSE(guestmem) ++#endif ++ + PAGE_TYPE_OPS(Zsmalloc, zsmalloc, zsmalloc) + + /* +diff --git a/mm/debug.c b/mm/debug.c +index 8d2acf432385..08bc42c6cba8 100644 +--- a/mm/debug.c ++++ b/mm/debug.c +@@ -56,6 +56,7 @@ static const char *page_type_names[] = { + DEF_PAGETYPE_NAME(table), + DEF_PAGETYPE_NAME(buddy), + DEF_PAGETYPE_NAME(unaccepted), ++ DEF_PAGETYPE_NAME(guestmem), + }; + + static const char *page_type_name(unsigned int page_type) +diff --git a/mm/swap.c b/mm/swap.c +index 47bc1bb919cc..d8fda3948684 100644 +--- a/mm/swap.c ++++ b/mm/swap.c +@@ -38,6 +38,10 @@ + #include + #include + ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM ++#include ++#endif ++ + #include "internal.h" + + #define CREATE_TRACE_POINTS +@@ -94,6 +98,26 @@ static void page_cache_release(struct folio *folio) + unlock_page_lruvec_irqrestore(lruvec, flags); + } + ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM ++static void gmem_folio_put(struct folio *folio) ++{ ++ /* ++ * Perform the callback only as long as the KVM module is still loaded. ++ * As long as the folio mapping is set, the folio is associated with a ++ * guest_memfd inode. ++ */ ++ if (folio->mapping) ++ kvm_gmem_handle_folio_put(folio); ++ ++ /* ++ * If there are no references to the folio left, it's not associated ++ * with a guest_memfd inode anymore. ++ */ ++ if (folio_ref_count(folio) == 0) ++ __folio_put(folio); ++} ++#endif /* CONFIG_KVM_GMEM_SHARED_MEM */ ++ + static void free_typed_folio(struct folio *folio) + { + switch (folio_get_type(folio)) { +@@ -101,6 +125,11 @@ static void free_typed_folio(struct folio *folio) + case PGTY_hugetlb: + free_huge_folio(folio); + return; ++#endif ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM ++ case PGTY_guestmem: ++ gmem_folio_put(folio); ++ return; + #endif + default: + WARN_ON_ONCE(1); +diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig +index 54e959e7d68f..4e759e8020c5 100644 +--- a/virt/kvm/Kconfig ++++ b/virt/kvm/Kconfig +@@ -124,3 +124,7 @@ config HAVE_KVM_ARCH_GMEM_PREPARE + config HAVE_KVM_ARCH_GMEM_INVALIDATE + bool + depends on KVM_PRIVATE_MEM ++ ++config KVM_GMEM_SHARED_MEM ++ select KVM_PRIVATE_MEM ++ bool +diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c +index b2aa6bf24d3a..5fc414becae5 100644 +--- a/virt/kvm/guest_memfd.c ++++ b/virt/kvm/guest_memfd.c +@@ -13,6 +13,14 @@ struct kvm_gmem { + struct list_head entry; + }; + ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM ++void kvm_gmem_handle_folio_put(struct folio *folio) ++{ ++ WARN_ONCE(1, "A placeholder that shouldn't trigger. Work in progress."); ++} ++EXPORT_SYMBOL_GPL(kvm_gmem_handle_folio_put); ++#endif /* CONFIG_KVM_GMEM_SHARED_MEM */ ++ + /** + * folio_file_pfn - like folio_file_page, but return a pfn. + * @folio: The folio which contains this index. +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0003-KVM-guest_memfd-Allow-host-to-map-guest_memfd-pages.patch b/resources/hiding_ci/linux_patches/0003-KVM-guest_memfd-Allow-host-to-map-guest_memfd-pages.patch new file mode 100644 index 00000000000..8fb306b257b --- /dev/null +++ b/resources/hiding_ci/linux_patches/0003-KVM-guest_memfd-Allow-host-to-map-guest_memfd-pages.patch @@ -0,0 +1,193 @@ +From fd39febef2e0d41394e51f5e34f2c8de80b3b4dc Mon Sep 17 00:00:00 2001 +From: Fuad Tabba +Date: Tue, 18 Mar 2025 16:18:17 +0000 +Subject: [PATCH 03/34] KVM: guest_memfd: Allow host to map guest_memfd() pages + +Add support for mmap() and fault() for guest_memfd backed memory +in the host for VMs that support in-place conversion between +shared and private. To that end, this patch adds the ability to +check whether the VM type supports in-place conversion, and only +allows mapping its memory if that's the case. + +Also add the KVM capability KVM_CAP_GMEM_SHARED_MEM, which +indicates that the VM supports shared memory in guest_memfd, or +that the host can create VMs that support shared memory. +Supporting shared memory implies that memory can be mapped when +shared with the host. + +This is controlled by the KVM_GMEM_SHARED_MEM configuration +option. + +Signed-off-by: Fuad Tabba +--- + include/linux/kvm_host.h | 11 +++++ + include/uapi/linux/kvm.h | 1 + + virt/kvm/guest_memfd.c | 101 +++++++++++++++++++++++++++++++++++++++ + virt/kvm/kvm_main.c | 4 ++ + 4 files changed, 117 insertions(+) + +diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h +index 3ad0719bfc4f..601bbcaa5e41 100644 +--- a/include/linux/kvm_host.h ++++ b/include/linux/kvm_host.h +@@ -728,6 +728,17 @@ static inline bool kvm_arch_has_private_mem(struct kvm *kvm) + } + #endif + ++/* ++ * Arch code must define kvm_arch_gmem_supports_shared_mem if support for ++ * private memory is enabled and it supports in-place shared/private conversion. ++ */ ++#if !defined(kvm_arch_gmem_supports_shared_mem) && !IS_ENABLED(CONFIG_KVM_GMEM_SHARED_MEM) ++static inline bool kvm_arch_gmem_supports_shared_mem(struct kvm *kvm) ++{ ++ return false; ++} ++#endif ++ + #ifndef kvm_arch_has_readonly_mem + static inline bool kvm_arch_has_readonly_mem(struct kvm *kvm) + { +diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h +index 45e6d8fca9b9..117937a895da 100644 +--- a/include/uapi/linux/kvm.h ++++ b/include/uapi/linux/kvm.h +@@ -929,6 +929,7 @@ struct kvm_enable_cap { + #define KVM_CAP_PRE_FAULT_MEMORY 236 + #define KVM_CAP_X86_APIC_BUS_CYCLES_NS 237 + #define KVM_CAP_X86_GUEST_MODE 238 ++#define KVM_CAP_GMEM_SHARED_MEM 239 + + struct kvm_irq_routing_irqchip { + __u32 irqchip; +diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c +index 5fc414becae5..fbf89e643add 100644 +--- a/virt/kvm/guest_memfd.c ++++ b/virt/kvm/guest_memfd.c +@@ -320,7 +320,108 @@ static pgoff_t kvm_gmem_get_index(struct kvm_memory_slot *slot, gfn_t gfn) + return gfn - slot->base_gfn + slot->gmem.pgoff; + } + ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM ++static bool kvm_gmem_offset_is_shared(struct file *file, pgoff_t index) ++{ ++ struct kvm_gmem *gmem = file->private_data; ++ ++ ++ /* For now, VMs that support shared memory share all their memory. */ ++ return kvm_arch_gmem_supports_shared_mem(gmem->kvm); ++} ++ ++static vm_fault_t kvm_gmem_fault(struct vm_fault *vmf) ++{ ++ struct inode *inode = file_inode(vmf->vma->vm_file); ++ struct folio *folio; ++ vm_fault_t ret = VM_FAULT_LOCKED; ++ ++ filemap_invalidate_lock_shared(inode->i_mapping); ++ ++ folio = kvm_gmem_get_folio(inode, vmf->pgoff); ++ if (IS_ERR(folio)) { ++ int err = PTR_ERR(folio); ++ ++ if (err == -EAGAIN) ++ ret = VM_FAULT_RETRY; ++ else ++ ret = vmf_error(err); ++ ++ goto out_filemap; ++ } ++ ++ if (folio_test_hwpoison(folio)) { ++ ret = VM_FAULT_HWPOISON; ++ goto out_folio; ++ } ++ ++ if (!kvm_gmem_offset_is_shared(vmf->vma->vm_file, vmf->pgoff)) { ++ ret = VM_FAULT_SIGBUS; ++ goto out_folio; ++ } ++ ++ /* ++ * Shared folios would not be marked as "guestmem" so far, and we only ++ * expect shared folios at this point. ++ */ ++ if (WARN_ON_ONCE(folio_test_guestmem(folio))) { ++ ret = VM_FAULT_SIGBUS; ++ goto out_folio; ++ } ++ ++ /* No support for huge pages. */ ++ if (WARN_ON_ONCE(folio_test_large(folio))) { ++ ret = VM_FAULT_SIGBUS; ++ goto out_folio; ++ } ++ ++ if (!folio_test_uptodate(folio)) { ++ clear_highpage(folio_page(folio, 0)); ++ kvm_gmem_mark_prepared(folio); ++ } ++ ++ vmf->page = folio_file_page(folio, vmf->pgoff); ++ ++out_folio: ++ if (ret != VM_FAULT_LOCKED) { ++ folio_unlock(folio); ++ folio_put(folio); ++ } ++ ++out_filemap: ++ filemap_invalidate_unlock_shared(inode->i_mapping); ++ ++ return ret; ++} ++ ++static const struct vm_operations_struct kvm_gmem_vm_ops = { ++ .fault = kvm_gmem_fault, ++}; ++ ++static int kvm_gmem_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct kvm_gmem *gmem = file->private_data; ++ ++ if (!kvm_arch_gmem_supports_shared_mem(gmem->kvm)) ++ return -ENODEV; ++ ++ if ((vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) != ++ (VM_SHARED | VM_MAYSHARE)) { ++ return -EINVAL; ++ } ++ ++ file_accessed(file); ++ vm_flags_set(vma, VM_DONTDUMP); ++ vma->vm_ops = &kvm_gmem_vm_ops; ++ ++ return 0; ++} ++#else ++#define kvm_gmem_mmap NULL ++#endif /* CONFIG_KVM_GMEM_SHARED_MEM */ ++ + static struct file_operations kvm_gmem_fops = { ++ .mmap = kvm_gmem_mmap, + .open = generic_file_open, + .release = kvm_gmem_release, + .fallocate = kvm_gmem_fallocate, +diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c +index ba0327e2d0d3..38f0f402ea46 100644 +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -4830,6 +4830,10 @@ static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg) + #ifdef CONFIG_KVM_PRIVATE_MEM + case KVM_CAP_GUEST_MEMFD: + return !kvm || kvm_arch_has_private_mem(kvm); ++#endif ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM ++ case KVM_CAP_GMEM_SHARED_MEM: ++ return !kvm || kvm_arch_gmem_supports_shared_mem(kvm); + #endif + default: + break; +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0004-KVM-x86-Mark-KVM_X86_SW_PROTECTED_VM-as-supporting-g.patch b/resources/hiding_ci/linux_patches/0004-KVM-x86-Mark-KVM_X86_SW_PROTECTED_VM-as-supporting-g.patch new file mode 100644 index 00000000000..33bf24f9415 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0004-KVM-x86-Mark-KVM_X86_SW_PROTECTED_VM-as-supporting-g.patch @@ -0,0 +1,58 @@ +From d16c343f0f95ecd8d2cda2dfba4ac8b7c293f217 Mon Sep 17 00:00:00 2001 +From: Fuad Tabba +Date: Tue, 18 Mar 2025 16:18:19 +0000 +Subject: [PATCH 04/34] KVM: x86: Mark KVM_X86_SW_PROTECTED_VM as supporting + guest_memfd shared memory + +The KVM_X86_SW_PROTECTED_VM type is meant for experimentation and +does not have any underlying support for protected guests. This +makes it a good candidate for testing mapping shared memory. +Therefore, when the kconfig option is enabled, mark +KVM_X86_SW_PROTECTED_VM as supporting shared memory. + +This means that this memory is considered by guest_memfd to be +shared with the host, with the possibility of in-place conversion +between shared and private. This allows the host to map and fault +in guest_memfd memory belonging to this VM type. + +Signed-off-by: Fuad Tabba +--- + arch/x86/include/asm/kvm_host.h | 5 +++++ + arch/x86/kvm/Kconfig | 3 ++- + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h +index 32ae3aa50c7e..b874e54a5ee4 100644 +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -2246,8 +2246,13 @@ void kvm_configure_mmu(bool enable_tdp, int tdp_forced_root_level, + + #ifdef CONFIG_KVM_PRIVATE_MEM + #define kvm_arch_has_private_mem(kvm) ((kvm)->arch.has_private_mem) ++ ++#define kvm_arch_gmem_supports_shared_mem(kvm) \ ++ (IS_ENABLED(CONFIG_KVM_GMEM_SHARED_MEM) && \ ++ ((kvm)->arch.vm_type == KVM_X86_SW_PROTECTED_VM)) + #else + #define kvm_arch_has_private_mem(kvm) false ++#define kvm_arch_gmem_supports_shared_mem(kvm) false + #endif + + #define kvm_arch_has_readonly_mem(kvm) (!(kvm)->arch.has_protected_state) +diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig +index ea2c4f21c1ca..22d1bcdaad58 100644 +--- a/arch/x86/kvm/Kconfig ++++ b/arch/x86/kvm/Kconfig +@@ -45,7 +45,8 @@ config KVM_X86 + select HAVE_KVM_PM_NOTIFIER if PM + select KVM_GENERIC_HARDWARE_ENABLING + select KVM_GENERIC_PRE_FAULT_MEMORY +- select KVM_GENERIC_PRIVATE_MEM if KVM_SW_PROTECTED_VM ++ select KVM_PRIVATE_MEM if KVM_SW_PROTECTED_VM ++ select KVM_GMEM_SHARED_MEM if KVM_SW_PROTECTED_VM + select KVM_WERROR if WERROR + + config KVM +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0005-KVM-arm64-Refactor-user_mem_abort-calculation-of-for.patch b/resources/hiding_ci/linux_patches/0005-KVM-arm64-Refactor-user_mem_abort-calculation-of-for.patch new file mode 100644 index 00000000000..38b3292884d --- /dev/null +++ b/resources/hiding_ci/linux_patches/0005-KVM-arm64-Refactor-user_mem_abort-calculation-of-for.patch @@ -0,0 +1,62 @@ +From 483ccb70335cb0c76161caf76c0ccb7c618038e2 Mon Sep 17 00:00:00 2001 +From: Fuad Tabba +Date: Tue, 18 Mar 2025 16:18:20 +0000 +Subject: [PATCH 05/34] KVM: arm64: Refactor user_mem_abort() calculation of + force_pte + +To simplify the code and to make the assumptions clearer, +refactor user_mem_abort() by immediately setting force_pte to +true if the conditions are met. Also, remove the comment about +logging_active being guaranteed to never be true for VM_PFNMAP +memslots, since it's not technically correct right now. + +No functional change intended. + +Signed-off-by: Fuad Tabba +--- + arch/arm64/kvm/mmu.c | 13 ++++--------- + 1 file changed, 4 insertions(+), 9 deletions(-) + +diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c +index 1f55b0c7b11d..887ffa1f5b14 100644 +--- a/arch/arm64/kvm/mmu.c ++++ b/arch/arm64/kvm/mmu.c +@@ -1460,7 +1460,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, + bool fault_is_perm) + { + int ret = 0; +- bool write_fault, writable, force_pte = false; ++ bool write_fault, writable; + bool exec_fault, mte_allowed; + bool device = false, vfio_allow_any_uc = false; + unsigned long mmu_seq; +@@ -1472,6 +1472,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, + gfn_t gfn; + kvm_pfn_t pfn; + bool logging_active = memslot_is_logging(memslot); ++ bool force_pte = logging_active || is_protected_kvm_enabled(); + long vma_pagesize, fault_granule; + enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R; + struct kvm_pgtable *pgt; +@@ -1521,16 +1522,10 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, + return -EFAULT; + } + +- /* +- * logging_active is guaranteed to never be true for VM_PFNMAP +- * memslots. +- */ +- if (logging_active || is_protected_kvm_enabled()) { +- force_pte = true; ++ if (force_pte) + vma_shift = PAGE_SHIFT; +- } else { ++ else + vma_shift = get_vma_page_shift(vma, hva); +- } + + switch (vma_shift) { + #ifndef __PAGETABLE_PMD_FOLDED +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0006-KVM-guest_memfd-Handle-in-place-shared-memory-as-gue.patch b/resources/hiding_ci/linux_patches/0006-KVM-guest_memfd-Handle-in-place-shared-memory-as-gue.patch new file mode 100644 index 00000000000..05d9e08b1fc --- /dev/null +++ b/resources/hiding_ci/linux_patches/0006-KVM-guest_memfd-Handle-in-place-shared-memory-as-gue.patch @@ -0,0 +1,40 @@ +From b1e925d4d5db8513dba67c3a9d40a2b507668f09 Mon Sep 17 00:00:00 2001 +From: Fuad Tabba +Date: Tue, 18 Mar 2025 16:18:18 +0000 +Subject: [PATCH 06/34] KVM: guest_memfd: Handle in-place shared memory as + guest_memfd backed memory + +For VMs that allow sharing guest_memfd backed memory in-place, +handle that memory the same as "private" guest_memfd memory. This +means that faulting that memory in the host or in the guest will +go through the guest_memfd subsystem. + +Note that the word "private" in the name of the function +kvm_mem_is_private() doesn't necessarily indicate that the memory +isn't shared, but is due to the history and evolution of +guest_memfd and the various names it has received. In effect, +this function is used to multiplex between the path of a normal +page fault and the path of a guest_memfd backed page fault. + +Signed-off-by: Fuad Tabba +--- + include/linux/kvm_host.h | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h +index 601bbcaa5e41..3d5595a71a2a 100644 +--- a/include/linux/kvm_host.h ++++ b/include/linux/kvm_host.h +@@ -2521,7 +2521,8 @@ static inline bool kvm_mem_is_private(struct kvm *kvm, gfn_t gfn) + #else + static inline bool kvm_mem_is_private(struct kvm *kvm, gfn_t gfn) + { +- return false; ++ return kvm_arch_gmem_supports_shared_mem(kvm) && ++ kvm_slot_can_be_private(gfn_to_memslot(kvm, gfn)); + } + #endif /* CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES */ + +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0007-KVM-arm64-Handle-guest_memfd-backed-guest-page-fault.patch b/resources/hiding_ci/linux_patches/0007-KVM-arm64-Handle-guest_memfd-backed-guest-page-fault.patch new file mode 100644 index 00000000000..1ce256e6f57 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0007-KVM-arm64-Handle-guest_memfd-backed-guest-page-fault.patch @@ -0,0 +1,174 @@ +From 996513a423377349767d5cfef87850e80131854f Mon Sep 17 00:00:00 2001 +From: Fuad Tabba +Date: Tue, 18 Mar 2025 16:18:21 +0000 +Subject: [PATCH 07/34] KVM: arm64: Handle guest_memfd()-backed guest page + faults + +Add arm64 support for handling guest page faults on guest_memfd +backed memslots. + +For now, the fault granule is restricted to PAGE_SIZE. + +Signed-off-by: Fuad Tabba +--- + arch/arm64/kvm/mmu.c | 65 +++++++++++++++++++++++++++------------- + include/linux/kvm_host.h | 5 ++++ + virt/kvm/kvm_main.c | 5 ---- + 3 files changed, 50 insertions(+), 25 deletions(-) + +diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c +index 887ffa1f5b14..adb0681fc1c6 100644 +--- a/arch/arm64/kvm/mmu.c ++++ b/arch/arm64/kvm/mmu.c +@@ -1454,6 +1454,30 @@ static bool kvm_vma_mte_allowed(struct vm_area_struct *vma) + return vma->vm_flags & VM_MTE_ALLOWED; + } + ++static kvm_pfn_t faultin_pfn(struct kvm *kvm, struct kvm_memory_slot *slot, ++ gfn_t gfn, bool write_fault, bool *writable, ++ struct page **page, bool is_private) ++{ ++ kvm_pfn_t pfn; ++ int ret; ++ ++ if (!is_private) ++ return __kvm_faultin_pfn(slot, gfn, write_fault ? FOLL_WRITE : 0, writable, page); ++ ++ *writable = false; ++ ++ ret = kvm_gmem_get_pfn(kvm, slot, gfn, &pfn, page, NULL); ++ if (!ret) { ++ *writable = !memslot_is_readonly(slot); ++ return pfn; ++ } ++ ++ if (ret == -EHWPOISON) ++ return KVM_PFN_ERR_HWPOISON; ++ ++ return KVM_PFN_ERR_NOSLOT_MASK; ++} ++ + static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, + struct kvm_s2_trans *nested, + struct kvm_memory_slot *memslot, unsigned long hva, +@@ -1461,19 +1485,20 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, + { + int ret = 0; + bool write_fault, writable; +- bool exec_fault, mte_allowed; ++ bool exec_fault, mte_allowed = false; + bool device = false, vfio_allow_any_uc = false; + unsigned long mmu_seq; + phys_addr_t ipa = fault_ipa; + struct kvm *kvm = vcpu->kvm; +- struct vm_area_struct *vma; ++ struct vm_area_struct *vma = NULL; + short vma_shift; + void *memcache; +- gfn_t gfn; ++ gfn_t gfn = ipa >> PAGE_SHIFT; + kvm_pfn_t pfn; + bool logging_active = memslot_is_logging(memslot); +- bool force_pte = logging_active || is_protected_kvm_enabled(); +- long vma_pagesize, fault_granule; ++ bool is_gmem = kvm_mem_is_private(kvm, gfn); ++ bool force_pte = logging_active || is_gmem || is_protected_kvm_enabled(); ++ long vma_pagesize, fault_granule = PAGE_SIZE; + enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R; + struct kvm_pgtable *pgt; + struct page *page; +@@ -1510,16 +1535,22 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, + return ret; + } + ++ mmap_read_lock(current->mm); ++ + /* + * Let's check if we will get back a huge page backed by hugetlbfs, or + * get block mapping for device MMIO region. + */ +- mmap_read_lock(current->mm); +- vma = vma_lookup(current->mm, hva); +- if (unlikely(!vma)) { +- kvm_err("Failed to find VMA for hva 0x%lx\n", hva); +- mmap_read_unlock(current->mm); +- return -EFAULT; ++ if (!is_gmem) { ++ vma = vma_lookup(current->mm, hva); ++ if (unlikely(!vma)) { ++ kvm_err("Failed to find VMA for hva 0x%lx\n", hva); ++ mmap_read_unlock(current->mm); ++ return -EFAULT; ++ } ++ ++ vfio_allow_any_uc = vma->vm_flags & VM_ALLOW_ANY_UNCACHED; ++ mte_allowed = kvm_vma_mte_allowed(vma); + } + + if (force_pte) +@@ -1590,18 +1621,13 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, + ipa &= ~(vma_pagesize - 1); + } + +- gfn = ipa >> PAGE_SHIFT; +- mte_allowed = kvm_vma_mte_allowed(vma); +- +- vfio_allow_any_uc = vma->vm_flags & VM_ALLOW_ANY_UNCACHED; +- + /* Don't use the VMA after the unlock -- it may have vanished */ + vma = NULL; + + /* + * Read mmu_invalidate_seq so that KVM can detect if the results of +- * vma_lookup() or __kvm_faultin_pfn() become stale prior to +- * acquiring kvm->mmu_lock. ++ * vma_lookup() or faultin_pfn() become stale prior to acquiring ++ * kvm->mmu_lock. + * + * Rely on mmap_read_unlock() for an implicit smp_rmb(), which pairs + * with the smp_wmb() in kvm_mmu_invalidate_end(). +@@ -1609,8 +1635,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, + mmu_seq = vcpu->kvm->mmu_invalidate_seq; + mmap_read_unlock(current->mm); + +- pfn = __kvm_faultin_pfn(memslot, gfn, write_fault ? FOLL_WRITE : 0, +- &writable, &page); ++ pfn = faultin_pfn(kvm, memslot, gfn, write_fault, &writable, &page, is_gmem); + if (pfn == KVM_PFN_ERR_HWPOISON) { + kvm_send_hwpoison_signal(hva, vma_shift); + return 0; +diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h +index 3d5595a71a2a..ec3bedc18eab 100644 +--- a/include/linux/kvm_host.h ++++ b/include/linux/kvm_host.h +@@ -1882,6 +1882,11 @@ static inline int memslot_id(struct kvm *kvm, gfn_t gfn) + return gfn_to_memslot(kvm, gfn)->id; + } + ++static inline bool memslot_is_readonly(const struct kvm_memory_slot *slot) ++{ ++ return slot->flags & KVM_MEM_READONLY; ++} ++ + static inline gfn_t + hva_to_gfn_memslot(unsigned long hva, struct kvm_memory_slot *slot) + { +diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c +index 38f0f402ea46..3e40acb9f5c0 100644 +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -2624,11 +2624,6 @@ unsigned long kvm_host_page_size(struct kvm_vcpu *vcpu, gfn_t gfn) + return size; + } + +-static bool memslot_is_readonly(const struct kvm_memory_slot *slot) +-{ +- return slot->flags & KVM_MEM_READONLY; +-} +- + static unsigned long __gfn_to_hva_many(const struct kvm_memory_slot *slot, gfn_t gfn, + gfn_t *nr_pages, bool write) + { +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0008-KVM-guest_memfd-selftests-guest_memfd-mmap-test-when.patch b/resources/hiding_ci/linux_patches/0008-KVM-guest_memfd-selftests-guest_memfd-mmap-test-when.patch new file mode 100644 index 00000000000..872ee55d789 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0008-KVM-guest_memfd-selftests-guest_memfd-mmap-test-when.patch @@ -0,0 +1,149 @@ +From 1ee5d01987bff47f007fb86ad7738b299816b2ef Mon Sep 17 00:00:00 2001 +From: Fuad Tabba +Date: Tue, 18 Mar 2025 16:18:23 +0000 +Subject: [PATCH 08/34] KVM: guest_memfd: selftests: guest_memfd mmap() test + when mapping is allowed + +Expand the guest_memfd selftests to include testing mapping guest +memory for VM types that support it. + +Also, build the guest_memfd selftest for arm64. + +Signed-off-by: Fuad Tabba +--- + tools/testing/selftests/kvm/Makefile.kvm | 1 + + .../testing/selftests/kvm/guest_memfd_test.c | 75 +++++++++++++++++-- + 2 files changed, 70 insertions(+), 6 deletions(-) + +diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm +index 4277b983cace..c9a3f30e28dd 100644 +--- a/tools/testing/selftests/kvm/Makefile.kvm ++++ b/tools/testing/selftests/kvm/Makefile.kvm +@@ -160,6 +160,7 @@ TEST_GEN_PROGS_arm64 += coalesced_io_test + TEST_GEN_PROGS_arm64 += demand_paging_test + TEST_GEN_PROGS_arm64 += dirty_log_test + TEST_GEN_PROGS_arm64 += dirty_log_perf_test ++TEST_GEN_PROGS_arm64 += guest_memfd_test + TEST_GEN_PROGS_arm64 += guest_print_test + TEST_GEN_PROGS_arm64 += get-reg-list + TEST_GEN_PROGS_arm64 += kvm_create_max_vcpus +diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c +index ce687f8d248f..38c501e49e0e 100644 +--- a/tools/testing/selftests/kvm/guest_memfd_test.c ++++ b/tools/testing/selftests/kvm/guest_memfd_test.c +@@ -34,12 +34,48 @@ static void test_file_read_write(int fd) + "pwrite on a guest_mem fd should fail"); + } + +-static void test_mmap(int fd, size_t page_size) ++static void test_mmap_allowed(int fd, size_t total_size) + { ++ size_t page_size = getpagesize(); ++ const char val = 0xaa; ++ char *mem; ++ int ret; ++ int i; ++ ++ mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); ++ TEST_ASSERT(mem != MAP_FAILED, "mmaping() guest memory should pass."); ++ ++ memset(mem, val, total_size); ++ for (i = 0; i < total_size; i++) ++ TEST_ASSERT_EQ(mem[i], val); ++ ++ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, 0, ++ page_size); ++ TEST_ASSERT(!ret, "fallocate the first page should succeed"); ++ ++ for (i = 0; i < page_size; i++) ++ TEST_ASSERT_EQ(mem[i], 0x00); ++ for (; i < total_size; i++) ++ TEST_ASSERT_EQ(mem[i], val); ++ ++ memset(mem, val, total_size); ++ for (i = 0; i < total_size; i++) ++ TEST_ASSERT_EQ(mem[i], val); ++ ++ ret = munmap(mem, total_size); ++ TEST_ASSERT(!ret, "munmap should succeed"); ++} ++ ++static void test_mmap_denied(int fd, size_t total_size) ++{ ++ size_t page_size = getpagesize(); + char *mem; + + mem = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + TEST_ASSERT_EQ(mem, MAP_FAILED); ++ ++ mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); ++ TEST_ASSERT_EQ(mem, MAP_FAILED); + } + + static void test_file_size(int fd, size_t page_size, size_t total_size) +@@ -170,19 +206,27 @@ static void test_create_guest_memfd_multiple(struct kvm_vm *vm) + close(fd1); + } + +-int main(int argc, char *argv[]) ++unsigned long get_shared_type(void) + { +- size_t page_size; ++#ifdef __x86_64__ ++ return KVM_X86_SW_PROTECTED_VM; ++#endif ++ return 0; ++} ++ ++void test_vm_type(unsigned long type, bool is_shared) ++{ ++ struct kvm_vm *vm; + size_t total_size; ++ size_t page_size; + int fd; +- struct kvm_vm *vm; + + TEST_REQUIRE(kvm_has_cap(KVM_CAP_GUEST_MEMFD)); + + page_size = getpagesize(); + total_size = page_size * 4; + +- vm = vm_create_barebones(); ++ vm = vm_create_barebones_type(type); + + test_create_guest_memfd_invalid(vm); + test_create_guest_memfd_multiple(vm); +@@ -190,10 +234,29 @@ int main(int argc, char *argv[]) + fd = vm_create_guest_memfd(vm, total_size, 0); + + test_file_read_write(fd); +- test_mmap(fd, page_size); ++ ++ if (is_shared) ++ test_mmap_allowed(fd, total_size); ++ else ++ test_mmap_denied(fd, total_size); ++ + test_file_size(fd, page_size, total_size); + test_fallocate(fd, page_size, total_size); + test_invalid_punch_hole(fd, page_size, total_size); + + close(fd); ++ kvm_vm_release(vm); ++} ++ ++int main(int argc, char *argv[]) ++{ ++#ifndef __aarch64__ ++ /* For now, arm64 only supports shared guest memory. */ ++ test_vm_type(VM_TYPE_DEFAULT, false); ++#endif ++ ++ if (kvm_has_cap(KVM_CAP_GMEM_SHARED_MEM)) ++ test_vm_type(get_shared_type(), true); ++ ++ return 0; + } +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0009-KVM-arm64-Enable-mapping-guest_memfd-in-arm64.patch b/resources/hiding_ci/linux_patches/0009-KVM-arm64-Enable-mapping-guest_memfd-in-arm64.patch new file mode 100644 index 00000000000..eb2cb3fd4e8 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0009-KVM-arm64-Enable-mapping-guest_memfd-in-arm64.patch @@ -0,0 +1,51 @@ +From 3cc51efc17a2c41a480eed36b31c1773936717e0 Mon Sep 17 00:00:00 2001 +From: Fuad Tabba +Date: Tue, 18 Mar 2025 16:18:22 +0000 +Subject: [PATCH 09/34] KVM: arm64: Enable mapping guest_memfd in arm64 + +Enable mapping guest_memfd in arm64. For now, it applies to all +VMs in arm64 that use guest_memfd. In the future, new VM types +can restrict this via kvm_arch_gmem_supports_shared_mem(). + +Signed-off-by: Fuad Tabba +--- + arch/arm64/include/asm/kvm_host.h | 12 ++++++++++++ + arch/arm64/kvm/Kconfig | 1 + + 2 files changed, 13 insertions(+) + +diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h +index d919557af5e5..4440b2334a05 100644 +--- a/arch/arm64/include/asm/kvm_host.h ++++ b/arch/arm64/include/asm/kvm_host.h +@@ -1543,4 +1543,16 @@ void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val); + #define kvm_has_s1poe(k) \ + (kvm_has_feat((k), ID_AA64MMFR3_EL1, S1POE, IMP)) + ++#ifdef CONFIG_KVM_PRIVATE_MEM ++static inline bool kvm_arch_has_private_mem(struct kvm *kvm) ++{ ++ return IS_ENABLED(CONFIG_KVM_PRIVATE_MEM); ++} ++ ++static inline bool kvm_arch_gmem_supports_shared_mem(struct kvm *kvm) ++{ ++ return IS_ENABLED(CONFIG_KVM_GMEM_SHARED_MEM); ++} ++#endif /* CONFIG_KVM_PRIVATE_MEM */ ++ + #endif /* __ARM64_KVM_HOST_H__ */ +diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig +index ead632ad01b4..4830d8805bed 100644 +--- a/arch/arm64/kvm/Kconfig ++++ b/arch/arm64/kvm/Kconfig +@@ -38,6 +38,7 @@ menuconfig KVM + select HAVE_KVM_VCPU_RUN_PID_CHANGE + select SCHED_INFO + select GUEST_PERF_EVENTS if PERF_EVENTS ++ select KVM_GMEM_SHARED_MEM + help + Support hosting virtualized guest machines. + +-- +2.47.1 + diff --git a/resources/hiding_ci/patches/0002-mm-introduce-AS_NO_DIRECT_MAP.patch b/resources/hiding_ci/linux_patches/0010-mm-introduce-AS_NO_DIRECT_MAP.patch similarity index 98% rename from resources/hiding_ci/patches/0002-mm-introduce-AS_NO_DIRECT_MAP.patch rename to resources/hiding_ci/linux_patches/0010-mm-introduce-AS_NO_DIRECT_MAP.patch index 53dfc236022..0ec11b19bb7 100644 --- a/resources/hiding_ci/patches/0002-mm-introduce-AS_NO_DIRECT_MAP.patch +++ b/resources/hiding_ci/linux_patches/0010-mm-introduce-AS_NO_DIRECT_MAP.patch @@ -1,7 +1,7 @@ -From 138b7a4c83c43b42851cb8fec2bbdbaadd960241 Mon Sep 17 00:00:00 2001 +From 22ec89c0ff7af3430027cf71cf8bce5c8ed6e402 Mon Sep 17 00:00:00 2001 From: Patrick Roy Date: Fri, 7 Feb 2025 11:16:06 +0000 -Subject: [PATCH 1/2] mm: introduce AS_NO_DIRECT_MAP +Subject: [PATCH 10/34] mm: introduce AS_NO_DIRECT_MAP Add AS_NO_DIRECT_MAP for mappings where direct map entries of folios are set to not present . Currently, mappings that match this description are @@ -204,5 +204,5 @@ index 1b0a214ee558..ea4c04d469b1 100644 inode->i_op = &secretmem_iops; inode->i_mapping->a_ops = &secretmem_aops; -- -2.48.1 +2.47.1 diff --git a/resources/hiding_ci/patches/0003-KVM-guest_memfd-Add-flag-to-remove-from-direct-map.patch b/resources/hiding_ci/linux_patches/0011-KVM-guest_memfd-Add-flag-to-remove-from-direct-map.patch similarity index 97% rename from resources/hiding_ci/patches/0003-KVM-guest_memfd-Add-flag-to-remove-from-direct-map.patch rename to resources/hiding_ci/linux_patches/0011-KVM-guest_memfd-Add-flag-to-remove-from-direct-map.patch index c46e04e8543..0c8b984a2e6 100644 --- a/resources/hiding_ci/patches/0003-KVM-guest_memfd-Add-flag-to-remove-from-direct-map.patch +++ b/resources/hiding_ci/linux_patches/0011-KVM-guest_memfd-Add-flag-to-remove-from-direct-map.patch @@ -1,7 +1,7 @@ -From 9bbc39f9c7622f0060d395b1063a564c24926d8d Mon Sep 17 00:00:00 2001 +From b1fc478976c93fd42b14e06d2de57e121be03142 Mon Sep 17 00:00:00 2001 From: Patrick Roy Date: Fri, 7 Feb 2025 14:33:01 +0000 -Subject: [PATCH 2/2] KVM: guest_memfd: Add flag to remove from direct map +Subject: [PATCH 11/34] KVM: guest_memfd: Add flag to remove from direct map Add KVM_GMEM_NO_DIRECT_MAP flag for KVM_CREATE_GUEST_MEMFD() ioctl. When set, guest_memfd folios will be removed from the direct map after @@ -174,5 +174,5 @@ index 3e40acb9f5c0..32ca1c921ab0 100644 return !kvm || kvm_arch_has_private_mem(kvm); #endif -- -2.48.1 +2.47.1 diff --git a/resources/hiding_ci/linux_patches/0012-patrick-v4-fixup.patch b/resources/hiding_ci/linux_patches/0012-patrick-v4-fixup.patch new file mode 100644 index 00000000000..7532bcbe975 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0012-patrick-v4-fixup.patch @@ -0,0 +1,51 @@ +From 098a8167ad6c55336cad9abb808ebdc105784278 Mon Sep 17 00:00:00 2001 +From: Nikita Kalyazin +Date: Thu, 10 Apr 2025 14:18:39 +0000 +Subject: [PATCH 12/34] patrick v4 fixup + +Do not make kvm_gmem_free_folio dependent on +CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE . +--- + virt/kvm/guest_memfd.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c +index a2b96bc51391..291d647a5c80 100644 +--- a/virt/kvm/guest_memfd.c ++++ b/virt/kvm/guest_memfd.c +@@ -487,28 +487,28 @@ static int kvm_gmem_error_folio(struct address_space *mapping, struct folio *fol + return MF_DELAYED; + } + +-#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE + static void kvm_gmem_free_folio(struct folio *folio) + { ++#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE + struct page *page = folio_page(folio, 0); + kvm_pfn_t pfn = page_to_pfn(page); + int order = folio_order(folio); ++#endif + + if (folio_test_private(folio)) + WARN_ON_ONCE(set_direct_map_valid_noflush(folio_page(folio, 0), + folio_nr_pages(folio), true)); + ++#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE + kvm_arch_gmem_invalidate(pfn, pfn + (1ul << order)); +-} + #endif ++} + + static const struct address_space_operations kvm_gmem_aops = { + .dirty_folio = noop_dirty_folio, + .migrate_folio = kvm_gmem_migrate_folio, + .error_remove_folio = kvm_gmem_error_folio, +-#ifdef CONFIG_HAVE_KVM_ARCH_GMEM_INVALIDATE + .free_folio = kvm_gmem_free_folio, +-#endif + }; + + static int kvm_gmem_getattr(struct mnt_idmap *idmap, const struct path *path, +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0013-KVM-Add-KVM_MEM_USERFAULT-memslot-flag-and-bitmap.patch b/resources/hiding_ci/linux_patches/0013-KVM-Add-KVM_MEM_USERFAULT-memslot-flag-and-bitmap.patch new file mode 100644 index 00000000000..263752c8c6e --- /dev/null +++ b/resources/hiding_ci/linux_patches/0013-KVM-Add-KVM_MEM_USERFAULT-memslot-flag-and-bitmap.patch @@ -0,0 +1,161 @@ +From abfa51cb95feaae899254453788c6db1c70d0189 Mon Sep 17 00:00:00 2001 +From: James Houghton +Date: Thu, 9 Jan 2025 20:49:17 +0000 +Subject: [PATCH 13/34] KVM: Add KVM_MEM_USERFAULT memslot flag and bitmap + +Use one of the 14 reserved u64s in struct kvm_userspace_memory_region2 +for the user to provide `userfault_bitmap`. + +The memslot flag indicates if KVM should be reading from the +`userfault_bitmap` field from the memslot. The user is permitted to +provide a bogus pointer. If the pointer cannot be read from, we will +return -EFAULT (with no other information) back to the user. + +Signed-off-by: James Houghton +--- + include/linux/kvm_host.h | 14 ++++++++++++++ + include/uapi/linux/kvm.h | 4 +++- + virt/kvm/Kconfig | 3 +++ + virt/kvm/kvm_main.c | 36 ++++++++++++++++++++++++++++++++++++ + 4 files changed, 56 insertions(+), 1 deletion(-) + +diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h +index ec3bedc18eab..6cd0d910678e 100644 +--- a/include/linux/kvm_host.h ++++ b/include/linux/kvm_host.h +@@ -596,6 +596,7 @@ struct kvm_memory_slot { + unsigned long *dirty_bitmap; + struct kvm_arch_memory_slot arch; + unsigned long userspace_addr; ++ unsigned long __user *userfault_bitmap; + u32 flags; + short id; + u16 as_id; +@@ -746,6 +747,11 @@ static inline bool kvm_arch_has_readonly_mem(struct kvm *kvm) + } + #endif + ++static inline bool kvm_has_userfault(struct kvm *kvm) ++{ ++ return IS_ENABLED(CONFIG_HAVE_KVM_USERFAULT); ++} ++ + struct kvm_memslots { + u64 generation; + atomic_long_t last_used_slot; +@@ -2592,4 +2598,12 @@ long kvm_arch_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, + void kvm_gmem_handle_folio_put(struct folio *folio); + #endif + ++int kvm_gfn_userfault(struct kvm *kvm, struct kvm_memory_slot *memslot, ++ gfn_t gfn); ++ ++static inline bool kvm_memslot_userfault(struct kvm_memory_slot *memslot) ++{ ++ return memslot->flags & KVM_MEM_USERFAULT; ++} ++ + #endif +diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h +index fb02a93546d8..03676746be71 100644 +--- a/include/uapi/linux/kvm.h ++++ b/include/uapi/linux/kvm.h +@@ -40,7 +40,8 @@ struct kvm_userspace_memory_region2 { + __u64 guest_memfd_offset; + __u32 guest_memfd; + __u32 pad1; +- __u64 pad2[14]; ++ __u64 userfault_bitmap; ++ __u64 pad2[13]; + }; + + /* +@@ -51,6 +52,7 @@ struct kvm_userspace_memory_region2 { + #define KVM_MEM_LOG_DIRTY_PAGES (1UL << 0) + #define KVM_MEM_READONLY (1UL << 1) + #define KVM_MEM_GUEST_MEMFD (1UL << 2) ++#define KVM_MEM_USERFAULT (1UL << 3) + + /* for KVM_IRQ_LINE */ + struct kvm_irq_level { +diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig +index 4e759e8020c5..7987fed3f3ec 100644 +--- a/virt/kvm/Kconfig ++++ b/virt/kvm/Kconfig +@@ -128,3 +128,6 @@ config HAVE_KVM_ARCH_GMEM_INVALIDATE + config KVM_GMEM_SHARED_MEM + select KVM_PRIVATE_MEM + bool ++ ++config HAVE_KVM_USERFAULT ++ bool +\ No newline at end of file +diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c +index 32ca1c921ab0..fb3ccf0cbb04 100644 +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -1532,6 +1532,9 @@ static int check_memory_region_flags(struct kvm *kvm, + !(mem->flags & KVM_MEM_GUEST_MEMFD)) + valid_flags |= KVM_MEM_READONLY; + ++ if (kvm_has_userfault(kvm)) ++ valid_flags |= KVM_MEM_USERFAULT; ++ + if (mem->flags & ~valid_flags) + return -EINVAL; + +@@ -1968,6 +1971,13 @@ static int kvm_set_memory_region(struct kvm *kvm, + (mem->memory_size >> PAGE_SHIFT) > KVM_MEM_MAX_NR_PAGES) + return -EINVAL; + ++ if (mem->flags & KVM_MEM_USERFAULT && ++ ((mem->userfault_bitmap != untagged_addr(mem->userfault_bitmap)) || ++ !access_ok((void __user *)(unsigned long)mem->userfault_bitmap, ++ DIV_ROUND_UP(mem->memory_size >> PAGE_SHIFT, BITS_PER_LONG) ++ * sizeof(long)))) ++ return -EINVAL; ++ + slots = __kvm_memslots(kvm, as_id); + + /* +@@ -2035,6 +2045,9 @@ static int kvm_set_memory_region(struct kvm *kvm, + if (r) + goto out; + } ++ if (mem->flags & KVM_MEM_USERFAULT) ++ new->userfault_bitmap = ++ (unsigned long __user *)(unsigned long)mem->userfault_bitmap; + + r = kvm_set_memslot(kvm, old, new, change); + if (r) +@@ -6468,3 +6481,26 @@ void kvm_exit(void) + kvm_irqfd_exit(); + } + EXPORT_SYMBOL_GPL(kvm_exit); ++ ++int kvm_gfn_userfault(struct kvm *kvm, struct kvm_memory_slot *memslot, ++ gfn_t gfn) ++{ ++ unsigned long bitmap_chunk = 0; ++ off_t offset; ++ ++ if (!kvm_memslot_userfault(memslot)) ++ return 0; ++ ++ if (WARN_ON_ONCE(!memslot->userfault_bitmap)) ++ return 0; ++ ++ offset = gfn - memslot->base_gfn; ++ ++ if (copy_from_user(&bitmap_chunk, ++ memslot->userfault_bitmap + offset / BITS_PER_LONG, ++ sizeof(bitmap_chunk))) ++ return -EFAULT; ++ ++ /* Set in the bitmap means that the gfn is userfault */ ++ return !!(bitmap_chunk & (1ul << (offset % BITS_PER_LONG))); ++} +\ No newline at end of file +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0014-KVM-Add-KVM_MEMORY_EXIT_FLAG_USERFAULT.patch b/resources/hiding_ci/linux_patches/0014-KVM-Add-KVM_MEMORY_EXIT_FLAG_USERFAULT.patch new file mode 100644 index 00000000000..11d3f4d0618 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0014-KVM-Add-KVM_MEMORY_EXIT_FLAG_USERFAULT.patch @@ -0,0 +1,28 @@ +From 0a91075ecff4f60404bc05da0d10d41e1b33fcec Mon Sep 17 00:00:00 2001 +From: James Houghton +Date: Thu, 9 Jan 2025 20:49:18 +0000 +Subject: [PATCH 14/34] KVM: Add KVM_MEMORY_EXIT_FLAG_USERFAULT + +This flag is used for vCPU memory faults caused by KVM Userfault; i.e., +the bit in `userfault_bitmap` corresponding to the faulting gfn was set. + +Signed-off-by: James Houghton +--- + include/uapi/linux/kvm.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h +index 03676746be71..0e1a2fac5735 100644 +--- a/include/uapi/linux/kvm.h ++++ b/include/uapi/linux/kvm.h +@@ -444,6 +444,7 @@ struct kvm_run { + /* KVM_EXIT_MEMORY_FAULT */ + struct { + #define KVM_MEMORY_EXIT_FLAG_PRIVATE (1ULL << 3) ++#define KVM_MEMORY_EXIT_FLAG_USERFAULT (1ULL << 4) + __u64 flags; + __u64 gpa; + __u64 size; +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0015-KVM-Allow-late-setting-of-KVM_MEM_USERFAULT-on-guest.patch b/resources/hiding_ci/linux_patches/0015-KVM-Allow-late-setting-of-KVM_MEM_USERFAULT-on-guest.patch new file mode 100644 index 00000000000..38f7624d108 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0015-KVM-Allow-late-setting-of-KVM_MEM_USERFAULT-on-guest.patch @@ -0,0 +1,58 @@ +From 7a626f99566e7ab7fce004fcf4041d87e75512cc Mon Sep 17 00:00:00 2001 +From: James Houghton +Date: Thu, 9 Jan 2025 20:49:19 +0000 +Subject: [PATCH 15/34] KVM: Allow late setting of KVM_MEM_USERFAULT on + guest_memfd memslot + +Currently guest_memfd memslots can only be deleted. Slightly change the +logic to allow KVM_MR_FLAGS_ONLY changes when the only flag being +changed is KVM_MEM_USERFAULT. + +Signed-off-by: James Houghton +--- + virt/kvm/kvm_main.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c +index fb3ccf0cbb04..c60fe692de03 100644 +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -2009,9 +2009,6 @@ static int kvm_set_memory_region(struct kvm *kvm, + if ((kvm->nr_memslot_pages + npages) < kvm->nr_memslot_pages) + return -EINVAL; + } else { /* Modify an existing slot. */ +- /* Private memslots are immutable, they can only be deleted. */ +- if (mem->flags & KVM_MEM_GUEST_MEMFD) +- return -EINVAL; + if ((mem->userspace_addr != old->userspace_addr) || + (npages != old->npages) || + ((mem->flags ^ old->flags) & KVM_MEM_READONLY)) +@@ -2025,6 +2022,16 @@ static int kvm_set_memory_region(struct kvm *kvm, + return 0; + } + ++ /* ++ * Except for being able to set KVM_MEM_USERFAULT, private memslots are ++ * immutable, they can only be deleted. ++ */ ++ if (mem->flags & KVM_MEM_GUEST_MEMFD && ++ !(change == KVM_MR_CREATE || ++ (change == KVM_MR_FLAGS_ONLY && ++ (mem->flags ^ old->flags) == KVM_MEM_USERFAULT))) ++ return -EINVAL; ++ + if ((change == KVM_MR_CREATE || change == KVM_MR_MOVE) && + kvm_check_memslot_overlap(slots, id, base_gfn, base_gfn + npages)) + return -EEXIST; +@@ -2040,7 +2047,7 @@ static int kvm_set_memory_region(struct kvm *kvm, + new->npages = npages; + new->flags = mem->flags; + new->userspace_addr = mem->userspace_addr; +- if (mem->flags & KVM_MEM_GUEST_MEMFD) { ++ if (mem->flags & KVM_MEM_GUEST_MEMFD && change == KVM_MR_CREATE) { + r = kvm_gmem_bind(kvm, new, mem->guest_memfd, mem->guest_memfd_offset); + if (r) + goto out; +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0016-KVM-x86-mmu-Add-support-for-KVM_MEM_USERFAULT.patch b/resources/hiding_ci/linux_patches/0016-KVM-x86-mmu-Add-support-for-KVM_MEM_USERFAULT.patch new file mode 100644 index 00000000000..5895c60b415 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0016-KVM-x86-mmu-Add-support-for-KVM_MEM_USERFAULT.patch @@ -0,0 +1,217 @@ +From 7e9f22f83ca191df8deab84d7c8c9d64a1b5b10f Mon Sep 17 00:00:00 2001 +From: James Houghton +Date: Thu, 9 Jan 2025 20:49:21 +0000 +Subject: [PATCH 16/34] KVM: x86/mmu: Add support for KVM_MEM_USERFAULT + +Adhering to the requirements of KVM Userfault: + +1. Zap all sptes for the memslot when KVM_MEM_USERFAULT is toggled on + with kvm_arch_flush_shadow_memslot(). +2. Only all PAGE_SIZE sptes when KVM_MEM_USERFAULT is enabled (for both + normal/GUP memory and guest_memfd memory). +3. Reconstruct huge mappings when KVM_MEM_USERFAULT is toggled off with + kvm_mmu_recover_huge_pages(). This is the behavior when dirty logging + is disabled; remain consistent with it. + +With the new logic in kvm_mmu_slot_apply_flags(), I've simplified the +two dirty-logging-toggle checks into one, and I have dropped the +WARN_ON() that was there. + +Signed-off-by: James Houghton +--- + arch/x86/kvm/Kconfig | 1 + + arch/x86/kvm/mmu/mmu.c | 28 +++++++++++++++++++++---- + arch/x86/kvm/mmu/mmu_internal.h | 20 +++++++++++++++--- + arch/x86/kvm/x86.c | 36 ++++++++++++++++++++++++--------- + include/linux/kvm_host.h | 5 ++++- + 5 files changed, 72 insertions(+), 18 deletions(-) + +diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig +index 22d1bcdaad58..6b1ef6402e30 100644 +--- a/arch/x86/kvm/Kconfig ++++ b/arch/x86/kvm/Kconfig +@@ -48,6 +48,7 @@ config KVM_X86 + select KVM_PRIVATE_MEM if KVM_SW_PROTECTED_VM + select KVM_GMEM_SHARED_MEM if KVM_SW_PROTECTED_VM + select KVM_WERROR if WERROR ++ select HAVE_KVM_USERFAULT + + config KVM + tristate "Kernel-based Virtual Machine (KVM) support" +diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c +index 8160870398b9..7ac7dc164522 100644 +--- a/arch/x86/kvm/mmu/mmu.c ++++ b/arch/x86/kvm/mmu/mmu.c +@@ -4292,14 +4292,20 @@ static inline u8 kvm_max_level_for_order(int order) + return PG_LEVEL_4K; + } + +-static u8 kvm_max_private_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, +- u8 max_level, int gmem_order) ++static u8 kvm_max_private_mapping_level(struct kvm *kvm, ++ struct kvm_memory_slot *slot, ++ kvm_pfn_t pfn, ++ u8 max_level, ++ int gmem_order) + { + u8 req_max_level; + + if (max_level == PG_LEVEL_4K) + return PG_LEVEL_4K; + ++ if (kvm_memslot_userfault(slot)) ++ return PG_LEVEL_4K; ++ + max_level = min(kvm_max_level_for_order(gmem_order), max_level); + if (max_level == PG_LEVEL_4K) + return PG_LEVEL_4K; +@@ -4336,8 +4342,10 @@ static int kvm_mmu_faultin_pfn_private(struct kvm_vcpu *vcpu, + } + + fault->map_writable = !(fault->slot->flags & KVM_MEM_READONLY); +- fault->max_level = kvm_max_private_mapping_level(vcpu->kvm, fault->pfn, +- fault->max_level, max_order); ++ fault->max_level = kvm_max_private_mapping_level(vcpu->kvm, fault->slot, ++ fault->pfn, ++ fault->max_level, ++ max_order); + + return RET_PF_CONTINUE; + } +@@ -4346,6 +4354,18 @@ static int __kvm_mmu_faultin_pfn(struct kvm_vcpu *vcpu, + struct kvm_page_fault *fault) + { + unsigned int foll = fault->write ? FOLL_WRITE : 0; ++ int userfault; ++ ++ userfault = kvm_gfn_userfault(vcpu->kvm, fault->slot, fault->gfn); ++ if (userfault < 0) ++ return userfault; ++ if (userfault) { ++ kvm_mmu_prepare_userfault_exit(vcpu, fault); ++ return -EFAULT; ++ } ++ ++ if (kvm_memslot_userfault(fault->slot)) ++ fault->max_level = PG_LEVEL_4K; + + if (fault->is_private) + return kvm_mmu_faultin_pfn_private(vcpu, fault); +diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h +index 75f00598289d..d1f18dcc18fb 100644 +--- a/arch/x86/kvm/mmu/mmu_internal.h ++++ b/arch/x86/kvm/mmu/mmu_internal.h +@@ -335,12 +335,26 @@ enum { + */ + static_assert(RET_PF_CONTINUE == 0); + +-static inline void kvm_mmu_prepare_memory_fault_exit(struct kvm_vcpu *vcpu, +- struct kvm_page_fault *fault) ++static inline void __kvm_mmu_prepare_memory_fault_exit(struct kvm_vcpu *vcpu, ++ struct kvm_page_fault *fault, ++ bool is_userfault) + { + kvm_prepare_memory_fault_exit(vcpu, fault->gfn << PAGE_SHIFT, + PAGE_SIZE, fault->write, fault->exec, +- fault->is_private); ++ fault->is_private, ++ is_userfault); ++} ++ ++static inline void kvm_mmu_prepare_memory_fault_exit(struct kvm_vcpu *vcpu, ++ struct kvm_page_fault *fault) ++{ ++ __kvm_mmu_prepare_memory_fault_exit(vcpu, fault, false); ++} ++ ++static inline void kvm_mmu_prepare_userfault_exit(struct kvm_vcpu *vcpu, ++ struct kvm_page_fault *fault) ++{ ++ __kvm_mmu_prepare_memory_fault_exit(vcpu, fault, true); + } + + static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index 4b64ab350bcd..04034ca04703 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -13075,12 +13075,36 @@ static void kvm_mmu_slot_apply_flags(struct kvm *kvm, + u32 new_flags = new ? new->flags : 0; + bool log_dirty_pages = new_flags & KVM_MEM_LOG_DIRTY_PAGES; + ++ /* ++ * When toggling KVM Userfault on, zap all sptes so that userfault-ness ++ * will be respected at refault time. All new faults will only install ++ * small sptes. Therefore, when toggling it off, recover hugepages. ++ * ++ * For MOVE and DELETE, there will be nothing to do, as the old ++ * mappings will have already been deleted by ++ * kvm_arch_flush_shadow_memslot(). ++ * ++ * For CREATE, no mappings will have been created yet. ++ */ ++ if ((old_flags ^ new_flags) & KVM_MEM_USERFAULT && ++ (change == KVM_MR_FLAGS_ONLY)) { ++ if (old_flags & KVM_MEM_USERFAULT) ++ kvm_mmu_recover_huge_pages(kvm, new); ++ else ++ kvm_arch_flush_shadow_memslot(kvm, old); ++ } ++ ++ /* ++ * Nothing more to do if dirty logging isn't being toggled. ++ */ ++ if (!((old_flags ^ new_flags) & KVM_MEM_LOG_DIRTY_PAGES)) ++ return; ++ + /* + * Update CPU dirty logging if dirty logging is being toggled. This + * applies to all operations. + */ +- if ((old_flags ^ new_flags) & KVM_MEM_LOG_DIRTY_PAGES) +- kvm_mmu_update_cpu_dirty_logging(kvm, log_dirty_pages); ++ kvm_mmu_update_cpu_dirty_logging(kvm, log_dirty_pages); + + /* + * Nothing more to do for RO slots (which can't be dirtied and can't be +@@ -13100,14 +13124,6 @@ static void kvm_mmu_slot_apply_flags(struct kvm *kvm, + if ((change != KVM_MR_FLAGS_ONLY) || (new_flags & KVM_MEM_READONLY)) + return; + +- /* +- * READONLY and non-flags changes were filtered out above, and the only +- * other flag is LOG_DIRTY_PAGES, i.e. something is wrong if dirty +- * logging isn't being toggled on or off. +- */ +- if (WARN_ON_ONCE(!((old_flags ^ new_flags) & KVM_MEM_LOG_DIRTY_PAGES))) +- return; +- + if (!log_dirty_pages) { + /* + * Recover huge page mappings in the slot now that dirty logging +diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h +index 6cd0d910678e..4a5379367332 100644 +--- a/include/linux/kvm_host.h ++++ b/include/linux/kvm_host.h +@@ -2499,7 +2499,8 @@ static inline void kvm_account_pgtable_pages(void *virt, int nr) + static inline void kvm_prepare_memory_fault_exit(struct kvm_vcpu *vcpu, + gpa_t gpa, gpa_t size, + bool is_write, bool is_exec, +- bool is_private) ++ bool is_private, ++ bool is_userfault) + { + vcpu->run->exit_reason = KVM_EXIT_MEMORY_FAULT; + vcpu->run->memory_fault.gpa = gpa; +@@ -2509,6 +2510,8 @@ static inline void kvm_prepare_memory_fault_exit(struct kvm_vcpu *vcpu, + vcpu->run->memory_fault.flags = 0; + if (is_private) + vcpu->run->memory_fault.flags |= KVM_MEMORY_EXIT_FLAG_PRIVATE; ++ if (is_userfault) ++ vcpu->run->memory_fault.flags |= KVM_MEMORY_EXIT_FLAG_USERFAULT; + } + + #ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0017-KVM-Advertise-KVM_CAP_USERFAULT-in-KVM_CHECK_EXTENSI.patch b/resources/hiding_ci/linux_patches/0017-KVM-Advertise-KVM_CAP_USERFAULT-in-KVM_CHECK_EXTENSI.patch new file mode 100644 index 00000000000..bdbcb9117ba --- /dev/null +++ b/resources/hiding_ci/linux_patches/0017-KVM-Advertise-KVM_CAP_USERFAULT-in-KVM_CHECK_EXTENSI.patch @@ -0,0 +1,45 @@ +From fe6a44733d6384057fd68732ebf3aeb612443d14 Mon Sep 17 00:00:00 2001 +From: James Houghton +Date: Thu, 9 Jan 2025 20:49:20 +0000 +Subject: [PATCH 17/34] KVM: Advertise KVM_CAP_USERFAULT in KVM_CHECK_EXTENSION + +Advertise support for KVM_CAP_USERFAULT when kvm_has_userfault() returns +true. Currently this is merely IS_ENABLED(CONFIG_HAVE_KVM_USERFAULT), so +it is somewhat redundant. + +Signed-off-by: James Houghton +--- + include/uapi/linux/kvm.h | 1 + + virt/kvm/kvm_main.c | 4 ++++ + 2 files changed, 5 insertions(+) + +diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h +index 0e1a2fac5735..f5ad5d39c24b 100644 +--- a/include/uapi/linux/kvm.h ++++ b/include/uapi/linux/kvm.h +@@ -934,6 +934,7 @@ struct kvm_enable_cap { + #define KVM_CAP_X86_GUEST_MODE 238 + #define KVM_CAP_GMEM_SHARED_MEM 239 + #define KVM_CAP_GMEM_NO_DIRECT_MAP 240 ++#define KVM_CAP_USERFAULT 241 + + struct kvm_irq_routing_irqchip { + __u32 irqchip; +diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c +index c60fe692de03..bb85ea8d0f85 100644 +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -4854,6 +4854,10 @@ static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg) + #ifdef CONFIG_KVM_GMEM_SHARED_MEM + case KVM_CAP_GMEM_SHARED_MEM: + return !kvm || kvm_arch_gmem_supports_shared_mem(kvm); ++#endif ++#ifdef CONFIG_HAVE_KVM_USERFAULT ++ case KVM_CAP_USERFAULT: ++ return kvm_has_userfault(kvm); + #endif + default: + break; +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0018-KVM-arm64-Add-support-for-KVM_MEM_USERFAULT.patch b/resources/hiding_ci/linux_patches/0018-KVM-arm64-Add-support-for-KVM_MEM_USERFAULT.patch new file mode 100644 index 00000000000..bc9d608d15b --- /dev/null +++ b/resources/hiding_ci/linux_patches/0018-KVM-arm64-Add-support-for-KVM_MEM_USERFAULT.patch @@ -0,0 +1,87 @@ +From 86888e840dce0193dfb14916857df1c09749b618 Mon Sep 17 00:00:00 2001 +From: James Houghton +Date: Thu, 9 Jan 2025 20:49:22 +0000 +Subject: [PATCH 18/34] KVM: arm64: Add support for KVM_MEM_USERFAULT + +Adhering to the requirements of KVM Userfault: +1. When it is toggled on, zap the second stage with + kvm_arch_flush_shadow_memslot(). This is to respect userfault-ness. +2. When KVM_MEM_USERFAULT is enabled, restrict new second-stage mappings + to be PAGE_SIZE, just like when dirty logging is enabled. + +Do not zap the second stage when KVM_MEM_USERFAULT is disabled to remain +consistent with the behavior when dirty logging is disabled. + +Signed-off-by: James Houghton +--- + arch/arm64/kvm/Kconfig | 1 + + arch/arm64/kvm/mmu.c | 27 ++++++++++++++++++++++++++- + 2 files changed, 27 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig +index 4830d8805bed..aa0f438fba1c 100644 +--- a/arch/arm64/kvm/Kconfig ++++ b/arch/arm64/kvm/Kconfig +@@ -39,6 +39,7 @@ menuconfig KVM + select SCHED_INFO + select GUEST_PERF_EVENTS if PERF_EVENTS + select KVM_GMEM_SHARED_MEM ++ select HAVE_KVM_USERFAULT + help + Support hosting virtualized guest machines. + +diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c +index adb0681fc1c6..39d9a02db9e9 100644 +--- a/arch/arm64/kvm/mmu.c ++++ b/arch/arm64/kvm/mmu.c +@@ -1497,7 +1497,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, + kvm_pfn_t pfn; + bool logging_active = memslot_is_logging(memslot); + bool is_gmem = kvm_mem_is_private(kvm, gfn); +- bool force_pte = logging_active || is_gmem || is_protected_kvm_enabled(); ++ bool force_pte = logging_active || is_gmem || is_protected_kvm_enabled() || ++ kvm_memslot_userfault(memslot); + long vma_pagesize, fault_granule = PAGE_SIZE; + enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R; + struct kvm_pgtable *pgt; +@@ -1635,6 +1636,13 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, + mmu_seq = vcpu->kvm->mmu_invalidate_seq; + mmap_read_unlock(current->mm); + ++ if (kvm_gfn_userfault(kvm, memslot, gfn)) { ++ kvm_prepare_memory_fault_exit(vcpu, gfn << PAGE_SHIFT, ++ PAGE_SIZE, write_fault, ++ exec_fault, false, true); ++ return -EFAULT; ++ } ++ + pfn = faultin_pfn(kvm, memslot, gfn, write_fault, &writable, &page, is_gmem); + if (pfn == KVM_PFN_ERR_HWPOISON) { + kvm_send_hwpoison_signal(hva, vma_shift); +@@ -2125,6 +2133,23 @@ void kvm_arch_commit_memory_region(struct kvm *kvm, + enum kvm_mr_change change) + { + bool log_dirty_pages = new && new->flags & KVM_MEM_LOG_DIRTY_PAGES; ++ u32 new_flags = new ? new->flags : 0; ++ u32 changed_flags = (new_flags) ^ (old ? old->flags : 0); ++ ++ /* ++ * If KVM_MEM_USERFAULT has been enabled, drop all the stage-2 mappings ++ * so that we can respect userfault-ness. ++ */ ++ if ((changed_flags & KVM_MEM_USERFAULT) && ++ (new_flags & KVM_MEM_USERFAULT) && ++ change == KVM_MR_FLAGS_ONLY) ++ kvm_arch_flush_shadow_memslot(kvm, old); ++ ++ /* ++ * Nothing left to do if not toggling dirty logging. ++ */ ++ if (!(changed_flags & KVM_MEM_LOG_DIRTY_PAGES)) ++ return; + + /* + * At this point memslot has been committed and there is an +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0019-KVM-selftests-Fix-vm_mem_region_set_flags-docstring.patch b/resources/hiding_ci/linux_patches/0019-KVM-selftests-Fix-vm_mem_region_set_flags-docstring.patch new file mode 100644 index 00000000000..effde901d5b --- /dev/null +++ b/resources/hiding_ci/linux_patches/0019-KVM-selftests-Fix-vm_mem_region_set_flags-docstring.patch @@ -0,0 +1,28 @@ +From 398111201a62de89a4973295512b303d74ea0662 Mon Sep 17 00:00:00 2001 +From: James Houghton +Date: Thu, 9 Jan 2025 20:49:23 +0000 +Subject: [PATCH 19/34] KVM: selftests: Fix vm_mem_region_set_flags docstring + +`flags` is what region->region.flags gets set to. + +Signed-off-by: James Houghton +--- + tools/testing/selftests/kvm/lib/kvm_util.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c +index 33fefeb3ca44..a87988a162f1 100644 +--- a/tools/testing/selftests/kvm/lib/kvm_util.c ++++ b/tools/testing/selftests/kvm/lib/kvm_util.c +@@ -1124,7 +1124,7 @@ memslot2region(struct kvm_vm *vm, uint32_t memslot) + * + * Input Args: + * vm - Virtual Machine +- * flags - Starting guest physical address ++ * flags - Flags for the memslot + * + * Output Args: None + * +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0020-KVM-selftests-Fix-prefault_mem-logic.patch b/resources/hiding_ci/linux_patches/0020-KVM-selftests-Fix-prefault_mem-logic.patch new file mode 100644 index 00000000000..e97c522033e --- /dev/null +++ b/resources/hiding_ci/linux_patches/0020-KVM-selftests-Fix-prefault_mem-logic.patch @@ -0,0 +1,37 @@ +From 281292095132694847d44d12de0268045ae727ec Mon Sep 17 00:00:00 2001 +From: James Houghton +Date: Thu, 9 Jan 2025 20:49:24 +0000 +Subject: [PATCH 20/34] KVM: selftests: Fix prefault_mem logic + +The previous logic didn't handle the case where memory was partitioned +AND we were using a single userfaultfd. It would only prefault the first +vCPU's memory and not the rest. + +Signed-off-by: James Houghton +--- + tools/testing/selftests/kvm/demand_paging_test.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c +index 0202b78f8680..315f5c9037b4 100644 +--- a/tools/testing/selftests/kvm/demand_paging_test.c ++++ b/tools/testing/selftests/kvm/demand_paging_test.c +@@ -172,11 +172,13 @@ static void run_test(enum vm_guest_mode mode, void *arg) + memset(guest_data_prototype, 0xAB, demand_paging_size); + + if (p->uffd_mode == UFFDIO_REGISTER_MODE_MINOR) { +- num_uffds = p->single_uffd ? 1 : nr_vcpus; +- for (i = 0; i < num_uffds; i++) { ++ for (i = 0; i < nr_vcpus; i++) { + vcpu_args = &memstress_args.vcpu_args[i]; + prefault_mem(addr_gpa2alias(vm, vcpu_args->gpa), + vcpu_args->pages * memstress_args.guest_page_size); ++ if (!p->partition_vcpu_memory_access) ++ /* We prefaulted everything */ ++ break; + } + } + +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0021-KVM-selftests-Add-va_start-end-into-uffd_desc.patch b/resources/hiding_ci/linux_patches/0021-KVM-selftests-Add-va_start-end-into-uffd_desc.patch new file mode 100644 index 00000000000..67bf2b8c9d8 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0021-KVM-selftests-Add-va_start-end-into-uffd_desc.patch @@ -0,0 +1,44 @@ +From c64583011616045a4b70e34aeef6fd77e6f23ccc Mon Sep 17 00:00:00 2001 +From: James Houghton +Date: Thu, 9 Jan 2025 20:49:25 +0000 +Subject: [PATCH 21/34] KVM: selftests: Add va_start/end into uffd_desc + +This will be used for the self-test to look up which userfaultfd we +should be using when handling a KVM Userfault (in the event KVM +Userfault and userfaultfd are being used together). + +Signed-off-by: James Houghton +--- + tools/testing/selftests/kvm/include/userfaultfd_util.h | 2 ++ + tools/testing/selftests/kvm/lib/userfaultfd_util.c | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/tools/testing/selftests/kvm/include/userfaultfd_util.h b/tools/testing/selftests/kvm/include/userfaultfd_util.h +index 60f7f9d435dc..b62fecdfe745 100644 +--- a/tools/testing/selftests/kvm/include/userfaultfd_util.h ++++ b/tools/testing/selftests/kvm/include/userfaultfd_util.h +@@ -30,6 +30,8 @@ struct uffd_desc { + int *pipefds; + pthread_t *readers; + struct uffd_reader_args *reader_args; ++ void *va_start; ++ void *va_end; + }; + + struct uffd_desc *uffd_setup_demand_paging(int uffd_mode, useconds_t delay, +diff --git a/tools/testing/selftests/kvm/lib/userfaultfd_util.c b/tools/testing/selftests/kvm/lib/userfaultfd_util.c +index 7c9de8414462..93004c85bcdc 100644 +--- a/tools/testing/selftests/kvm/lib/userfaultfd_util.c ++++ b/tools/testing/selftests/kvm/lib/userfaultfd_util.c +@@ -152,6 +152,8 @@ struct uffd_desc *uffd_setup_demand_paging(int uffd_mode, useconds_t delay, + expected_ioctls, "missing userfaultfd ioctls"); + + uffd_desc->uffd = uffd; ++ uffd_desc->va_start = hva; ++ uffd_desc->va_end = (char *)hva + len; + for (i = 0; i < uffd_desc->num_readers; ++i) { + int pipes[2]; + +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0022-KVM-selftests-Inform-set_memory_region_test-of-KVM_M.patch b/resources/hiding_ci/linux_patches/0022-KVM-selftests-Inform-set_memory_region_test-of-KVM_M.patch new file mode 100644 index 00000000000..22ec8dbcc83 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0022-KVM-selftests-Inform-set_memory_region_test-of-KVM_M.patch @@ -0,0 +1,31 @@ +From 73cef3464706c3665efcbac533979e83716b0d86 Mon Sep 17 00:00:00 2001 +From: James Houghton +Date: Thu, 9 Jan 2025 20:49:27 +0000 +Subject: [PATCH 22/34] KVM: selftests: Inform set_memory_region_test of + KVM_MEM_USERFAULT + +The KVM_MEM_USERFAULT flag is supported iff KVM_CAP_USERFAULT is +available. + +Signed-off-by: James Houghton +--- + tools/testing/selftests/kvm/set_memory_region_test.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c +index bc440d5aba57..56231c02d88c 100644 +--- a/tools/testing/selftests/kvm/set_memory_region_test.c ++++ b/tools/testing/selftests/kvm/set_memory_region_test.c +@@ -364,6 +364,9 @@ static void test_invalid_memory_region_flags(void) + if (kvm_check_cap(KVM_CAP_MEMORY_ATTRIBUTES) & KVM_MEMORY_ATTRIBUTE_PRIVATE) + supported_flags |= KVM_MEM_GUEST_MEMFD; + ++ if (kvm_check_cap(KVM_CAP_USERFAULT)) ++ supported_flags |= KVM_MEM_USERFAULT; ++ + for (i = 0; i < 32; i++) { + if ((supported_flags & BIT(i)) && !(v2_only_flags & BIT(i))) + continue; +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0023-KVM-selftests-Add-KVM-Userfault-mode-to-demand_pagin.patch b/resources/hiding_ci/linux_patches/0023-KVM-selftests-Add-KVM-Userfault-mode-to-demand_pagin.patch new file mode 100644 index 00000000000..d0b3c5e7489 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0023-KVM-selftests-Add-KVM-Userfault-mode-to-demand_pagin.patch @@ -0,0 +1,381 @@ +From 6aa865fbd91cb293da61db4e11f0ce1a6de36cae Mon Sep 17 00:00:00 2001 +From: James Houghton +Date: Thu, 9 Jan 2025 20:49:26 +0000 +Subject: [PATCH 23/34] KVM: selftests: Add KVM Userfault mode to + demand_paging_test + +Add a way for the KVM_RUN loop to handle -EFAULT exits when they are for +KVM_MEMORY_EXIT_FLAG_USERFAULT. In this case, preemptively handle the +UFFDIO_COPY or UFFDIO_CONTINUE if userfaultfd is also in use. This saves +the trip through the userfaultfd poll/read/WAKE loop. + +When preemptively handling UFFDIO_COPY/CONTINUE, do so with +MODE_DONTWAKE, as there will not be a thread to wake. If a thread *does* +take the userfaultfd slow path, we will get a regular userfault, and we +will call handle_uffd_page_request() which will do a full wake-up. In +the EEXIST case, a wake-up will not occur. Make sure to call UFFDIO_WAKE +explicitly in this case. + +When handling KVM userfaults, make sure to set the bitmap with +memory_order_release. Although it wouldn't affect the functionality of +the test (because memstress doesn't actually require any particular +guest memory contents), it is what userspace normally needs to do. + +Add `-k` to set the test to use KVM Userfault. + +Add the vm_mem_region_set_flags_userfault() helper for setting +`userfault_bitmap` and KVM_MEM_USERFAULT at the same time. + +Signed-off-by: James Houghton +--- + .../selftests/kvm/demand_paging_test.c | 139 +++++++++++++++++- + .../testing/selftests/kvm/include/kvm_util.h | 5 + + tools/testing/selftests/kvm/lib/kvm_util.c | 40 ++++- + 3 files changed, 176 insertions(+), 8 deletions(-) + +diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c +index 315f5c9037b4..183c70731093 100644 +--- a/tools/testing/selftests/kvm/demand_paging_test.c ++++ b/tools/testing/selftests/kvm/demand_paging_test.c +@@ -12,7 +12,9 @@ + #include + #include + #include ++#include + #include ++#include + + #include "kvm_util.h" + #include "test_util.h" +@@ -24,11 +26,21 @@ + #ifdef __NR_userfaultfd + + static int nr_vcpus = 1; ++static int num_uffds; + static uint64_t guest_percpu_mem_size = DEFAULT_PER_VCPU_MEM_SIZE; + + static size_t demand_paging_size; ++static size_t host_page_size; + static char *guest_data_prototype; + ++static struct { ++ bool enabled; ++ int uffd_mode; /* set if userfaultfd is also in use */ ++ struct uffd_desc **uffd_descs; ++} kvm_userfault_data; ++ ++static void resolve_kvm_userfault(u64 gpa, u64 size); ++ + static void vcpu_worker(struct memstress_vcpu_args *vcpu_args) + { + struct kvm_vcpu *vcpu = vcpu_args->vcpu; +@@ -41,8 +53,22 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args) + clock_gettime(CLOCK_MONOTONIC, &start); + + /* Let the guest access its memory */ ++restart: + ret = _vcpu_run(vcpu); +- TEST_ASSERT(ret == 0, "vcpu_run failed: %d", ret); ++ if (ret < 0 && errno == EFAULT && kvm_userfault_data.enabled) { ++ /* Check for userfault. */ ++ TEST_ASSERT(run->exit_reason == KVM_EXIT_MEMORY_FAULT, ++ "Got invalid exit reason: %x", run->exit_reason); ++ TEST_ASSERT(run->memory_fault.flags == ++ KVM_MEMORY_EXIT_FLAG_USERFAULT, ++ "Got invalid memory fault exit: %llx", ++ run->memory_fault.flags); ++ resolve_kvm_userfault(run->memory_fault.gpa, ++ run->memory_fault.size); ++ goto restart; ++ } else ++ TEST_ASSERT(ret == 0, "vcpu_run failed: %d", ret); ++ + if (get_ucall(vcpu, NULL) != UCALL_SYNC) { + TEST_ASSERT(false, + "Invalid guest sync status: exit_reason=%s", +@@ -54,11 +80,10 @@ static void vcpu_worker(struct memstress_vcpu_args *vcpu_args) + ts_diff.tv_sec, ts_diff.tv_nsec); + } + +-static int handle_uffd_page_request(int uffd_mode, int uffd, +- struct uffd_msg *msg) ++static int resolve_uffd_page_request(int uffd_mode, int uffd, uint64_t addr, ++ bool wake) + { + pid_t tid = syscall(__NR_gettid); +- uint64_t addr = msg->arg.pagefault.address; + struct timespec start; + struct timespec ts_diff; + int r; +@@ -71,7 +96,7 @@ static int handle_uffd_page_request(int uffd_mode, int uffd, + copy.src = (uint64_t)guest_data_prototype; + copy.dst = addr; + copy.len = demand_paging_size; +- copy.mode = 0; ++ copy.mode = wake ? 0 : UFFDIO_COPY_MODE_DONTWAKE; + + r = ioctl(uffd, UFFDIO_COPY, ©); + /* +@@ -96,6 +121,7 @@ static int handle_uffd_page_request(int uffd_mode, int uffd, + + cont.range.start = addr; + cont.range.len = demand_paging_size; ++ cont.mode = wake ? 0 : UFFDIO_CONTINUE_MODE_DONTWAKE; + + r = ioctl(uffd, UFFDIO_CONTINUE, &cont); + /* +@@ -119,6 +145,20 @@ static int handle_uffd_page_request(int uffd_mode, int uffd, + TEST_FAIL("Invalid uffd mode %d", uffd_mode); + } + ++ if (r < 0 && wake) { ++ /* ++ * No wake-up occurs when UFFDIO_COPY/CONTINUE fails, but we ++ * have a thread waiting. Wake it up. ++ */ ++ struct uffdio_range range = {0}; ++ ++ range.start = addr; ++ range.len = demand_paging_size; ++ ++ TEST_ASSERT(ioctl(uffd, UFFDIO_WAKE, &range) == 0, ++ "UFFDIO_WAKE failed: 0x%lx", addr); ++ } ++ + ts_diff = timespec_elapsed(start); + + PER_PAGE_DEBUG("UFFD page-in %d \t%ld ns\n", tid, +@@ -129,6 +169,58 @@ static int handle_uffd_page_request(int uffd_mode, int uffd, + return 0; + } + ++static int handle_uffd_page_request(int uffd_mode, int uffd, ++ struct uffd_msg *msg) ++{ ++ uint64_t addr = msg->arg.pagefault.address; ++ ++ return resolve_uffd_page_request(uffd_mode, uffd, addr, true); ++} ++ ++static void resolve_kvm_userfault(u64 gpa, u64 size) ++{ ++ struct kvm_vm *vm = memstress_args.vm; ++ struct userspace_mem_region *region; ++ unsigned long *bitmap_chunk; ++ u64 page, gpa_offset; ++ ++ region = (struct userspace_mem_region *) userspace_mem_region_find( ++ vm, gpa, (gpa + size - 1)); ++ ++ if (kvm_userfault_data.uffd_mode) { ++ /* ++ * Resolve userfaults early, without needing to read them ++ * off the userfaultfd. ++ */ ++ uint64_t hva = (uint64_t)addr_gpa2hva(vm, gpa); ++ struct uffd_desc **descs = kvm_userfault_data.uffd_descs; ++ int i, fd; ++ ++ for (i = 0; i < num_uffds; ++i) ++ if (hva >= (uint64_t)descs[i]->va_start && ++ hva < (uint64_t)descs[i]->va_end) ++ break; ++ ++ TEST_ASSERT(i < num_uffds, ++ "Did not find userfaultfd for hva: %lx", hva); ++ ++ fd = kvm_userfault_data.uffd_descs[i]->uffd; ++ resolve_uffd_page_request(kvm_userfault_data.uffd_mode, fd, ++ hva, false); ++ } else { ++ uint64_t hva = (uint64_t)addr_gpa2hva(vm, gpa); ++ ++ memcpy((char *)hva, guest_data_prototype, demand_paging_size); ++ } ++ ++ gpa_offset = gpa - region->region.guest_phys_addr; ++ page = gpa_offset / host_page_size; ++ bitmap_chunk = (unsigned long *)region->region.userfault_bitmap + ++ page / BITS_PER_LONG; ++ atomic_fetch_and_explicit((_Atomic unsigned long *)bitmap_chunk, ++ ~(1ul << (page % BITS_PER_LONG)), memory_order_release); ++} ++ + struct test_params { + int uffd_mode; + bool single_uffd; +@@ -136,6 +228,7 @@ struct test_params { + int readers_per_uffd; + enum vm_mem_backing_src_type src_type; + bool partition_vcpu_memory_access; ++ bool kvm_userfault; + }; + + static void prefault_mem(void *alias, uint64_t len) +@@ -149,6 +242,25 @@ static void prefault_mem(void *alias, uint64_t len) + } + } + ++static void enable_userfault(struct kvm_vm *vm, int slots) ++{ ++ for (int i = 0; i < slots; ++i) { ++ int slot = MEMSTRESS_MEM_SLOT_INDEX + i; ++ struct userspace_mem_region *region; ++ unsigned long *userfault_bitmap; ++ int flags = KVM_MEM_USERFAULT; ++ ++ region = memslot2region(vm, slot); ++ userfault_bitmap = bitmap_zalloc(region->mmap_size / ++ host_page_size); ++ /* everything is userfault initially */ ++ memset(userfault_bitmap, -1, region->mmap_size / host_page_size / CHAR_BIT); ++ printf("Setting bitmap: %p\n", userfault_bitmap); ++ vm_mem_region_set_flags_userfault(vm, slot, flags, ++ userfault_bitmap); ++ } ++} ++ + static void run_test(enum vm_guest_mode mode, void *arg) + { + struct memstress_vcpu_args *vcpu_args; +@@ -159,12 +271,13 @@ static void run_test(enum vm_guest_mode mode, void *arg) + struct timespec ts_diff; + double vcpu_paging_rate; + struct kvm_vm *vm; +- int i, num_uffds = 0; ++ int i; + + vm = memstress_create_vm(mode, nr_vcpus, guest_percpu_mem_size, 1, + p->src_type, p->partition_vcpu_memory_access); + + demand_paging_size = get_backing_src_pagesz(p->src_type); ++ host_page_size = getpagesize(); + + guest_data_prototype = malloc(demand_paging_size); + TEST_ASSERT(guest_data_prototype, +@@ -208,6 +321,14 @@ static void run_test(enum vm_guest_mode mode, void *arg) + } + } + ++ if (p->kvm_userfault) { ++ TEST_REQUIRE(kvm_has_cap(KVM_CAP_USERFAULT)); ++ kvm_userfault_data.enabled = true; ++ kvm_userfault_data.uffd_mode = p->uffd_mode; ++ kvm_userfault_data.uffd_descs = uffd_descs; ++ enable_userfault(vm, 1); ++ } ++ + pr_info("Finished creating vCPUs and starting uffd threads\n"); + + clock_gettime(CLOCK_MONOTONIC, &start); +@@ -265,6 +386,7 @@ static void help(char *name) + printf(" -v: specify the number of vCPUs to run.\n"); + printf(" -o: Overlap guest memory accesses instead of partitioning\n" + " them into a separate region of memory for each vCPU.\n"); ++ printf(" -k: Use KVM Userfault\n"); + puts(""); + exit(0); + } +@@ -283,7 +405,7 @@ int main(int argc, char *argv[]) + + guest_modes_append_default(); + +- while ((opt = getopt(argc, argv, "ahom:u:d:b:s:v:c:r:")) != -1) { ++ while ((opt = getopt(argc, argv, "ahokm:u:d:b:s:v:c:r:")) != -1) { + switch (opt) { + case 'm': + guest_modes_cmdline(optarg); +@@ -326,6 +448,9 @@ int main(int argc, char *argv[]) + "Invalid number of readers per uffd %d: must be >=1", + p.readers_per_uffd); + break; ++ case 'k': ++ p.kvm_userfault = true; ++ break; + case 'h': + default: + help(argv[0]); +diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h +index 4c4e5a847f67..0d49a9ce832a 100644 +--- a/tools/testing/selftests/kvm/include/kvm_util.h ++++ b/tools/testing/selftests/kvm/include/kvm_util.h +@@ -582,6 +582,8 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, + void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, + uint64_t guest_paddr, uint32_t slot, uint64_t npages, + uint32_t flags, int guest_memfd_fd, uint64_t guest_memfd_offset); ++struct userspace_mem_region * ++userspace_mem_region_find(struct kvm_vm *vm, uint64_t start, uint64_t end); + + #ifndef vm_arch_has_protected_memory + static inline bool vm_arch_has_protected_memory(struct kvm_vm *vm) +@@ -591,6 +593,9 @@ static inline bool vm_arch_has_protected_memory(struct kvm_vm *vm) + #endif + + void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); ++void vm_mem_region_set_flags_userfault(struct kvm_vm *vm, uint32_t slot, ++ uint32_t flags, ++ unsigned long *userfault_bitmap); + void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa); + void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot); + struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id); +diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c +index a87988a162f1..a8f6b949ac59 100644 +--- a/tools/testing/selftests/kvm/lib/kvm_util.c ++++ b/tools/testing/selftests/kvm/lib/kvm_util.c +@@ -634,7 +634,7 @@ void kvm_parse_vcpu_pinning(const char *pcpus_string, uint32_t vcpu_to_pcpu[], + * of the regions is returned. Null is returned only when no overlapping + * region exists. + */ +-static struct userspace_mem_region * ++struct userspace_mem_region * + userspace_mem_region_find(struct kvm_vm *vm, uint64_t start, uint64_t end) + { + struct rb_node *node; +@@ -1149,6 +1149,44 @@ void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags) + ret, errno, slot, flags); + } + ++/* ++ * VM Memory Region Flags Set with a userfault bitmap ++ * ++ * Input Args: ++ * vm - Virtual Machine ++ * flags - Flags for the memslot ++ * userfault_bitmap - The bitmap to use for KVM_MEM_USERFAULT ++ * ++ * Output Args: None ++ * ++ * Return: None ++ * ++ * Sets the flags of the memory region specified by the value of slot, ++ * to the values given by flags. This helper adds a way to provide a ++ * userfault_bitmap. ++ */ ++void vm_mem_region_set_flags_userfault(struct kvm_vm *vm, uint32_t slot, ++ uint32_t flags, ++ unsigned long *userfault_bitmap) ++{ ++ int ret; ++ struct userspace_mem_region *region; ++ ++ region = memslot2region(vm, slot); ++ ++ TEST_ASSERT(!userfault_bitmap ^ (flags & KVM_MEM_USERFAULT), ++ "KVM_MEM_USERFAULT must be specified with a bitmap"); ++ ++ region->region.flags = flags; ++ region->region.userfault_bitmap = (__u64)userfault_bitmap; ++ ++ ret = __vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION2, ®ion->region); ++ ++ TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION2 IOCTL failed,\n" ++ " rc: %i errno: %i slot: %u flags: 0x%x", ++ ret, errno, slot, flags); ++} ++ + /* + * VM Memory Region Move + * +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0024-KVM-selftests-Add-KVM_MEM_USERFAULT-guest_memfd-togg.patch b/resources/hiding_ci/linux_patches/0024-KVM-selftests-Add-KVM_MEM_USERFAULT-guest_memfd-togg.patch new file mode 100644 index 00000000000..36b151a0f3c --- /dev/null +++ b/resources/hiding_ci/linux_patches/0024-KVM-selftests-Add-KVM_MEM_USERFAULT-guest_memfd-togg.patch @@ -0,0 +1,65 @@ +From be1d7a3ce1b177d64198b8e060bc9a3844f462cd Mon Sep 17 00:00:00 2001 +From: James Houghton +Date: Thu, 9 Jan 2025 20:49:28 +0000 +Subject: [PATCH 24/34] KVM: selftests: Add KVM_MEM_USERFAULT + guest_memfd + toggle tests + +Make sure KVM_MEM_USERFAULT can be toggled on and off for +KVM_MEM_GUEST_MEMFD memslots. + +Signed-off-by: James Houghton +--- + .../selftests/kvm/set_memory_region_test.c | 30 +++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c +index 56231c02d88c..95d315b976df 100644 +--- a/tools/testing/selftests/kvm/set_memory_region_test.c ++++ b/tools/testing/selftests/kvm/set_memory_region_test.c +@@ -608,6 +608,35 @@ static void test_mmio_during_vectoring(void) + } + #endif + ++static void test_private_memory_region_userfault(void) ++{ ++ struct kvm_vm *vm; ++ int memfd; ++ ++ pr_info("Testing toggling KVM_MEM_USERFAULT on KVM_MEM_GUEST_MEMFD memory regions\n"); ++ ++ vm = vm_create_barebones_type(KVM_X86_SW_PROTECTED_VM); ++ ++ test_invalid_guest_memfd(vm, vm->kvm_fd, 0, "KVM fd should fail"); ++ test_invalid_guest_memfd(vm, vm->fd, 0, "VM's fd should fail"); ++ ++ memfd = vm_create_guest_memfd(vm, MEM_REGION_SIZE, 0); ++ ++ vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_GUEST_MEMFD, ++ MEM_REGION_GPA, MEM_REGION_SIZE, 0, memfd, 0); ++ ++ vm_set_user_memory_region2(vm, MEM_REGION_SLOT, ++ KVM_MEM_GUEST_MEMFD | KVM_MEM_USERFAULT, ++ MEM_REGION_GPA, MEM_REGION_SIZE, 0, memfd, 0); ++ ++ vm_set_user_memory_region2(vm, MEM_REGION_SLOT, KVM_MEM_GUEST_MEMFD, ++ MEM_REGION_GPA, MEM_REGION_SIZE, 0, memfd, 0); ++ ++ close(memfd); ++ ++ kvm_vm_free(vm); ++} ++ + int main(int argc, char *argv[]) + { + #ifdef __x86_64__ +@@ -633,6 +662,7 @@ int main(int argc, char *argv[]) + (kvm_check_cap(KVM_CAP_VM_TYPES) & BIT(KVM_X86_SW_PROTECTED_VM))) { + test_add_private_memory_region(); + test_add_overlapping_private_memory_regions(); ++ test_private_memory_region_userfault(); + } else { + pr_info("Skipping tests for KVM_MEM_GUEST_MEMFD memory regions\n"); + } +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0025-KVM-Documentation-Add-KVM_CAP_USERFAULT-and-KVM_MEM_.patch b/resources/hiding_ci/linux_patches/0025-KVM-Documentation-Add-KVM_CAP_USERFAULT-and-KVM_MEM_.patch new file mode 100644 index 00000000000..68aa5a42ad1 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0025-KVM-Documentation-Add-KVM_CAP_USERFAULT-and-KVM_MEM_.patch @@ -0,0 +1,76 @@ +From fb4c74191df7821bf047af099473dd8f20948b43 Mon Sep 17 00:00:00 2001 +From: James Houghton +Date: Thu, 9 Jan 2025 20:49:29 +0000 +Subject: [PATCH 25/34] KVM: Documentation: Add KVM_CAP_USERFAULT and + KVM_MEM_USERFAULT details + +Include the note about memory ordering when clearing bits in +userfault_bitmap, as it may not be obvious for users. + +Signed-off-by: James Houghton +Reviewed-by: Bagas Sanjaya +--- + Documentation/virt/kvm/api.rst | 33 ++++++++++++++++++++++++++++++++- + 1 file changed, 32 insertions(+), 1 deletion(-) + +diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst +index 2b52eb77e29c..3ec3d0bdb18a 100644 +--- a/Documentation/virt/kvm/api.rst ++++ b/Documentation/virt/kvm/api.rst +@@ -6287,7 +6287,8 @@ bounds checks apply (use common sense). + __u64 guest_memfd_offset; + __u32 guest_memfd; + __u32 pad1; +- __u64 pad2[14]; ++ __u64 userfault_bitmap; ++ __u64 pad2[13]; + }; + + A KVM_MEM_GUEST_MEMFD region _must_ have a valid guest_memfd (private memory) and +@@ -6303,6 +6304,25 @@ state. At VM creation time, all memory is shared, i.e. the PRIVATE attribute + is '0' for all gfns. Userspace can control whether memory is shared/private by + toggling KVM_MEMORY_ATTRIBUTE_PRIVATE via KVM_SET_MEMORY_ATTRIBUTES as needed. + ++When the KVM_MEM_USERFAULT flag is set, userfault_bitmap points to the starting ++address for the bitmap that controls if vCPU memory faults should immediately ++exit to userspace. If an invalid pointer is provided, at fault time, KVM_RUN ++will return -EFAULT. KVM_MEM_USERFAULT is only supported when ++KVM_CAP_USERFAULT is supported. ++ ++userfault_bitmap should point to an array of longs where each bit in the array ++linearly corresponds to a single gfn. Bit 0 in userfault_bitmap corresponds to ++guest_phys_addr, bit 1 corresponds to guest_phys_addr + PAGE_SIZE, etc. If the ++bit for a page is set, any vCPU access to that page will exit to userspace with ++KVM_MEMORY_EXIT_FLAG_USERFAULT. ++ ++Setting bits in userfault_bitmap has no effect on pages that have already been ++mapped by KVM until KVM_MEM_USERFAULT is disabled and re-enabled again. ++ ++Clearing bits in userfault_bitmap should usually be done with a store-release ++if changes to guest memory are being made available to the guest via ++userfault_bitmap. ++ + S390: + ^^^^^ + +@@ -8258,6 +8278,17 @@ KVM exits with the register state of either the L1 or L2 guest + depending on which executed at the time of an exit. Userspace must + take care to differentiate between these cases. + ++7.37 KVM_CAP_USERFAULT ++---------------------- ++ ++:Architectures: x86, arm64 ++:Returns: Informational only, -EINVAL on direct KVM_ENABLE_CAP. ++ ++The presence of this capability indicates that KVM_SET_USER_MEMORY_REGION2 will ++accept KVM_MEM_USERFAULT as a valid memslot flag. ++ ++See KVM_SET_USER_MEMORY_REGION2 for more details. ++ + 8. Other capabilities. + ====================== + +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0026-KVM-guest_memfd-add-generic-population-via-write.patch b/resources/hiding_ci/linux_patches/0026-KVM-guest_memfd-add-generic-population-via-write.patch new file mode 100644 index 00000000000..f7c1cce60f2 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0026-KVM-guest_memfd-add-generic-population-via-write.patch @@ -0,0 +1,141 @@ +From dda48e07b48f344c57d8ed90ddad7e01c26f7952 Mon Sep 17 00:00:00 2001 +From: Nikita Kalyazin +Date: Fri, 29 Nov 2024 11:51:02 +0000 +Subject: [PATCH 26/34] KVM: guest_memfd: add generic population via write + +write syscall populates guest_memfd with user-supplied data in a generic +way, ie no vendor-specific preparation is performed. This is supposed +to be used in non-CoCo setups where guest memory is not +hardware-encrypted. + +The following behaviour is implemented: + - only page-aligned count and offset are allowed + - if the memory is already allocated, the call will successfully + populate it + - if the memory is not allocated, the call will both allocate and + populate + - if the memory is already populated, the call will not repopulate it + +Signed-off-by: Nikita Kalyazin +--- + virt/kvm/guest_memfd.c | 94 ++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 91 insertions(+), 3 deletions(-) + +diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c +index 291d647a5c80..5abb6d52a375 100644 +--- a/virt/kvm/guest_memfd.c ++++ b/virt/kvm/guest_memfd.c +@@ -432,12 +432,97 @@ static int kvm_gmem_mmap(struct file *file, struct vm_area_struct *vma) + + return 0; + } +-#else +-#define kvm_gmem_mmap NULL ++ ++static ssize_t kvm_kmem_gmem_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *offset) ++{ ++ pgoff_t start, end, index; ++ ssize_t ret = 0; ++ ++ if (!PAGE_ALIGNED(*offset) || !PAGE_ALIGNED(count)) ++ return -EINVAL; ++ ++ if (*offset + count > i_size_read(file_inode(file))) ++ return -EINVAL; ++ ++ if (!buf) ++ return -EINVAL; ++ ++ start = *offset >> PAGE_SHIFT; ++ end = (*offset + count) >> PAGE_SHIFT; ++ ++ filemap_invalidate_lock_shared(file->f_mapping); ++ ++ for (index = start; index < end; ) { ++ struct folio *folio; ++ void *vaddr; ++ pgoff_t buf_offset = (index - start) << PAGE_SHIFT; ++ ++ if (signal_pending(current)) { ++ ret = -EINTR; ++ goto out; ++ } ++ ++ folio = kvm_gmem_get_folio(file_inode(file), index); ++ if (IS_ERR(folio)) { ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (folio_test_hwpoison(folio)) { ++ folio_unlock(folio); ++ folio_put(folio); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ /* No support for huge pages. */ ++ if (WARN_ON_ONCE(folio_test_large(folio))) { ++ folio_unlock(folio); ++ folio_put(folio); ++ ret = -EFAULT; ++ goto out; ++ } ++ ++ if (folio_test_uptodate(folio)) { ++ folio_unlock(folio); ++ folio_put(folio); ++ ret = -ENOSPC; ++ goto out; ++ } ++ ++ folio_unlock(folio); ++ ++ vaddr = kmap_local_folio(folio, 0); ++ ret = copy_from_user(vaddr, buf + buf_offset, PAGE_SIZE); ++ kunmap_local(vaddr); ++ if (ret) { ++ ret = -EINVAL; ++ folio_put(folio); ++ goto out; ++ } ++ ++ kvm_gmem_mark_prepared(folio); ++ folio_put(folio); ++ ++ index = folio_next_index(folio); ++ *offset += PAGE_SIZE; ++ } ++ ++out: ++ filemap_invalidate_unlock_shared(file->f_mapping); ++ ++ return ret && start == (*offset >> PAGE_SHIFT) ? ++ ret : *offset - (start << PAGE_SHIFT); ++} + #endif /* CONFIG_KVM_GMEM_SHARED_MEM */ + + static struct file_operations kvm_gmem_fops = { +- .mmap = kvm_gmem_mmap, ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM ++ .mmap = kvm_gmem_mmap, ++ .llseek = default_llseek, ++ .write = kvm_kmem_gmem_write, ++#endif /* CONFIG_KVM_GMEM_SHARED_MEM */ + .open = generic_file_open, + .release = kvm_gmem_release, + .fallocate = kvm_gmem_fallocate, +@@ -557,6 +642,9 @@ static int __kvm_gmem_create(struct kvm *kvm, loff_t size, u64 flags) + } + + file->f_flags |= O_LARGEFILE; ++#ifdef CONFIG_KVM_GMEM_SHARED_MEM ++ file->f_mode |= FMODE_LSEEK | FMODE_PWRITE; ++#endif /* CONFIG_KVM_GMEM_SHARED_MEM */ + + inode = file->f_inode; + WARN_ON(file->f_mapping != inode->i_mapping); +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0027-KVM-selftests-update-guest_memfd-write-tests.patch b/resources/hiding_ci/linux_patches/0027-KVM-selftests-update-guest_memfd-write-tests.patch new file mode 100644 index 00000000000..6062f6fd982 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0027-KVM-selftests-update-guest_memfd-write-tests.patch @@ -0,0 +1,126 @@ +From 120635067e2d910bf96a53e3b7e2f2d5be19af7e Mon Sep 17 00:00:00 2001 +From: Nikita Kalyazin +Date: Fri, 29 Nov 2024 11:57:58 +0000 +Subject: [PATCH 27/34] KVM: selftests: update guest_memfd write tests + +This is to reflect that the write syscall is now implemented for +guest_memfd. + +Signed-off-by: Nikita Kalyazin +--- + .../testing/selftests/kvm/guest_memfd_test.c | 85 +++++++++++++++++-- + 1 file changed, 79 insertions(+), 6 deletions(-) + +diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c +index 38c501e49e0e..b07221aa54c9 100644 +--- a/tools/testing/selftests/kvm/guest_memfd_test.c ++++ b/tools/testing/selftests/kvm/guest_memfd_test.c +@@ -20,18 +20,90 @@ + #include "kvm_util.h" + #include "test_util.h" + +-static void test_file_read_write(int fd) ++static void test_file_read(int fd) + { + char buf[64]; + + TEST_ASSERT(read(fd, buf, sizeof(buf)) < 0, + "read on a guest_mem fd should fail"); +- TEST_ASSERT(write(fd, buf, sizeof(buf)) < 0, +- "write on a guest_mem fd should fail"); + TEST_ASSERT(pread(fd, buf, sizeof(buf), 0) < 0, + "pread on a guest_mem fd should fail"); +- TEST_ASSERT(pwrite(fd, buf, sizeof(buf), 0) < 0, +- "pwrite on a guest_mem fd should fail"); ++} ++ ++static void test_file_write(int fd, size_t total_size) ++{ ++ size_t page_size = getpagesize(); ++ void *buf = NULL; ++ int ret; ++ ++ ret = posix_memalign(&buf, page_size, total_size); ++ TEST_ASSERT_EQ(ret, 0); ++ ++ /* Check arguments correctness checks work as expected */ ++ ++ ret = pwrite(fd, buf, page_size - 1, 0); ++ TEST_ASSERT(ret == -1, "write unaligned count on a guest_mem fd should fail"); ++ TEST_ASSERT_EQ(errno, EINVAL); ++ ++ ret = pwrite(fd, buf, page_size, 1); ++ TEST_ASSERT(ret == -1, "write unaligned offset on a guest_mem fd should fail"); ++ TEST_ASSERT_EQ(errno, EINVAL); ++ ++ ret = pwrite(fd, buf, page_size, total_size); ++ TEST_ASSERT(ret == -1, "writing past the file size on a guest_mem fd should fail"); ++ TEST_ASSERT_EQ(errno, EINVAL); ++ ++ ret = pwrite(fd, NULL, page_size, 0); ++ TEST_ASSERT(ret == -1, "supplying a NULL buffer when writing a guest_mem fd should fail"); ++ TEST_ASSERT_EQ(errno, EINVAL); ++ ++ /* Check double population is not allowed */ ++ ++ ret = pwrite(fd, buf, page_size, 0); ++ TEST_ASSERT(ret == page_size, "page-aligned write on a guest_mem fd should succeed"); ++ ++ ret = pwrite(fd, buf, page_size, 0); ++ TEST_ASSERT(ret == -1, "write on already populated guest_mem fd should fail"); ++ TEST_ASSERT_EQ(errno, ENOSPC); ++ ++ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, 0, page_size); ++ TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) should succeed"); ++ ++ /* Check population is allowed again after punching a hole */ ++ ++ ret = pwrite(fd, buf, page_size, 0); ++ TEST_ASSERT(ret == page_size, "page-aligned write on a punched guest_mem fd should succeed"); ++ ++ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, 0, page_size); ++ TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) should succeed"); ++ ++ /* Check population of already allocated memory is allowed */ ++ ++ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE, 0, page_size); ++ TEST_ASSERT(!ret, "fallocate with aligned offset and size should succeed"); ++ ++ ret = pwrite(fd, buf, page_size, 0); ++ TEST_ASSERT(ret == page_size, "write on a preallocated guest_mem fd should succeed"); ++ ++ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, 0, page_size); ++ TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) should succeed"); ++ ++ /* Check population works until an already populated page is encountered */ ++ ++ ret = pwrite(fd, buf, total_size, 0); ++ TEST_ASSERT(ret == total_size, "page-aligned write on a guest_mem fd should succeed"); ++ ++ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, 0, page_size); ++ TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) should succeed"); ++ ++ ret = pwrite(fd, buf, total_size, 0); ++ TEST_ASSERT(ret == page_size, "write on a guest_mem fd should not overwrite data"); ++ ++ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, 0, total_size); ++ TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) should succeed"); ++ ++ ++ free(buf); + } + + static void test_mmap_allowed(int fd, size_t total_size) +@@ -233,7 +305,8 @@ void test_vm_type(unsigned long type, bool is_shared) + + fd = vm_create_guest_memfd(vm, total_size, 0); + +- test_file_read_write(fd); ++ test_file_read(fd); ++ test_file_write(fd, total_size); + + if (is_shared) + test_mmap_allowed(fd, total_size); +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0028-mm-userfaultfd-generic-continue-for-non-hugetlbfs.patch b/resources/hiding_ci/linux_patches/0028-mm-userfaultfd-generic-continue-for-non-hugetlbfs.patch new file mode 100644 index 00000000000..e610f502a9b --- /dev/null +++ b/resources/hiding_ci/linux_patches/0028-mm-userfaultfd-generic-continue-for-non-hugetlbfs.patch @@ -0,0 +1,153 @@ +From 38fb84551a238b98a622433157fb2537ecb5611e Mon Sep 17 00:00:00 2001 +From: Nikita Kalyazin +Date: Mon, 31 Mar 2025 10:15:35 +0000 +Subject: [PATCH 28/34] mm: userfaultfd: generic continue for non hugetlbfs + +Remove shmem-specific code from UFFDIO_CONTINUE implementation for +non-huge pages by calling vm_ops->fault(). A new VMF flag, +FAULT_FLAG_USERFAULT_CONTINUE, is introduced to avoid recursive call to +handle_userfault(). + +Suggested-by: James Houghton +Signed-off-by: Nikita Kalyazin +--- + include/linux/mm_types.h | 4 ++++ + mm/hugetlb.c | 2 +- + mm/shmem.c | 9 ++++++--- + mm/userfaultfd.c | 37 +++++++++++++++++++++++++++---------- + 4 files changed, 38 insertions(+), 14 deletions(-) + +diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h +index 0234f14f2aa6..2f26ee9742bf 100644 +--- a/include/linux/mm_types.h ++++ b/include/linux/mm_types.h +@@ -1429,6 +1429,9 @@ enum tlb_flush_reason { + * @FAULT_FLAG_ORIG_PTE_VALID: whether the fault has vmf->orig_pte cached. + * We should only access orig_pte if this flag set. + * @FAULT_FLAG_VMA_LOCK: The fault is handled under VMA lock. ++ * @FAULT_FLAG_USERFAULT_CONTINUE: The fault handler must not call userfaultfd ++ * minor handler as it is being called by the ++ * userfaultfd code itself. + * + * About @FAULT_FLAG_ALLOW_RETRY and @FAULT_FLAG_TRIED: we can specify + * whether we would allow page faults to retry by specifying these two +@@ -1467,6 +1470,7 @@ enum fault_flag { + FAULT_FLAG_UNSHARE = 1 << 10, + FAULT_FLAG_ORIG_PTE_VALID = 1 << 11, + FAULT_FLAG_VMA_LOCK = 1 << 12, ++ FAULT_FLAG_USERFAULT_CONTINUE = 1 << 13, + }; + + typedef unsigned int __bitwise zap_flags_t; +diff --git a/mm/hugetlb.c b/mm/hugetlb.c +index 97930d44d460..c004cfdcd4e2 100644 +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -6228,7 +6228,7 @@ static vm_fault_t hugetlb_no_page(struct address_space *mapping, + } + + /* Check for page in userfault range. */ +- if (userfaultfd_minor(vma)) { ++ if (userfaultfd_minor(vma) && !(vmf->flags & FAULT_FLAG_USERFAULT_CONTINUE)) { + folio_unlock(folio); + folio_put(folio); + /* See comment in userfaultfd_missing() block above */ +diff --git a/mm/shmem.c b/mm/shmem.c +index 1ede0800e846..b4159303fe59 100644 +--- a/mm/shmem.c ++++ b/mm/shmem.c +@@ -2467,7 +2467,8 @@ static int shmem_get_folio_gfp(struct inode *inode, pgoff_t index, + fault_mm = vma ? vma->vm_mm : NULL; + + folio = filemap_get_entry(inode->i_mapping, index); +- if (folio && vma && userfaultfd_minor(vma)) { ++ if (folio && vma && userfaultfd_minor(vma) && ++ !(vmf->flags & FAULT_FLAG_USERFAULT_CONTINUE)) { + if (!xa_is_value(folio)) + folio_put(folio); + *fault_type = handle_userfault(vmf, VM_UFFD_MINOR); +@@ -2727,6 +2728,8 @@ static vm_fault_t shmem_falloc_wait(struct vm_fault *vmf, struct inode *inode) + static vm_fault_t shmem_fault(struct vm_fault *vmf) + { + struct inode *inode = file_inode(vmf->vma->vm_file); ++ enum sgp_type sgp = vmf->flags & FAULT_FLAG_USERFAULT_CONTINUE ? ++ SGP_NOALLOC : SGP_CACHE; + gfp_t gfp = mapping_gfp_mask(inode->i_mapping); + struct folio *folio = NULL; + vm_fault_t ret = 0; +@@ -2743,8 +2746,8 @@ static vm_fault_t shmem_fault(struct vm_fault *vmf) + } + + WARN_ON_ONCE(vmf->page != NULL); +- err = shmem_get_folio_gfp(inode, vmf->pgoff, 0, &folio, SGP_CACHE, +- gfp, vmf, &ret); ++ err = shmem_get_folio_gfp(inode, vmf->pgoff, 0, &folio, sgp, gfp, vmf, ++ &ret); + if (err) + return vmf_error(err); + if (folio) { +diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c +index d06453fa8aba..4b3dbc7dac64 100644 +--- a/mm/userfaultfd.c ++++ b/mm/userfaultfd.c +@@ -380,30 +380,47 @@ static int mfill_atomic_pte_zeropage(pmd_t *dst_pmd, + return ret; + } + +-/* Handles UFFDIO_CONTINUE for all shmem VMAs (shared or private). */ ++/* Handles UFFDIO_CONTINUE for all VMAs */ + static int mfill_atomic_pte_continue(pmd_t *dst_pmd, + struct vm_area_struct *dst_vma, + unsigned long dst_addr, + uffd_flags_t flags) + { +- struct inode *inode = file_inode(dst_vma->vm_file); +- pgoff_t pgoff = linear_page_index(dst_vma, dst_addr); + struct folio *folio; + struct page *page; + int ret; ++ struct vm_fault vmf = { ++ .vma = dst_vma, ++ .address = dst_addr, ++ .flags = FAULT_FLAG_WRITE | FAULT_FLAG_REMOTE | ++ FAULT_FLAG_USERFAULT_CONTINUE, ++ .pte = NULL, ++ .page = NULL, ++ .pgoff = linear_page_index(dst_vma, dst_addr), ++ }; ++ ++ if (!dst_vma->vm_ops || !dst_vma->vm_ops->fault) ++ return -EINVAL; + +- ret = shmem_get_folio(inode, pgoff, 0, &folio, SGP_NOALLOC); +- /* Our caller expects us to return -EFAULT if we failed to find folio */ +- if (ret == -ENOENT) ++retry: ++ ret = dst_vma->vm_ops->fault(&vmf); ++ if (ret & VM_FAULT_ERROR) { + ret = -EFAULT; +- if (ret) + goto out; +- if (!folio) { +- ret = -EFAULT; ++ } ++ ++ if (ret & VM_FAULT_NOPAGE) { ++ ret = -EAGAIN; + goto out; + } + +- page = folio_file_page(folio, pgoff); ++ if (ret & VM_FAULT_RETRY) ++ goto retry; ++ ++ page = vmf.page; ++ folio = page_folio(page); ++ BUG_ON(!folio); ++ + if (PageHWPoison(page)) { + ret = -EIO; + goto out_release; +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0029-mm-provide-can_userfault-vma-operation.patch b/resources/hiding_ci/linux_patches/0029-mm-provide-can_userfault-vma-operation.patch new file mode 100644 index 00000000000..0f939d066d1 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0029-mm-provide-can_userfault-vma-operation.patch @@ -0,0 +1,95 @@ +From bcfff7f58b747aac6f27a51ce54efe5eae4b02f9 Mon Sep 17 00:00:00 2001 +From: Nikita Kalyazin +Date: Fri, 4 Apr 2025 14:15:18 +0000 +Subject: [PATCH 29/34] mm: provide can_userfault vma operation + +The new operation allows to decouple the userfaulfd code from +dependencies to VMA types, specifically, shmem and hugetlb. The +vm_flags bitmap argument is processed with "any" logic, meaning if the +VMA type supports any of the flags set, it returns true. This is to +avoid multiple calls when checking for __VM_UFFD_FLAGS. + +Signed-off-by: Nikita Kalyazin +--- + include/linux/mm.h | 5 +++++ + mm/hugetlb.c | 7 +++++++ + mm/shmem.c | 8 ++++++++ + 3 files changed, 20 insertions(+) + +diff --git a/include/linux/mm.h b/include/linux/mm.h +index 8483e09aeb2c..488d721d8542 100644 +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -680,6 +680,11 @@ struct vm_operations_struct { + */ + struct page *(*find_special_page)(struct vm_area_struct *vma, + unsigned long addr); ++ /* ++ * True if the VMA supports userfault at least for one of the vm_flags ++ */ ++ bool (*can_userfault)(struct vm_area_struct *vma, ++ unsigned long vm_flags); + }; + + #ifdef CONFIG_NUMA_BALANCING +diff --git a/mm/hugetlb.c b/mm/hugetlb.c +index c004cfdcd4e2..f3901c11e1fd 100644 +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -5143,6 +5143,12 @@ static unsigned long hugetlb_vm_op_pagesize(struct vm_area_struct *vma) + return huge_page_size(hstate_vma(vma)); + } + ++static bool hugetlb_vm_op_can_userfault(struct vm_area_struct *vma, ++ unsigned long vm_flags) ++{ ++ return true; ++} ++ + /* + * We cannot handle pagefaults against hugetlb pages at all. They cause + * handle_mm_fault() to try to instantiate regular-sized pages in the +@@ -5168,6 +5174,7 @@ const struct vm_operations_struct hugetlb_vm_ops = { + .close = hugetlb_vm_op_close, + .may_split = hugetlb_vm_op_split, + .pagesize = hugetlb_vm_op_pagesize, ++ .can_userfault = hugetlb_vm_op_can_userfault, + }; + + static pte_t make_huge_pte(struct vm_area_struct *vma, struct page *page, +diff --git a/mm/shmem.c b/mm/shmem.c +index b4159303fe59..0b9e19abd1e9 100644 +--- a/mm/shmem.c ++++ b/mm/shmem.c +@@ -2891,6 +2891,12 @@ static struct mempolicy *shmem_get_policy(struct vm_area_struct *vma, + return mpol_shared_policy_lookup(&SHMEM_I(inode)->policy, index); + } + ++static bool shmem_can_userfault(struct vm_area_struct *vma, ++ unsigned long vm_flags) ++{ ++ return true; ++} ++ + static struct mempolicy *shmem_get_pgoff_policy(struct shmem_inode_info *info, + pgoff_t index, unsigned int order, pgoff_t *ilx) + { +@@ -5309,6 +5315,7 @@ static const struct vm_operations_struct shmem_vm_ops = { + .set_policy = shmem_set_policy, + .get_policy = shmem_get_policy, + #endif ++ .can_userfault = shmem_can_userfault, + }; + + static const struct vm_operations_struct shmem_anon_vm_ops = { +@@ -5318,6 +5325,7 @@ static const struct vm_operations_struct shmem_anon_vm_ops = { + .set_policy = shmem_set_policy, + .get_policy = shmem_get_policy, + #endif ++ .can_userfault = shmem_can_userfault, + }; + + int shmem_init_fs_context(struct fs_context *fc) +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0030-mm-userfaultfd-use-can_userfault-vma-operation.patch b/resources/hiding_ci/linux_patches/0030-mm-userfaultfd-use-can_userfault-vma-operation.patch new file mode 100644 index 00000000000..3344989cb31 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0030-mm-userfaultfd-use-can_userfault-vma-operation.patch @@ -0,0 +1,79 @@ +From 2c19b37bc94ef338ec540424a9a1eee95ffbdc3c Mon Sep 17 00:00:00 2001 +From: Nikita Kalyazin +Date: Fri, 4 Apr 2025 14:16:49 +0000 +Subject: [PATCH 30/34] mm: userfaultfd: use can_userfault vma operation + +Signed-off-by: Nikita Kalyazin +--- + include/linux/userfaultfd_k.h | 13 ++++++------- + mm/userfaultfd.c | 10 +++++++--- + 2 files changed, 13 insertions(+), 10 deletions(-) + +diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h +index 75342022d144..64551e8a55fb 100644 +--- a/include/linux/userfaultfd_k.h ++++ b/include/linux/userfaultfd_k.h +@@ -221,8 +221,8 @@ static inline bool vma_can_userfault(struct vm_area_struct *vma, + if (vm_flags & VM_DROPPABLE) + return false; + +- if ((vm_flags & VM_UFFD_MINOR) && +- (!is_vm_hugetlb_page(vma) && !vma_is_shmem(vma))) ++ if (!vma->vm_ops->can_userfault || ++ !vma->vm_ops->can_userfault(vma, VM_UFFD_MINOR)) + return false; + + /* +@@ -235,16 +235,15 @@ static inline bool vma_can_userfault(struct vm_area_struct *vma, + #ifndef CONFIG_PTE_MARKER_UFFD_WP + /* + * If user requested uffd-wp but not enabled pte markers for +- * uffd-wp, then shmem & hugetlbfs are not supported but only +- * anonymous. ++ * uffd-wp, then only anonymous is supported. + */ + if ((vm_flags & VM_UFFD_WP) && !vma_is_anonymous(vma)) + return false; + #endif + +- /* By default, allow any of anon|shmem|hugetlb */ +- return vma_is_anonymous(vma) || is_vm_hugetlb_page(vma) || +- vma_is_shmem(vma); ++ return vma_is_anonymous(vma) || ++ (vma->vm_ops->can_userfault && ++ vma->vm_ops->can_userfault(vma, vm_flags)); + } + + static inline bool vma_has_uffd_without_event_remap(struct vm_area_struct *vma) +diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c +index 4b3dbc7dac64..0aa82c968e16 100644 +--- a/mm/userfaultfd.c ++++ b/mm/userfaultfd.c +@@ -728,6 +728,7 @@ static __always_inline ssize_t mfill_atomic(struct userfaultfd_ctx *ctx, + unsigned long src_addr, dst_addr; + long copied; + struct folio *folio; ++ bool can_userfault; + + /* + * Sanitize the command parameters: +@@ -787,10 +788,13 @@ static __always_inline ssize_t mfill_atomic(struct userfaultfd_ctx *ctx, + return mfill_atomic_hugetlb(ctx, dst_vma, dst_start, + src_start, len, flags); + +- if (!vma_is_anonymous(dst_vma) && !vma_is_shmem(dst_vma)) ++ can_userfault = dst_vma->vm_ops->can_userfault && ++ dst_vma->vm_ops->can_userfault(dst_vma, __VM_UFFD_FLAGS); ++ ++ if (!vma_is_anonymous(dst_vma) && !can_userfault) + goto out_unlock; +- if (!vma_is_shmem(dst_vma) && +- uffd_flags_mode_is(flags, MFILL_ATOMIC_CONTINUE)) ++ ++ if (!can_userfault && uffd_flags_mode_is(flags, MFILL_ATOMIC_CONTINUE)) + goto out_unlock; + + while (src_addr < src_start + len) { +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0031-KVM-guest_memfd-add-support-for-userfaultfd-minor.patch b/resources/hiding_ci/linux_patches/0031-KVM-guest_memfd-add-support-for-userfaultfd-minor.patch new file mode 100644 index 00000000000..4e544677625 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0031-KVM-guest_memfd-add-support-for-userfaultfd-minor.patch @@ -0,0 +1,44 @@ +From 140a906e90e2ba2092148d80e0764e54802c947c Mon Sep 17 00:00:00 2001 +From: Nikita Kalyazin +Date: Tue, 1 Apr 2025 15:02:56 +0000 +Subject: [PATCH 31/34] KVM: guest_memfd: add support for userfaultfd minor + +Add support for sending a pagefault event if userfaultfd is registered. +Only page minor event is currently supported. + +Signed-off-by: Nikita Kalyazin +--- + virt/kvm/guest_memfd.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c +index 5abb6d52a375..91ee5dd91c31 100644 +--- a/virt/kvm/guest_memfd.c ++++ b/virt/kvm/guest_memfd.c +@@ -5,6 +5,9 @@ + #include + #include + #include ++#ifdef CONFIG_KVM_PRIVATE_MEM ++#include ++#endif /* CONFIG_KVM_PRIVATE_MEM */ + + #include "kvm_mm.h" + +@@ -396,6 +399,13 @@ static vm_fault_t kvm_gmem_fault(struct vm_fault *vmf) + kvm_gmem_mark_prepared(folio); + } + ++ if (userfaultfd_minor(vmf->vma) && ++ !(vmf->flags & FAULT_FLAG_USERFAULT_CONTINUE)) { ++ folio_unlock(folio); ++ filemap_invalidate_unlock_shared(inode->i_mapping); ++ return handle_userfault(vmf, VM_UFFD_MINOR); ++ } ++ + vmf->page = folio_file_page(folio, vmf->pgoff); + + out_folio: +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0032-mm-userfaultfd-add-UFFD_FEATURE_MINOR_GUEST_MEMFD.patch b/resources/hiding_ci/linux_patches/0032-mm-userfaultfd-add-UFFD_FEATURE_MINOR_GUEST_MEMFD.patch new file mode 100644 index 00000000000..3700d496c49 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0032-mm-userfaultfd-add-UFFD_FEATURE_MINOR_GUEST_MEMFD.patch @@ -0,0 +1,61 @@ +From 27e27a59e6139f780439f13cf7180f06c5b0d518 Mon Sep 17 00:00:00 2001 +From: Nikita Kalyazin +Date: Fri, 4 Apr 2025 14:18:03 +0000 +Subject: [PATCH 32/34] mm: userfaultfd: add UFFD_FEATURE_MINOR_GUEST_MEMFD + +Signed-off-by: Nikita Kalyazin +--- + fs/userfaultfd.c | 3 ++- + include/uapi/linux/userfaultfd.h | 8 +++++++- + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c +index 97c4d71115d8..32152bfa462a 100644 +--- a/fs/userfaultfd.c ++++ b/fs/userfaultfd.c +@@ -1954,7 +1954,8 @@ static int userfaultfd_api(struct userfaultfd_ctx *ctx, + uffdio_api.features = UFFD_API_FEATURES; + #ifndef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR + uffdio_api.features &= +- ~(UFFD_FEATURE_MINOR_HUGETLBFS | UFFD_FEATURE_MINOR_SHMEM); ++ ~(UFFD_FEATURE_MINOR_HUGETLBFS | UFFD_FEATURE_MINOR_SHMEM | ++ UFFD_FEATURE_MINOR_GUEST_MEMFD); + #endif + #ifndef CONFIG_HAVE_ARCH_USERFAULTFD_WP + uffdio_api.features &= ~UFFD_FEATURE_PAGEFAULT_FLAG_WP; +diff --git a/include/uapi/linux/userfaultfd.h b/include/uapi/linux/userfaultfd.h +index 2841e4ea8f2c..ed688797eba7 100644 +--- a/include/uapi/linux/userfaultfd.h ++++ b/include/uapi/linux/userfaultfd.h +@@ -42,7 +42,8 @@ + UFFD_FEATURE_WP_UNPOPULATED | \ + UFFD_FEATURE_POISON | \ + UFFD_FEATURE_WP_ASYNC | \ +- UFFD_FEATURE_MOVE) ++ UFFD_FEATURE_MOVE | \ ++ UFFD_FEATURE_MINOR_GUEST_MEMFD) + #define UFFD_API_IOCTLS \ + ((__u64)1 << _UFFDIO_REGISTER | \ + (__u64)1 << _UFFDIO_UNREGISTER | \ +@@ -230,6 +231,10 @@ struct uffdio_api { + * + * UFFD_FEATURE_MOVE indicates that the kernel supports moving an + * existing page contents from userspace. ++ * ++ * UFFD_FEATURE_MINOR_GUEST_MEMFD indicates the same support as ++ * UFFD_FEATURE_MINOR_HUGETLBFS, but for guest_memfd-backed pages ++ * instead. + */ + #define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0) + #define UFFD_FEATURE_EVENT_FORK (1<<1) +@@ -248,6 +253,7 @@ struct uffdio_api { + #define UFFD_FEATURE_POISON (1<<14) + #define UFFD_FEATURE_WP_ASYNC (1<<15) + #define UFFD_FEATURE_MOVE (1<<16) ++#define UFFD_FEATURE_MINOR_GUEST_MEMFD (1<<17) + __u64 features; + + __u64 ioctls; +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0033-KVM-selftests-test-userfaultfd-minor-for-guest_memfd.patch b/resources/hiding_ci/linux_patches/0033-KVM-selftests-test-userfaultfd-minor-for-guest_memfd.patch new file mode 100644 index 00000000000..bfade8ef68a --- /dev/null +++ b/resources/hiding_ci/linux_patches/0033-KVM-selftests-test-userfaultfd-minor-for-guest_memfd.patch @@ -0,0 +1,146 @@ +From 4647a42c34b3896fd872f8b2991b55827d084a38 Mon Sep 17 00:00:00 2001 +From: Nikita Kalyazin +Date: Fri, 28 Feb 2025 16:17:41 +0000 +Subject: [PATCH 33/34] KVM: selftests: test userfaultfd minor for guest_memfd + +The test demonstrates that a minor userfaultfd event in guest_memfd can +be resolved via a memcpy followed by a UFFDIO_CONTINUE ioctl. + +Signed-off-by: Nikita Kalyazin +--- + .../testing/selftests/kvm/guest_memfd_test.c | 99 +++++++++++++++++++ + 1 file changed, 99 insertions(+) + +diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c +index b07221aa54c9..c9578f0ce46f 100644 +--- a/tools/testing/selftests/kvm/guest_memfd_test.c ++++ b/tools/testing/selftests/kvm/guest_memfd_test.c +@@ -10,12 +10,16 @@ + #include + #include + #include ++#include + + #include + #include ++#include + #include + #include + #include ++#include ++#include + + #include "kvm_util.h" + #include "test_util.h" +@@ -278,6 +282,98 @@ static void test_create_guest_memfd_multiple(struct kvm_vm *vm) + close(fd1); + } + ++struct fault_args { ++ char *addr; ++ volatile char value; ++}; ++ ++static void *fault_thread_fn(void *arg) ++{ ++ struct fault_args *args = arg; ++ ++ /* Trigger page fault */ ++ args->value = *args->addr; ++ return NULL; ++} ++ ++static void test_uffd_minor(int fd, size_t page_size, size_t total_size) ++{ ++ struct uffdio_register uffd_reg; ++ struct uffdio_continue uffd_cont; ++ struct uffd_msg msg; ++ struct fault_args args; ++ pthread_t fault_thread; ++ void *mem, *mem_nofault, *buf = NULL; ++ int uffd, ret; ++ off_t offset = page_size; ++ void *fault_addr; ++ ++ ret = posix_memalign(&buf, page_size, total_size); ++ TEST_ASSERT_EQ(ret, 0); ++ ++ uffd = syscall(__NR_userfaultfd, O_CLOEXEC); ++ TEST_ASSERT(uffd != -1, "userfaultfd creation should succeed"); ++ ++ struct uffdio_api uffdio_api = { ++ .api = UFFD_API, ++ .features = UFFD_FEATURE_MINOR_GUEST_MEMFD, ++ }; ++ ret = ioctl(uffd, UFFDIO_API, &uffdio_api); ++ TEST_ASSERT(ret != -1, "ioctl(UFFDIO_API) should succeed"); ++ ++ mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); ++ TEST_ASSERT(mem != MAP_FAILED, "mmap should succeed"); ++ ++ mem_nofault = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); ++ TEST_ASSERT(mem_nofault != MAP_FAILED, "mmap should succeed"); ++ ++ uffd_reg.range.start = (unsigned long)mem; ++ uffd_reg.range.len = total_size; ++ uffd_reg.mode = UFFDIO_REGISTER_MODE_MINOR; ++ ret = ioctl(uffd, UFFDIO_REGISTER, &uffd_reg); ++ TEST_ASSERT(ret != -1, "ioctl(UFFDIO_REGISTER) should succeed"); ++ ++ ret = fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, ++ offset, page_size); ++ TEST_ASSERT(!ret, "fallocate(PUNCH_HOLE) should succeed"); ++ ++ fault_addr = mem + offset; ++ args.addr = fault_addr; ++ ++ ret = pthread_create(&fault_thread, NULL, fault_thread_fn, &args); ++ TEST_ASSERT(ret == 0, "pthread_create should succeed"); ++ ++ ret = read(uffd, &msg, sizeof(msg)); ++ TEST_ASSERT(ret != -1, "read from userfaultfd should succeed"); ++ TEST_ASSERT(msg.event == UFFD_EVENT_PAGEFAULT, "event type should be pagefault"); ++ TEST_ASSERT((void *)(msg.arg.pagefault.address & ~(page_size - 1)) == fault_addr, ++ "pagefault should occur at expected address"); ++ ++ memcpy(mem_nofault + offset, buf + offset, page_size); ++ ++ uffd_cont.range.start = (unsigned long)fault_addr; ++ uffd_cont.range.len = page_size; ++ uffd_cont.mode = 0; ++ ret = ioctl(uffd, UFFDIO_CONTINUE, &uffd_cont); ++ TEST_ASSERT(ret != -1, "ioctl(UFFDIO_CONTINUE) should succeed"); ++ ++ TEST_ASSERT(args.value == *(char *)(mem_nofault + offset), ++ "memory should contain the value that was copied"); ++ TEST_ASSERT(args.value == *(char *)(mem + offset), ++ "no further fault is expected"); ++ ++ ret = pthread_join(fault_thread, NULL); ++ TEST_ASSERT(ret == 0, "pthread_join should succeed"); ++ ++ ret = munmap(mem_nofault, total_size); ++ TEST_ASSERT(!ret, "munmap should succeed"); ++ ++ ret = munmap(mem, total_size); ++ TEST_ASSERT(!ret, "munmap should succeed"); ++ free(buf); ++ close(uffd); ++} ++ + unsigned long get_shared_type(void) + { + #ifdef __x86_64__ +@@ -317,6 +413,9 @@ void test_vm_type(unsigned long type, bool is_shared) + test_fallocate(fd, page_size, total_size); + test_invalid_punch_hole(fd, page_size, total_size); + ++ if (is_shared) ++ test_uffd_minor(fd, page_size, total_size); ++ + close(fd); + kvm_vm_release(vm); + } +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/0034-uffd-v3-fixup.patch b/resources/hiding_ci/linux_patches/0034-uffd-v3-fixup.patch new file mode 100644 index 00000000000..41df6ff2428 --- /dev/null +++ b/resources/hiding_ci/linux_patches/0034-uffd-v3-fixup.patch @@ -0,0 +1,50 @@ +From a03bf9042094cc0fd1b2a71307b6e0b02e8500d8 Mon Sep 17 00:00:00 2001 +From: Nikita Kalyazin +Date: Thu, 10 Apr 2025 14:18:53 +0000 +Subject: [PATCH 34/34] uffd v3 fixup + + - implement can_userfault for guest_memfd + - check vma->vm_ops pointer before dereferencing +--- + include/linux/userfaultfd_k.h | 3 ++- + virt/kvm/guest_memfd.c | 9 ++++++++- + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h +index 64551e8a55fb..92fb5372bea5 100644 +--- a/include/linux/userfaultfd_k.h ++++ b/include/linux/userfaultfd_k.h +@@ -221,7 +221,8 @@ static inline bool vma_can_userfault(struct vm_area_struct *vma, + if (vm_flags & VM_DROPPABLE) + return false; + +- if (!vma->vm_ops->can_userfault || ++ if (!vma->vm_ops || ++ !vma->vm_ops->can_userfault || + !vma->vm_ops->can_userfault(vma, VM_UFFD_MINOR)) + return false; + +diff --git a/virt/kvm/guest_memfd.c b/virt/kvm/guest_memfd.c +index 91ee5dd91c31..202b12dc4b6f 100644 +--- a/virt/kvm/guest_memfd.c ++++ b/virt/kvm/guest_memfd.c +@@ -420,8 +420,15 @@ static vm_fault_t kvm_gmem_fault(struct vm_fault *vmf) + return ret; + } + ++static bool kvm_gmem_can_userfault(struct vm_area_struct *vma, ++ unsigned long vm_flags) ++{ ++ return vm_flags & VM_UFFD_MINOR; ++} ++ + static const struct vm_operations_struct kvm_gmem_vm_ops = { +- .fault = kvm_gmem_fault, ++ .fault = kvm_gmem_fault, ++ .can_userfault = kvm_gmem_can_userfault, + }; + + static int kvm_gmem_mmap(struct file *file, struct vm_area_struct *vma) +-- +2.47.1 + diff --git a/resources/hiding_ci/linux_patches/GPL-2.0 b/resources/hiding_ci/linux_patches/GPL-2.0 new file mode 100644 index 00000000000..ff0812fd89c --- /dev/null +++ b/resources/hiding_ci/linux_patches/GPL-2.0 @@ -0,0 +1,359 @@ +Valid-License-Identifier: GPL-2.0 +Valid-License-Identifier: GPL-2.0-only +Valid-License-Identifier: GPL-2.0+ +Valid-License-Identifier: GPL-2.0-or-later +SPDX-URL: https://spdx.org/licenses/GPL-2.0.html +Usage-Guide: + To use this license in source code, put one of the following SPDX + tag/value pairs into a comment according to the placement + guidelines in the licensing rules documentation. + For 'GNU General Public License (GPL) version 2 only' use: + SPDX-License-Identifier: GPL-2.0 + or + SPDX-License-Identifier: GPL-2.0-only + For 'GNU General Public License (GPL) version 2 or any later version' use: + SPDX-License-Identifier: GPL-2.0+ + or + SPDX-License-Identifier: GPL-2.0-or-later +License-Text: + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/resources/hiding_ci/linux_patches/README.md b/resources/hiding_ci/linux_patches/README.md new file mode 100644 index 00000000000..7a119e42452 --- /dev/null +++ b/resources/hiding_ci/linux_patches/README.md @@ -0,0 +1,8 @@ +# Linux kernel patches for direct map removal + +The Linux kernel patches in this directory are distributed under the `GPL-2.0` +licence (see the full licence text at [GPL-2.0](./GPL-2.0)). The patches are +required by Firecracker's "Secret Freedom" feature that removes the VM memory +from the host direct map (see +[lore](https://lore.kernel.org/kvm/20250221160728.1584559-1-roypat@amazon.co.uk/) +for more details). The patches are not yet merged upstream. diff --git a/resources/hiding_ci/patches/0001.lore b/resources/hiding_ci/patches/0001.lore deleted file mode 100644 index 7663841026d..00000000000 --- a/resources/hiding_ci/patches/0001.lore +++ /dev/null @@ -1 +0,0 @@ -https://lore.kernel.org/kvm/20250318161823.4005529-1-tabba@google.com