]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
7.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 16 Jul 2026 11:45:32 +0000 (13:45 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 16 Jul 2026 11:45:32 +0000 (13:45 +0200)
added patches:
audit-fix-removal-of-dangling-executable-rules.patch
dma-buf-udmabuf-skip-redundant-cpu-sync-to-fix-cacheline-eexist-warning.patch
fpga-dfl-afu-validate-dma-mapping-length-in-afu_dma_map_region.patch
iommu-amd-don-t-split-flush-for-amd_iommu_domain_flush_all.patch
iommu-vt-d-avoid-warning-in-sva-unbind-path.patch
iommufd-avoid-partial-fault-group-delivery-in-iommufd_fault_fops_read.patch
iommufd-break-the-loop-on-failure-in-iommufd_fault_fops_read.patch
iommufd-fix-data_len-byte-count-vs-element-count-mismatch.patch
iommufd-move-vevent-memory-allocation-outside-spinlock.patch
iommufd-propagate-allocation-failure-in-iommufd_veventq_deliver_fetch.patch
iommufd-reject-invalid-read-count-in-iommufd_fault_fops_read.patch
iommufd-reject-invalid-read-count-in-iommufd_veventq_fops_read.patch
iommufd-rewind-header-length-in-done-if-iommufd_veventq_fops_read-fails.patch
iommufd-set-upper-bounds-on-cache-invalidation-entry_num-and-entry_len.patch
iommufd-set-veventq_depth-upper-bound.patch
iommufd-use-sizeof-hdr-instead-of-sizeof-hdr-in-veventq-read.patch
kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-vcpu.patch
kvm-arm64-clear-__hyp_running_vcpu-when-flushing-the-pkvm-hyp-vcpu.patch
kvm-arm64-don-t-leak-pfn-when-kvm_translate_vncr-races-mmu-notifier.patch
kvm-arm64-nv-avoid-dereferencing-null-vncr-pseudo-tlb.patch
kvm-guest_memfd-treat-memslot-binding-offset-size-as-unsigned-values.patch
kvm-sev-don-t-terminate-snp-vms-on-vmgexit-without-a-registered-ghcb.patch
kvm-sev-pin-source-page-for-write-when-adding-cpuid-data-for-snp-guest.patch
kvm-svm-disable-x2avic-rdmsr-interception-for-msrs-kvm-actually-supports.patch
kvm-svm-only-disable-x2avic-wrmsr-interception-for-msrs-that-are-accelerated.patch
kvm-tdx-account-all-non-transient-page-allocations-for-per-td-structures.patch
kvm-vmx-handle-bad-values-on-proxied-writes-to-lbr-msrs.patch
kvm-vmx-refresh-guest_pending_dbg_exceptions.bs-on-all-injected-dbs.patch
kvm-x86-add-dedicated-api-for-getting-mask-of-accelerated-x2apic-msrs.patch
kvm-x86-ensure-vendor-s-exit-handler-runs-before-fastpath-userspace-exits.patch
landlock-account-all-audit-data-allocations-to-user-space.patch
landlock-set-audit_net.sk-for-socket-access-checks.patch
loongarch-kvm-add-missing-slots_lock-for-device-register-unregister.patch
revert-svcrdma-use-contiguous-pages-for-rdma-read-sink-buffers.patch
selftests-landlock-explicitly-disable-audit-in-teardowns.patch
selftests-landlock-filter-dealloc-records-in-audit_count_records.patch
selftests-landlock-increase-default-audit-socket-timeout.patch
svcrdma-wake-sq-waiters-when-the-transport-closes.patch
udmabuf-fix-dma-direction-mismatch-in-release_udmabuf.patch

40 files changed:
queue-7.1/audit-fix-removal-of-dangling-executable-rules.patch [new file with mode: 0644]
queue-7.1/dma-buf-udmabuf-skip-redundant-cpu-sync-to-fix-cacheline-eexist-warning.patch [new file with mode: 0644]
queue-7.1/fpga-dfl-afu-validate-dma-mapping-length-in-afu_dma_map_region.patch [new file with mode: 0644]
queue-7.1/iommu-amd-don-t-split-flush-for-amd_iommu_domain_flush_all.patch [new file with mode: 0644]
queue-7.1/iommu-vt-d-avoid-warning-in-sva-unbind-path.patch [new file with mode: 0644]
queue-7.1/iommufd-avoid-partial-fault-group-delivery-in-iommufd_fault_fops_read.patch [new file with mode: 0644]
queue-7.1/iommufd-break-the-loop-on-failure-in-iommufd_fault_fops_read.patch [new file with mode: 0644]
queue-7.1/iommufd-fix-data_len-byte-count-vs-element-count-mismatch.patch [new file with mode: 0644]
queue-7.1/iommufd-move-vevent-memory-allocation-outside-spinlock.patch [new file with mode: 0644]
queue-7.1/iommufd-propagate-allocation-failure-in-iommufd_veventq_deliver_fetch.patch [new file with mode: 0644]
queue-7.1/iommufd-reject-invalid-read-count-in-iommufd_fault_fops_read.patch [new file with mode: 0644]
queue-7.1/iommufd-reject-invalid-read-count-in-iommufd_veventq_fops_read.patch [new file with mode: 0644]
queue-7.1/iommufd-rewind-header-length-in-done-if-iommufd_veventq_fops_read-fails.patch [new file with mode: 0644]
queue-7.1/iommufd-set-upper-bounds-on-cache-invalidation-entry_num-and-entry_len.patch [new file with mode: 0644]
queue-7.1/iommufd-set-veventq_depth-upper-bound.patch [new file with mode: 0644]
queue-7.1/iommufd-use-sizeof-hdr-instead-of-sizeof-hdr-in-veventq-read.patch [new file with mode: 0644]
queue-7.1/kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-vcpu.patch [new file with mode: 0644]
queue-7.1/kvm-arm64-clear-__hyp_running_vcpu-when-flushing-the-pkvm-hyp-vcpu.patch [new file with mode: 0644]
queue-7.1/kvm-arm64-don-t-leak-pfn-when-kvm_translate_vncr-races-mmu-notifier.patch [new file with mode: 0644]
queue-7.1/kvm-arm64-nv-avoid-dereferencing-null-vncr-pseudo-tlb.patch [new file with mode: 0644]
queue-7.1/kvm-guest_memfd-treat-memslot-binding-offset-size-as-unsigned-values.patch [new file with mode: 0644]
queue-7.1/kvm-sev-don-t-terminate-snp-vms-on-vmgexit-without-a-registered-ghcb.patch [new file with mode: 0644]
queue-7.1/kvm-sev-pin-source-page-for-write-when-adding-cpuid-data-for-snp-guest.patch [new file with mode: 0644]
queue-7.1/kvm-svm-disable-x2avic-rdmsr-interception-for-msrs-kvm-actually-supports.patch [new file with mode: 0644]
queue-7.1/kvm-svm-only-disable-x2avic-wrmsr-interception-for-msrs-that-are-accelerated.patch [new file with mode: 0644]
queue-7.1/kvm-tdx-account-all-non-transient-page-allocations-for-per-td-structures.patch [new file with mode: 0644]
queue-7.1/kvm-vmx-handle-bad-values-on-proxied-writes-to-lbr-msrs.patch [new file with mode: 0644]
queue-7.1/kvm-vmx-refresh-guest_pending_dbg_exceptions.bs-on-all-injected-dbs.patch [new file with mode: 0644]
queue-7.1/kvm-x86-add-dedicated-api-for-getting-mask-of-accelerated-x2apic-msrs.patch [new file with mode: 0644]
queue-7.1/kvm-x86-ensure-vendor-s-exit-handler-runs-before-fastpath-userspace-exits.patch [new file with mode: 0644]
queue-7.1/landlock-account-all-audit-data-allocations-to-user-space.patch [new file with mode: 0644]
queue-7.1/landlock-set-audit_net.sk-for-socket-access-checks.patch [new file with mode: 0644]
queue-7.1/loongarch-kvm-add-missing-slots_lock-for-device-register-unregister.patch [new file with mode: 0644]
queue-7.1/revert-svcrdma-use-contiguous-pages-for-rdma-read-sink-buffers.patch [new file with mode: 0644]
queue-7.1/selftests-landlock-explicitly-disable-audit-in-teardowns.patch [new file with mode: 0644]
queue-7.1/selftests-landlock-filter-dealloc-records-in-audit_count_records.patch [new file with mode: 0644]
queue-7.1/selftests-landlock-increase-default-audit-socket-timeout.patch [new file with mode: 0644]
queue-7.1/series
queue-7.1/svcrdma-wake-sq-waiters-when-the-transport-closes.patch [new file with mode: 0644]
queue-7.1/udmabuf-fix-dma-direction-mismatch-in-release_udmabuf.patch [new file with mode: 0644]

diff --git a/queue-7.1/audit-fix-removal-of-dangling-executable-rules.patch b/queue-7.1/audit-fix-removal-of-dangling-executable-rules.patch
new file mode 100644 (file)
index 0000000..f8443f1
--- /dev/null
@@ -0,0 +1,61 @@
+From 888a0396e154524f4027f27da84bdbec9eb68916 Mon Sep 17 00:00:00 2001
+From: Ricardo Robaina <rrobaina@redhat.com>
+Date: Wed, 13 May 2026 18:47:59 -0300
+Subject: audit: fix removal of dangling executable rules
+
+From: Ricardo Robaina <rrobaina@redhat.com>
+
+commit 888a0396e154524f4027f27da84bdbec9eb68916 upstream.
+
+When an audited executable is deleted from the disk, its dentry
+becomes negative. Any later attempt to delete the associated audit
+rule will lead to audit_alloc_mark() encountering this negative
+dentry and immediately aborting, returning -ENOENT.
+
+This early abort prevents the subsystem from allocating the temporary
+fsnotify mark needed to construct the search key, meaning the kernel
+cannot find the existing rule in its own lists to delete it. This
+leaves a dangling rule in memory, resulting in the following error
+while attempting to delete the rule:
+
+ # ./audit-dupe-exe-deadlock.sh
+ No rules
+ Error deleting rule (No such file or directory)
+ There was an error while processing parameters
+
+ # auditctl -l
+ -a always,exit -S all -F exe=/tmp/file -F path=/tmp/file -F key=dr
+
+ # auditctl -D
+ Error deleting rule (No such file or directory)
+ There was an error while processing parameters
+
+This patch fixes this issue by removing the d_really_is_negative()
+check. By doing so, a dummy mark can be successfully generated for
+the deleted path, which allows the audit subsystem to properly match
+and flush the dangling rule.
+
+Cc: stable@kernel.org
+Fixes: 76a53de6f7ff ("VFS/audit: introduce kern_path_parent() for audit")
+Acked-by: Waiman Long <longman@redhat.com>
+Acked-by: Richard Guy Briggs <rgb@redhat.com>
+Signed-off-by: Ricardo Robaina <rrobaina@redhat.com>
+Signed-off-by: Paul Moore <paul@paul-moore.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/audit_fsnotify.c |    4 ----
+ 1 file changed, 4 deletions(-)
+
+--- a/kernel/audit_fsnotify.c
++++ b/kernel/audit_fsnotify.c
+@@ -84,10 +84,6 @@ struct audit_fsnotify_mark *audit_alloc_
+       dentry = kern_path_parent(pathname, &path);
+       if (IS_ERR(dentry))
+               return ERR_CAST(dentry); /* returning an error */
+-      if (d_really_is_negative(dentry)) {
+-              audit_mark = ERR_PTR(-ENOENT);
+-              goto out;
+-      }
+       audit_mark = kzalloc_obj(*audit_mark);
+       if (unlikely(!audit_mark)) {
diff --git a/queue-7.1/dma-buf-udmabuf-skip-redundant-cpu-sync-to-fix-cacheline-eexist-warning.patch b/queue-7.1/dma-buf-udmabuf-skip-redundant-cpu-sync-to-fix-cacheline-eexist-warning.patch
new file mode 100644 (file)
index 0000000..6df4c9b
--- /dev/null
@@ -0,0 +1,81 @@
+From 504e2b4ab97a51d56d966cd36d0997ad30b65b2d Mon Sep 17 00:00:00 2001
+From: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
+Date: Tue, 31 Mar 2026 11:16:57 +0500
+Subject: dma-buf/udmabuf: skip redundant cpu sync to fix cacheline EEXIST warning
+
+From: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
+
+commit 504e2b4ab97a51d56d966cd36d0997ad30b65b2d upstream.
+
+When CONFIG_DMA_API_DEBUG_SG is enabled, importing a udmabuf into a DRM
+driver (e.g. amdgpu for video playback in GNOME Videos / Showtime)
+triggers a spurious warning:
+
+  DMA-API: amdgpu 0000:03:00.0: cacheline tracking EEXIST, \
+      overlapping mappings aren't supported
+  WARNING: kernel/dma/debug.c:619 at add_dma_entry+0x473/0x5f0
+
+The call chain is:
+
+  amdgpu_cs_ioctl
+   -> amdgpu_ttm_backend_bind
+    -> dma_buf_map_attachment
+     -> [udmabuf] map_udmabuf -> get_sg_table
+      -> dma_map_sgtable(dev, sg, direction, 0)  // attrs=0
+       -> debug_dma_map_sg -> add_dma_entry -> EEXIST
+
+This happens because udmabuf builds a per-page scatter-gather list via
+sg_set_folio().  When begin_cpu_udmabuf() has already created an sg
+table mapped for the misc device, and an importer such as amdgpu maps
+the same pages for its own device via map_udmabuf(), the DMA debug
+infrastructure sees two active mappings whose physical addresses share
+cacheline boundaries and warns about the overlap.
+
+The DMA_ATTR_SKIP_CPU_SYNC flag suppresses this check in
+add_dma_entry() because it signals that no CPU cache maintenance is
+performed at map/unmap time, making the cacheline overlap harmless.
+
+All other major dma-buf exporters already pass this flag:
+  - drm_gem_map_dma_buf() passes DMA_ATTR_SKIP_CPU_SYNC
+  - amdgpu_dma_buf_map() passes DMA_ATTR_SKIP_CPU_SYNC
+
+The CPU sync at map/unmap time is also redundant for udmabuf:
+begin_cpu_udmabuf() and end_cpu_udmabuf() already perform explicit
+cache synchronization via dma_sync_sgtable_for_cpu/device() when CPU
+access is requested through the dma-buf interface.
+
+Pass DMA_ATTR_SKIP_CPU_SYNC to dma_map_sgtable() and
+dma_unmap_sgtable() in udmabuf to suppress the spurious warning and
+skip the redundant sync.
+
+Fixes: 284562e1f348 ("udmabuf: implement begin_cpu_access/end_cpu_access hooks")
+Cc: stable@vger.kernel.org
+Signed-off-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
+Acked-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
+Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
+Link: https://patch.msgid.link/20260331061657.79983-1-mikhail.v.gavrilov@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/dma-buf/udmabuf.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/dma-buf/udmabuf.c
++++ b/drivers/dma-buf/udmabuf.c
+@@ -163,7 +163,7 @@ static struct sg_table *get_sg_table(str
+               sg_set_folio(sgl, ubuf->folios[i], PAGE_SIZE,
+                            ubuf->offsets[i]);
+-      ret = dma_map_sgtable(dev, sg, direction, 0);
++      ret = dma_map_sgtable(dev, sg, direction, DMA_ATTR_SKIP_CPU_SYNC);
+       if (ret < 0)
+               goto err_map;
+       return sg;
+@@ -178,7 +178,7 @@ err_alloc:
+ static void put_sg_table(struct device *dev, struct sg_table *sg,
+                        enum dma_data_direction direction)
+ {
+-      dma_unmap_sgtable(dev, sg, direction, 0);
++      dma_unmap_sgtable(dev, sg, direction, DMA_ATTR_SKIP_CPU_SYNC);
+       sg_free_table(sg);
+       kfree(sg);
+ }
diff --git a/queue-7.1/fpga-dfl-afu-validate-dma-mapping-length-in-afu_dma_map_region.patch b/queue-7.1/fpga-dfl-afu-validate-dma-mapping-length-in-afu_dma_map_region.patch
new file mode 100644 (file)
index 0000000..9b7d4bc
--- /dev/null
@@ -0,0 +1,42 @@
+From fc3b071a7c8dc0f5d56defddf6e6fd5aaa3e1e27 Mon Sep 17 00:00:00 2001
+From: Sebastian Alba Vives <sebasjosue84@gmail.com>
+Date: Mon, 18 May 2026 13:07:41 -0600
+Subject: fpga: dfl-afu: validate DMA mapping length in afu_dma_map_region()
+
+From: Sebastian Alba Vives <sebasjosue84@gmail.com>
+
+commit fc3b071a7c8dc0f5d56defddf6e6fd5aaa3e1e27 upstream.
+
+afu_ioctl_dma_map() accepts a 64-bit length from userspace via
+DFL_FPGA_PORT_DMA_MAP ioctl without an upper bound check. The value
+is passed to afu_dma_pin_pages() where npages is derived as
+length >> PAGE_SHIFT and passed to pin_user_pages_fast() which takes
+int nr_pages, causing implicit truncation if length is very large.
+
+Validate map.length at the ioctl entry point before calling
+afu_dma_map_region(), rejecting values whose page count exceeds
+INT_MAX.
+
+Fixes: fa8dda1edef9 ("fpga: dfl: afu: add DFL_FPGA_PORT_DMA_MAP/UNMAP ioctls support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Sebastian Alba Vives <sebasjosue84@gmail.com>
+Reviewed-by: Xu Yilun <yilun.xu@intel.com>
+Link: https://lore.kernel.org/r/20260518190742.61426-3-sebasjosue84@gmail.com
+Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/fpga/dfl-afu-main.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/fpga/dfl-afu-main.c
++++ b/drivers/fpga/dfl-afu-main.c
+@@ -723,6 +723,9 @@ afu_ioctl_dma_map(struct dfl_feature_dev
+       if (map.argsz < minsz || map.flags)
+               return -EINVAL;
++      if (map.length >> PAGE_SHIFT > (u64)INT_MAX)
++              return -EINVAL;
++
+       ret = afu_dma_map_region(fdata, map.user_addr, map.length, &map.iova);
+       if (ret)
+               return ret;
diff --git a/queue-7.1/iommu-amd-don-t-split-flush-for-amd_iommu_domain_flush_all.patch b/queue-7.1/iommu-amd-don-t-split-flush-for-amd_iommu_domain_flush_all.patch
new file mode 100644 (file)
index 0000000..72de8d6
--- /dev/null
@@ -0,0 +1,61 @@
+From 69fe699afe1afcb730164b86c228483c2da05f94 Mon Sep 17 00:00:00 2001
+From: Weinan Liu <wnliu@google.com>
+Date: Thu, 28 May 2026 22:31:47 +0000
+Subject: iommu/amd: Don't split flush for amd_iommu_domain_flush_all()
+
+From: Weinan Liu <wnliu@google.com>
+
+commit 69fe699afe1afcb730164b86c228483c2da05f94 upstream.
+
+We have observed multiple full invalidations occurring during device
+detach when we are done using the vfio-device.
+
+blocked_domain_attach_device()
+  -> detach_device()
+    -> amd_iommu_domain_flush_all()
+      -> amd_iommu_domain_flush_pages(..., CMD_INV_IOMMU_ALL_PAGES_ADDRESS)
+
+       while (size != 0) {
+
+          -> __domain_flush_pages( flush_size /* power of 2 flush_size */)
+            -> domain_flush_pages_v1()
+              -> build_inv_iommu_pages()
+                -> build_inv_address()
+
+         }
+
+build_inv_address() will trigger a full invalidation  if the chunk
+size > (1 << 51). Consequently, the guest will issue multiple full
+invalidations for a single call to  amd_iommu_domain_flush_all()
+
+Without this patch, we will see 10 time instead of 1 time full
+invalidations for every amd_iommu_domain_flush_all().
+
+Cc: stable@vger.kernel.org
+Fixes: a270be1b3fdf ("iommu/amd: Use only natural aligned flushes in a VM")
+Suggested-by: Josef Bacik <josef@toxicpanda.com>
+Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Weinan Liu <wnliu@google.com>
+Reviewed-by: Wei Wang <wei.w.wang@hotmail.com>
+Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
+Reviewed-by: Samiullah Khawaja <skhawaja@google.com>
+Reviewed-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
+Reviewed-by: Vasant Hegde <vasant.hegde@amd.com>
+Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/amd/iommu.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/iommu/amd/iommu.c
++++ b/drivers/iommu/amd/iommu.c
+@@ -1774,7 +1774,8 @@ void amd_iommu_domain_flush_pages(struct
+ {
+       lockdep_assert_held(&domain->lock);
+-      if (likely(!amd_iommu_np_cache)) {
++      if (likely(!amd_iommu_np_cache) ||
++              size >= (1ULL<<52)) {
+               __domain_flush_pages(domain, address, size);
+               /* Wait until IOMMU TLB and all device IOTLB flushes are complete */
diff --git a/queue-7.1/iommu-vt-d-avoid-warning-in-sva-unbind-path.patch b/queue-7.1/iommu-vt-d-avoid-warning-in-sva-unbind-path.patch
new file mode 100644 (file)
index 0000000..a407cdf
--- /dev/null
@@ -0,0 +1,103 @@
+From 534b5f98ab7319d8004bbc7dab6481462243e883 Mon Sep 17 00:00:00 2001
+From: Lu Baolu <baolu.lu@linux.intel.com>
+Date: Thu, 4 Jun 2026 14:03:06 +0800
+Subject: iommu/vt-d: Avoid WARNING in sva unbind path
+
+From: Lu Baolu <baolu.lu@linux.intel.com>
+
+commit 534b5f98ab7319d8004bbc7dab6481462243e883 upstream.
+
+The Intel IOMMU driver allows SVA on devices even if they do not support
+PCI/PRI. Commit 39c20c4e83b9 ("iommu/vt-d: Only handle IOPF for SVA when
+PRI is supported") modified the SVA bind path to allow this configuration
+by skipping IOPF enablement when PRI is missing. However, it failed to
+update the unbind path.
+
+This creates an imbalance: the unbind path attempts to disable IOPF for
+a device that never had it enabled, triggering a WARNING in
+intel_iommu_disable_iopf():
+
+ WARNING: drivers/iommu/intel/iommu.c:3475 at intel_iommu_disable_iopf+0x4f/0x90d
+ Call Trace:
+  <TASK>
+  blocking_domain_set_dev_pasid+0x50/0x70
+  iommu_detach_device_pasid+0x89/0xc0
+  iommu_sva_unbind_device+0x73/0x150
+  xe_vm_close_and_put+0x4d2/0x1200 [xe]
+
+Fix this by bypassing IOPF operations for SVA domains on non-PRI hardware
+in both the bind and unbind paths.
+
+Fixes: 39c20c4e83b9 ("iommu/vt-d: Only handle IOPF for SVA when PRI is supported")
+Cc: stable@vger.kernel.org
+Reported-by: Nareshkumar Gollakoti <naresh.kumar.g@intel.com>
+Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Link: https://lore.kernel.org/r/20260519052917.3729796-1-baolu.lu@linux.intel.com
+Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/intel/iommu.h |   11 +++++++++++
+ drivers/iommu/intel/svm.c   |   12 ++++--------
+ 2 files changed, 15 insertions(+), 8 deletions(-)
+
+--- a/drivers/iommu/intel/iommu.h
++++ b/drivers/iommu/intel/iommu.h
+@@ -1254,18 +1254,29 @@ void intel_iommu_disable_iopf(struct dev
+ static inline int iopf_for_domain_set(struct iommu_domain *domain,
+                                     struct device *dev)
+ {
++      struct device_domain_info *info = dev_iommu_priv_get(dev);
++
+       if (!domain || !domain->iopf_handler)
+               return 0;
++      /* SVA with non-IOMMU/PRI IOPF handling is allowed. */
++      if (domain->type == IOMMU_DOMAIN_SVA && !info->pri_supported)
++              return 0;
++
+       return intel_iommu_enable_iopf(dev);
+ }
+ static inline void iopf_for_domain_remove(struct iommu_domain *domain,
+                                         struct device *dev)
+ {
++      struct device_domain_info *info = dev_iommu_priv_get(dev);
++
+       if (!domain || !domain->iopf_handler)
+               return;
++      if (domain->type == IOMMU_DOMAIN_SVA && !info->pri_supported)
++              return;
++
+       intel_iommu_disable_iopf(dev);
+ }
+--- a/drivers/iommu/intel/svm.c
++++ b/drivers/iommu/intel/svm.c
+@@ -164,12 +164,9 @@ static int intel_svm_set_dev_pasid(struc
+       if (IS_ERR(dev_pasid))
+               return PTR_ERR(dev_pasid);
+-      /* SVA with non-IOMMU/PRI IOPF handling is allowed. */
+-      if (info->pri_supported) {
+-              ret = iopf_for_domain_replace(domain, old, dev);
+-              if (ret)
+-                      goto out_remove_dev_pasid;
+-      }
++      ret = iopf_for_domain_replace(domain, old, dev);
++      if (ret)
++              goto out_remove_dev_pasid;
+       /* Setup the pasid table: */
+       sflags = cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;
+@@ -184,8 +181,7 @@ static int intel_svm_set_dev_pasid(struc
+       return 0;
+ out_unwind_iopf:
+-      if (info->pri_supported)
+-              iopf_for_domain_replace(old, domain, dev);
++      iopf_for_domain_replace(old, domain, dev);
+ out_remove_dev_pasid:
+       domain_remove_dev_pasid(domain, dev, pasid);
+       return ret;
diff --git a/queue-7.1/iommufd-avoid-partial-fault-group-delivery-in-iommufd_fault_fops_read.patch b/queue-7.1/iommufd-avoid-partial-fault-group-delivery-in-iommufd_fault_fops_read.patch
new file mode 100644 (file)
index 0000000..7c5ce10
--- /dev/null
@@ -0,0 +1,70 @@
+From 091ab6d70dc444f56ed14faedbcacfc979f4c613 Mon Sep 17 00:00:00 2001
+From: Nicolin Chen <nicolinc@nvidia.com>
+Date: Mon, 1 Jun 2026 13:42:37 -0700
+Subject: iommufd: Avoid partial fault group delivery in iommufd_fault_fops_read()
+
+From: Nicolin Chen <nicolinc@nvidia.com>
+
+commit 091ab6d70dc444f56ed14faedbcacfc979f4c613 upstream.
+
+The cookie returned by xa_alloc() in iommufd_fault_fops_read() is per fault
+group, but the inner copy_to_user() runs per fault inside the group. If a
+copy fails mid-group, xa_erase clears the cookie and the group is restored
+to the deliver list, yet done is not rolled back. The function returns the
+partial byte count, with the successfully copied faults sitting at offsets
+below done carrying the now-erased cookie. The next read() then re-fetches
+the group, allocates a fresh cookie, and re-delivers every fault including
+the ones already copied; userspace sees duplicates carrying the new cookie,
+and a stale cookie that can never be responded to.
+
+Use a local group_done variable that tracks the per-group progress inside
+the inner loop, and only commit done = group_done after the inner loop has
+finished successfully. On a copy_to_user failure the outer break skips the
+commit, so done remains at its prior start-of-group baseline; the partial
+bytes already written past done are undefined to userspace per the read(2)
+contract, and the next read re-delivers the whole group atomically.
+
+Fixes: 07838f7fd529 ("iommufd: Add iommufd fault object")
+Link: https://patch.msgid.link/r/360cab4d4aeccb0bae275a970e2b3c340a71e0e0.1780343944.git.nicolinc@nvidia.com
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-7
+Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Pranjal Shrivastava <praan@google.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/iommufd/eventq.c |    7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+--- a/drivers/iommu/iommufd/eventq.c
++++ b/drivers/iommu/iommufd/eventq.c
+@@ -139,6 +139,8 @@ static ssize_t iommufd_fault_fops_read(s
+       mutex_lock(&fault->mutex);
+       while ((group = iommufd_fault_deliver_fetch(fault))) {
++              size_t group_done = done;
++
+               if (done >= count ||
+                   group->fault_count * fault_size > count - done) {
+                       iommufd_fault_deliver_restore(fault, group);
+@@ -160,16 +162,17 @@ static ssize_t iommufd_fault_fops_read(s
+                       iommufd_compose_fault_message(&iopf->fault,
+                                                     &data, idev,
+                                                     group->cookie);
+-                      if (copy_to_user(buf + done, &data, fault_size)) {
++                      if (copy_to_user(buf + group_done, &data, fault_size)) {
+                               xa_erase(&fault->response, group->cookie);
+                               iommufd_fault_deliver_restore(fault, group);
+                               rc = -EFAULT;
+                               break;
+                       }
+-                      done += fault_size;
++                      group_done += fault_size;
+               }
+               if (rc)
+                       break;
++              done = group_done;
+       }
+       mutex_unlock(&fault->mutex);
diff --git a/queue-7.1/iommufd-break-the-loop-on-failure-in-iommufd_fault_fops_read.patch b/queue-7.1/iommufd-break-the-loop-on-failure-in-iommufd_fault_fops_read.patch
new file mode 100644 (file)
index 0000000..0b4a0d7
--- /dev/null
@@ -0,0 +1,39 @@
+From 172fc8b19825a0f5884c38f2289188284e2d45ee Mon Sep 17 00:00:00 2001
+From: Nicolin Chen <nicolinc@nvidia.com>
+Date: Mon, 1 Jun 2026 13:42:36 -0700
+Subject: iommufd: Break the loop on failure in iommufd_fault_fops_read()
+
+From: Nicolin Chen <nicolinc@nvidia.com>
+
+commit 172fc8b19825a0f5884c38f2289188284e2d45ee upstream.
+
+On a copy_to_user() failure inside the inner list_for_each_entry, only the
+inner loop breaks; the outer while re-fetches the just-restored fault group
+and retries the failing copy_to_user() forever, spinning the reader at 100%
+CPU with fault->mutex held.
+
+Check rc after the inner loop and break the outer while as well.
+
+Fixes: 07838f7fd529 ("iommufd: Add iommufd fault object")
+Link: https://patch.msgid.link/r/336a9b6e44fe66a24199d3be777c405c85c98622.1780343944.git.nicolinc@nvidia.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Pranjal Shrivastava <praan@google.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/iommufd/eventq.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/iommu/iommufd/eventq.c
++++ b/drivers/iommu/iommufd/eventq.c
+@@ -168,6 +168,8 @@ static ssize_t iommufd_fault_fops_read(s
+                       }
+                       done += fault_size;
+               }
++              if (rc)
++                      break;
+       }
+       mutex_unlock(&fault->mutex);
diff --git a/queue-7.1/iommufd-fix-data_len-byte-count-vs-element-count-mismatch.patch b/queue-7.1/iommufd-fix-data_len-byte-count-vs-element-count-mismatch.patch
new file mode 100644 (file)
index 0000000..6a7e3d0
--- /dev/null
@@ -0,0 +1,40 @@
+From 85345becfead3255a5f875d4b4d82ea01d926239 Mon Sep 17 00:00:00 2001
+From: Nicolin Chen <nicolinc@nvidia.com>
+Date: Thu, 21 May 2026 17:36:32 -0700
+Subject: iommufd: Fix data_len byte-count vs element-count mismatch
+
+From: Nicolin Chen <nicolinc@nvidia.com>
+
+commit 85345becfead3255a5f875d4b4d82ea01d926239 upstream.
+
+kzalloc_flex() computes the allocation size. With event_data typed as u64,
+data_len is interpreted as a u64 element count. Yet, every caller and the
+read path treat data_len as a byte count. The current code over-allocates
+by sizeof(u64) and the __counted_by() annotation overstates the length by
+the same factor.
+
+Re-type event_data as u8. No functional change in user-visible behavior.
+
+Fixes: e36ba5ab808e ("iommufd: Add IOMMUFD_OBJ_VEVENTQ and IOMMUFD_CMD_VEVENTQ_ALLOC")
+Link: https://patch.msgid.link/r/f7665f839b9dce917d6bd394375a1cf56568d86b.1779408671.git.nicolinc@nvidia.com
+Cc: stable@vger.kernel.org
+Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/iommufd/iommufd_private.h |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/iommu/iommufd/iommufd_private.h
++++ b/drivers/iommu/iommufd/iommufd_private.h
+@@ -602,7 +602,7 @@ struct iommufd_vevent {
+       struct iommufd_vevent_header header;
+       struct list_head node; /* for iommufd_eventq::deliver */
+       ssize_t data_len;
+-      u64 event_data[] __counted_by(data_len);
++      u8 event_data[] __counted_by(data_len);
+ };
+ #define vevent_for_lost_events_header(vevent) \
diff --git a/queue-7.1/iommufd-move-vevent-memory-allocation-outside-spinlock.patch b/queue-7.1/iommufd-move-vevent-memory-allocation-outside-spinlock.patch
new file mode 100644 (file)
index 0000000..b8fdd28
--- /dev/null
@@ -0,0 +1,63 @@
+From 47443565d10c51366c9382dbc8597cd6c460b8a2 Mon Sep 17 00:00:00 2001
+From: Nicolin Chen <nicolinc@nvidia.com>
+Date: Thu, 21 May 2026 17:36:33 -0700
+Subject: iommufd: Move vevent memory allocation outside spinlock
+
+From: Nicolin Chen <nicolinc@nvidia.com>
+
+commit 47443565d10c51366c9382dbc8597cd6c460b8a2 upstream.
+
+The veventq memory allocation happens inside the spinlock. Given its depth
+is decided by the user space, this leaves a vulnerability, where userspace
+can allocate large queues to exhaust atomic memory reserves.
+
+Move the allocation outside the spinlock and use GFP_NOWAIT, which can fail
+fast under memory pressure without dipping into the GFP_ATOMIC reserves or
+direct-reclaiming from the threaded IRQ handler. On allocation failure,
+queue the lost_events_header (so userspace learns of the drop) and return
+-ENOMEM so the caller learns of the kernel-side memory pressure.
+
+This is intentionally distinct from the queue-overflow path, which also
+queues the lost_events_header but returns 0: a full queue is an expected
+userspace-pacing condition rather than a kernel error.
+
+A subsequent change will cap the upper bound of the veventq_depth.
+
+Fixes: e36ba5ab808e ("iommufd: Add IOMMUFD_OBJ_VEVENTQ and IOMMUFD_CMD_VEVENTQ_ALLOC")
+Link: https://patch.msgid.link/r/5ff36b5d80f7f6299f851be532a5195c1d2f1dae.1779408671.git.nicolinc@nvidia.com
+Cc: stable@vger.kernel.org
+Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/iommufd/driver.c |   13 ++++++++-----
+ 1 file changed, 8 insertions(+), 5 deletions(-)
+
+--- a/drivers/iommu/iommufd/driver.c
++++ b/drivers/iommu/iommufd/driver.c
+@@ -149,15 +149,18 @@ int iommufd_viommu_report_event(struct i
+               goto out_unlock_veventqs;
+       }
+-      spin_lock(&veventq->common.lock);
+-      if (veventq->num_events == veventq->depth) {
++      /* Pre-allocate to avoid GFP_ATOMIC; use GFP_NOWAIT to avoid sleeping */
++      vevent = kzalloc_flex(*vevent, event_data, data_len, GFP_NOWAIT);
++      if (!vevent) {
++              spin_lock(&veventq->common.lock);
+               vevent = &veventq->lost_events_header;
++              rc = -ENOMEM;
+               goto out_set_header;
+       }
+-      vevent = kzalloc_flex(*vevent, event_data, data_len, GFP_ATOMIC);
+-      if (!vevent) {
+-              rc = -ENOMEM;
++      spin_lock(&veventq->common.lock);
++      if (veventq->num_events == veventq->depth) {
++              kfree(vevent);
+               vevent = &veventq->lost_events_header;
+               goto out_set_header;
+       }
diff --git a/queue-7.1/iommufd-propagate-allocation-failure-in-iommufd_veventq_deliver_fetch.patch b/queue-7.1/iommufd-propagate-allocation-failure-in-iommufd_veventq_deliver_fetch.patch
new file mode 100644 (file)
index 0000000..d577f74
--- /dev/null
@@ -0,0 +1,53 @@
+From 489e63dd120bad52eba63f5506c214750cd5bc75 Mon Sep 17 00:00:00 2001
+From: Nicolin Chen <nicolinc@nvidia.com>
+Date: Mon, 1 Jun 2026 13:42:34 -0700
+Subject: iommufd: Propagate allocation failure in iommufd_veventq_deliver_fetch()
+
+From: Nicolin Chen <nicolinc@nvidia.com>
+
+commit 489e63dd120bad52eba63f5506c214750cd5bc75 upstream.
+
+When the kzalloc_obj() fails in iommufd_veventq_deliver_fetch(), it returns
+NULL, falsely advertising to userspace that the queue is empty.
+
+Propagate the -ENOMEM properly to the caller.
+
+Fixes: e36ba5ab808e ("iommufd: Add IOMMUFD_OBJ_VEVENTQ and IOMMUFD_CMD_VEVENTQ_ALLOC")
+Link: https://patch.msgid.link/r/25d29feac909e36f78c145fa99ef2d4cb7a415da.1780343944.git.nicolinc@nvidia.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Pranjal Shrivastava <praan@google.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/iommufd/eventq.c |   10 +++++++++-
+ 1 file changed, 9 insertions(+), 1 deletion(-)
+
+--- a/drivers/iommu/iommufd/eventq.c
++++ b/drivers/iommu/iommufd/eventq.c
+@@ -264,8 +264,10 @@ iommufd_veventq_deliver_fetch(struct iom
+               /* Make a copy of the lost_events_header for copy_to_user */
+               if (next == &veventq->lost_events_header) {
+                       vevent = kzalloc_obj(*vevent, GFP_ATOMIC);
+-                      if (!vevent)
++                      if (!vevent) {
++                              vevent = ERR_PTR(-ENOMEM);
+                               goto out_unlock;
++                      }
+               }
+               list_del(&next->node);
+               if (vevent)
+@@ -315,6 +317,12 @@ static ssize_t iommufd_veventq_fops_read
+               return -EINVAL;
+       while ((cur = iommufd_veventq_deliver_fetch(veventq))) {
++              if (IS_ERR(cur)) {
++                      if (done == 0)
++                              rc = PTR_ERR(cur);
++                      break;
++              }
++
+               /* Validate the remaining bytes against the header size */
+               if (done >= count || sizeof(*hdr) > count - done) {
+                       iommufd_veventq_deliver_restore(veventq, cur);
diff --git a/queue-7.1/iommufd-reject-invalid-read-count-in-iommufd_fault_fops_read.patch b/queue-7.1/iommufd-reject-invalid-read-count-in-iommufd_fault_fops_read.patch
new file mode 100644 (file)
index 0000000..df7b7b7
--- /dev/null
@@ -0,0 +1,40 @@
+From 47916a54eeb2a9e654512ee609f71bd5b29db702 Mon Sep 17 00:00:00 2001
+From: Nicolin Chen <nicolinc@nvidia.com>
+Date: Mon, 1 Jun 2026 13:42:35 -0700
+Subject: iommufd: Reject invalid read count in iommufd_fault_fops_read()
+
+From: Nicolin Chen <nicolinc@nvidia.com>
+
+commit 47916a54eeb2a9e654512ee609f71bd5b29db702 upstream.
+
+The read count must be large enough to hold one fault or a group's faults.
+
+iommufd_fault_fops_read() does not validate the count, but returns 0 as if
+the read had succeeded while leaving the pending fault in the queue.
+
+Return -EINVAL in the undersize cases.
+
+Fixes: 07838f7fd529 ("iommufd: Add iommufd fault object")
+Link: https://patch.msgid.link/r/85c118a606fbedc5c132a1f5ec223a5ba23b92d2.1780343944.git.nicolinc@nvidia.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Pranjal Shrivastava <praan@google.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/iommufd/eventq.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/iommu/iommufd/eventq.c
++++ b/drivers/iommu/iommufd/eventq.c
+@@ -142,6 +142,9 @@ static ssize_t iommufd_fault_fops_read(s
+               if (done >= count ||
+                   group->fault_count * fault_size > count - done) {
+                       iommufd_fault_deliver_restore(fault, group);
++                      /* Read count doesn't fit the first fault group */
++                      if (done == 0)
++                              rc = -EINVAL;
+                       break;
+               }
diff --git a/queue-7.1/iommufd-reject-invalid-read-count-in-iommufd_veventq_fops_read.patch b/queue-7.1/iommufd-reject-invalid-read-count-in-iommufd_veventq_fops_read.patch
new file mode 100644 (file)
index 0000000..d56bc89
--- /dev/null
@@ -0,0 +1,51 @@
+From 00203ca8323f9714630408c19a209b52397975e6 Mon Sep 17 00:00:00 2001
+From: Nicolin Chen <nicolinc@nvidia.com>
+Date: Mon, 1 Jun 2026 13:42:33 -0700
+Subject: iommufd: Reject invalid read count in iommufd_veventq_fops_read()
+
+From: Nicolin Chen <nicolinc@nvidia.com>
+
+commit 00203ca8323f9714630408c19a209b52397975e6 upstream.
+
+The read count must be large enough to hold a vEVENT header. For a normal
+vEVENT, it must also hold the trailing data following the header.
+
+iommufd_veventq_fops_read() does not validate the count, but returns 0 as
+if the read had succeeded while leaving the pending event in the queue.
+
+Return -EINVAL in both undersize cases.
+
+Fixes: e36ba5ab808e ("iommufd: Add IOMMUFD_OBJ_VEVENTQ and IOMMUFD_CMD_VEVENTQ_ALLOC")
+Link: https://patch.msgid.link/r/e1111adcc8a8882fbfd84accd6674dc846dc5689.1780343944.git.nicolinc@nvidia.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Pranjal Shrivastava <praan@google.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/iommufd/eventq.c |    6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/iommu/iommufd/eventq.c
++++ b/drivers/iommu/iommufd/eventq.c
+@@ -310,6 +310,9 @@ static ssize_t iommufd_veventq_fops_read
+       if (*ppos)
+               return -ESPIPE;
++      /* Minimum read count is a vEVENT header */
++      if (count < sizeof(*hdr))
++              return -EINVAL;
+       while ((cur = iommufd_veventq_deliver_fetch(veventq))) {
+               /* Validate the remaining bytes against the header size */
+@@ -323,6 +326,9 @@ static ssize_t iommufd_veventq_fops_read
+               if (!vevent_for_lost_events_header(cur) &&
+                   sizeof(*hdr) + cur->data_len > count - done) {
+                       iommufd_veventq_deliver_restore(veventq, cur);
++                      /* Read count doesn't fit a single normal vEVENT */
++                      if (done == 0)
++                              rc = -EINVAL;
+                       break;
+               }
diff --git a/queue-7.1/iommufd-rewind-header-length-in-done-if-iommufd_veventq_fops_read-fails.patch b/queue-7.1/iommufd-rewind-header-length-in-done-if-iommufd_veventq_fops_read-fails.patch
new file mode 100644 (file)
index 0000000..5fd2359
--- /dev/null
@@ -0,0 +1,36 @@
+From 01e41ad76c12ae5c49ab4ef4fc7dd54e9b8784d6 Mon Sep 17 00:00:00 2001
+From: Nicolin Chen <nicolinc@nvidia.com>
+Date: Mon, 1 Jun 2026 13:42:32 -0700
+Subject: iommufd: Rewind header length in done if iommufd_veventq_fops_read() fails
+
+From: Nicolin Chen <nicolinc@nvidia.com>
+
+commit 01e41ad76c12ae5c49ab4ef4fc7dd54e9b8784d6 upstream.
+
+When the first event copy fails, rc = -EFAULT will not be reported as done
+is set to the length of the copied header.
+
+Rewind it to report rc correctly.
+
+Fixes: e36ba5ab808e ("iommufd: Add IOMMUFD_OBJ_VEVENTQ and IOMMUFD_CMD_VEVENTQ_ALLOC")
+Link: https://patch.msgid.link/r/78f8caeb6a5d667a26b870e3068cec47dd4b5be1.1780343944.git.nicolinc@nvidia.com
+Cc: stable@vger.kernel.org
+Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Pranjal Shrivastava <praan@google.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/iommufd/eventq.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/iommu/iommufd/eventq.c
++++ b/drivers/iommu/iommufd/eventq.c
+@@ -336,6 +336,7 @@ static ssize_t iommufd_veventq_fops_read
+               if (cur->data_len &&
+                   copy_to_user(buf + done, cur->event_data, cur->data_len)) {
+                       iommufd_veventq_deliver_restore(veventq, cur);
++                      done -= sizeof(*hdr);
+                       rc = -EFAULT;
+                       break;
+               }
diff --git a/queue-7.1/iommufd-set-upper-bounds-on-cache-invalidation-entry_num-and-entry_len.patch b/queue-7.1/iommufd-set-upper-bounds-on-cache-invalidation-entry_num-and-entry_len.patch
new file mode 100644 (file)
index 0000000..d67dc55
--- /dev/null
@@ -0,0 +1,62 @@
+From 4d70986002f2f3eaaed89124fb2522bded38b016 Mon Sep 17 00:00:00 2001
+From: Nicolin Chen <nicolinc@nvidia.com>
+Date: Wed, 3 Jun 2026 14:26:53 -0700
+Subject: iommufd: Set upper bounds on cache invalidation entry_num and entry_len
+
+From: Nicolin Chen <nicolinc@nvidia.com>
+
+commit 4d70986002f2f3eaaed89124fb2522bded38b016 upstream.
+
+iommufd_hwpt_invalidate() takes a user-controlled entry_num and entry_len,
+each bounded only by U32_MAX. An entry_len beyond the kernel's struct size
+makes the copy helper verify the extra bytes are zero, scanning that excess
+in one uninterruptible pass; a multi-gigabyte value over zeroed user memory
+trips the soft-lockup watchdog.
+
+A large entry_num is the other half, driving the backend invalidation loop
+with no reschedule. The VT-d nested handler, for one, copies each entry and
+flushes caches per iteration, pinning the CPU on a non-preemptible kernel.
+
+Cap both in the ioctl. entry_len is held under PAGE_SIZE, above any request
+struct, and entry_num under 1 << 19, the order of a hardware invalidation
+queue and well beyond any real batch, bounding the per-call loop length.
+
+Fixes: 8c6eabae3807 ("iommufd: Add IOMMU_HWPT_INVALIDATE")
+Link: https://patch.msgid.link/r/447fa93663f7526eb361719e83fa8b649464483d.1780521606.git.nicolinc@nvidia.com
+Cc: stable@vger.kernel.org
+Assisted-by: Claude:claude-opus-4-8
+Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/iommufd/hw_pagetable.c |   11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+--- a/drivers/iommu/iommufd/hw_pagetable.c
++++ b/drivers/iommu/iommufd/hw_pagetable.c
+@@ -489,6 +489,9 @@ int iommufd_hwpt_get_dirty_bitmap(struct
+       return rc;
+ }
++/* An arbitrary entry_num cap, far above any realistic invalidation batch */
++#define IOMMU_HWPT_INVALIDATE_ENTRY_NUM_MAX (1U << 19)
++
+ int iommufd_hwpt_invalidate(struct iommufd_ucmd *ucmd)
+ {
+       struct iommu_hwpt_invalidate *cmd = ucmd->cmd;
+@@ -507,7 +510,13 @@ int iommufd_hwpt_invalidate(struct iommu
+               goto out;
+       }
+-      if (cmd->entry_num && (!cmd->data_uptr || !cmd->entry_len)) {
++      /*
++       * Bound entry_num and entry_len so a single call cannot pin the CPU;
++       * entry_len also caps the copy_struct_from_user() trailing-zero scan.
++       */
++      if (cmd->entry_num &&
++          (!cmd->data_uptr || !cmd->entry_len || cmd->entry_len > PAGE_SIZE ||
++           cmd->entry_num > IOMMU_HWPT_INVALIDATE_ENTRY_NUM_MAX)) {
+               rc = -EINVAL;
+               goto out;
+       }
diff --git a/queue-7.1/iommufd-set-veventq_depth-upper-bound.patch b/queue-7.1/iommufd-set-veventq_depth-upper-bound.patch
new file mode 100644 (file)
index 0000000..0ed09f4
--- /dev/null
@@ -0,0 +1,51 @@
+From 6ebf2eb46fbd5b40393ff8fbb847ba96925beaff Mon Sep 17 00:00:00 2001
+From: Nicolin Chen <nicolinc@nvidia.com>
+Date: Thu, 21 May 2026 17:36:34 -0700
+Subject: iommufd: Set veventq_depth upper bound
+
+From: Nicolin Chen <nicolinc@nvidia.com>
+
+commit 6ebf2eb46fbd5b40393ff8fbb847ba96925beaff upstream.
+
+iommufd_veventq_alloc() accepts any !0 veventq_depth from userspace, with
+an upper bound at U32_MAX.
+
+This leaves a vulnerability where userspace can allocate excessively large
+queues to exhaust kernel memory reserves.
+
+Cap the veventq_depth (maximum number of entries) to 1 << 19, matching the
+maximum number of entries in the SMMUv3 EVTQ (the largest use case today).
+
+Fixes: e36ba5ab808e ("iommufd: Add IOMMUFD_OBJ_VEVENTQ and IOMMUFD_CMD_VEVENTQ_ALLOC")
+Link: https://patch.msgid.link/r/8426cbaa5e8294472ec7f076ef427cc473be5985.1779408671.git.nicolinc@nvidia.com
+Cc: stable@vger.kernel.org
+Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/iommufd/eventq.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/iommu/iommufd/eventq.c
++++ b/drivers/iommu/iommufd/eventq.c
+@@ -473,6 +473,9 @@ int iommufd_fault_iopf_handler(struct io
+ static const struct file_operations iommufd_veventq_fops =
+       INIT_EVENTQ_FOPS(iommufd_veventq_fops_read, NULL);
++/* An arbitrary upper bound for veventq_depth that fits all existing HWs */
++#define VEVENTQ_MAX_DEPTH (1U << 19)
++
+ int iommufd_veventq_alloc(struct iommufd_ucmd *ucmd)
+ {
+       struct iommu_veventq_alloc *cmd = ucmd->cmd;
+@@ -484,7 +487,7 @@ int iommufd_veventq_alloc(struct iommufd
+       if (cmd->flags || cmd->__reserved ||
+           cmd->type == IOMMU_VEVENTQ_TYPE_DEFAULT)
+               return -EOPNOTSUPP;
+-      if (!cmd->veventq_depth)
++      if (!cmd->veventq_depth || cmd->veventq_depth > VEVENTQ_MAX_DEPTH)
+               return -EINVAL;
+       viommu = iommufd_get_viommu(ucmd, cmd->viommu_id);
diff --git a/queue-7.1/iommufd-use-sizeof-hdr-instead-of-sizeof-hdr-in-veventq-read.patch b/queue-7.1/iommufd-use-sizeof-hdr-instead-of-sizeof-hdr-in-veventq-read.patch
new file mode 100644 (file)
index 0000000..3fbbe66
--- /dev/null
@@ -0,0 +1,68 @@
+From be93d186ae88a92e7aa77e122d4e661fa57b1e39 Mon Sep 17 00:00:00 2001
+From: Kai Aizen <kai.aizen.dev@gmail.com>
+Date: Thu, 30 Apr 2026 20:56:30 +0300
+Subject: iommufd: Use sizeof(*hdr) instead of sizeof(hdr) in veventq read
+
+From: Kai Aizen <kai.aizen.dev@gmail.com>
+
+commit be93d186ae88a92e7aa77e122d4e661fa57b1e39 upstream.
+
+The bound-check in iommufd_veventq_fops_read() for the normal vEVENT
+path uses sizeof(hdr) where the surrounding code uses sizeof(*hdr):
+
+       if (!vevent_for_lost_events_header(cur) &&
+           sizeof(hdr) + cur->data_len > count - done) {
+
+hdr is declared as struct iommufd_vevent_header *, so sizeof(hdr)
+evaluates to the size of the pointer.  Surrounding code uses
+sizeof(*hdr) consistently:
+
+       if (done >= count || sizeof(*hdr) > count - done) {
+       ...
+       if (copy_to_user(buf + done, hdr, sizeof(*hdr))) {
+       ...
+       done += sizeof(*hdr);
+
+struct iommufd_vevent_header is currently 8 bytes (two __u32 fields,
+flags and sequence), so on 64-bit (sizeof(void *) == 8) the two
+expressions happen to be equal and the check works as intended.
+
+On 32-bit (sizeof(void *) == 4) the check under-counts the header by
+4 bytes: a vEVENT whose data_len causes 8 + cur->data_len to exceed
+count - done while 4 + cur->data_len does not will pass the check,
+then the loop will copy_to_user 8 bytes of header followed by data_len
+bytes of payload, writing past the user-supplied buffer.
+
+It is also a latent bug for any future expansion of struct
+iommufd_vevent_header beyond sizeof(void *) on 64-bit; the check
+should not depend on the type happening to match the host pointer
+width.
+
+Use sizeof(*hdr) to match the rest of the function and the actual
+amount that will be copied.
+
+Fixes: e36ba5ab808e ("iommufd: Add IOMMUFD_OBJ_VEVENTQ and IOMMUFD_CMD_VEVENTQ_ALLOC")
+Link: https://patch.msgid.link/r/20260430175630.67078-1-kai.aizen.dev@gmail.com
+Cc: stable@vger.kernel.org
+Reported-by: Kai Aizen <kai.aizen.dev@gmail.com>
+Signed-off-by: Kai Aizen <kai.aizen.dev@gmail.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/iommufd/eventq.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/iommu/iommufd/eventq.c
++++ b/drivers/iommu/iommufd/eventq.c
+@@ -321,7 +321,7 @@ static ssize_t iommufd_veventq_fops_read
+               /* If being a normal vEVENT, validate against the full size */
+               if (!vevent_for_lost_events_header(cur) &&
+-                  sizeof(hdr) + cur->data_len > count - done) {
++                  sizeof(*hdr) + cur->data_len > count - done) {
+                       iommufd_veventq_deliver_restore(veventq, cur);
+                       break;
+               }
diff --git a/queue-7.1/kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-vcpu.patch b/queue-7.1/kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-vcpu.patch
new file mode 100644 (file)
index 0000000..3d57fea
--- /dev/null
@@ -0,0 +1,83 @@
+From 8cc8bbbfab14c22c5551d0dd19b208a44b141c76 Mon Sep 17 00:00:00 2001
+From: Hyunwoo Kim <imv4bel@gmail.com>
+Date: Sun, 7 Jun 2026 02:56:11 +0900
+Subject: KVM: arm64: Bound used_lrs when flushing the pKVM hyp vCPU
+
+From: Hyunwoo Kim <imv4bel@gmail.com>
+
+commit 8cc8bbbfab14c22c5551d0dd19b208a44b141c76 upstream.
+
+flush_hyp_vcpu() copies the host vGIC state into the hyp's private vCPU
+on every run. The vGIC list register save and restore use used_lrs as
+their loop bound and expect it to stay within the number of implemented
+list registers. While this is generally the case, flush_hyp_vcpu()
+copies vgic_v3 verbatim and does not enforce this, so a value provided
+by the host is used at EL2 to index vgic_lr[] and access ICH_LR<n>_EL2
+(host -> EL2).
+
+Fix by clamping used_lrs to the number of implemented list registers
+after the copy, as the trusted path already does in
+vgic_flush_lr_state(). The number of implemented list registers is
+constant after init, so it is replicated once from
+kvm_vgic_global_state.nr_lr into hyp_gicv3_nr_lr rather than read on
+every entry.
+
+Cc: stable@vger.kernel.org
+Fixes: be66e67f1750 ("KVM: arm64: Use the pKVM hyp vCPU structure in handle___kvm_vcpu_run()")
+Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
+Reviewed-by: Fuad Tabba <tabba@google.com>
+Tested-by: Fuad Tabba <tabba@google.com>
+Link: https://patch.msgid.link/20260606175614.83273-3-imv4bel@gmail.com
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm64/include/asm/kvm_hyp.h   |    1 +
+ arch/arm64/kvm/arm.c               |    2 ++
+ arch/arm64/kvm/hyp/nvhe/hyp-main.c |    9 +++++++++
+ 3 files changed, 12 insertions(+)
+
+--- a/arch/arm64/include/asm/kvm_hyp.h
++++ b/arch/arm64/include/asm/kvm_hyp.h
+@@ -157,5 +157,6 @@ extern unsigned long kvm_nvhe_sym(__icac
+ extern unsigned int kvm_nvhe_sym(kvm_arm_vmid_bits);
+ extern unsigned int kvm_nvhe_sym(kvm_host_sve_max_vl);
+ extern unsigned long kvm_nvhe_sym(hyp_nr_cpus);
++extern unsigned int kvm_nvhe_sym(hyp_gicv3_nr_lr);
+ #endif /* __ARM64_KVM_HYP_H__ */
+--- a/arch/arm64/kvm/arm.c
++++ b/arch/arm64/kvm/arm.c
+@@ -2426,6 +2426,8 @@ static int __init init_subsystems(void)
+       switch (err) {
+       case 0:
+               vgic_present = true;
++              if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
++                      kvm_nvhe_sym(hyp_gicv3_nr_lr) = kvm_vgic_global_state.nr_lr;
+               break;
+       case -ENODEV:
+       case -ENXIO:
+--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
++++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+@@ -24,6 +24,9 @@
+ DEFINE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
++/* Number of implemented GICv3 LRs. Used by flush_hyp_vcpu(). */
++unsigned int hyp_gicv3_nr_lr;
++
+ void __kvm_hyp_host_forward_smc(struct kvm_cpu_context *host_ctxt);
+ static void __hyp_sve_save_guest(struct kvm_vcpu *vcpu)
+@@ -139,6 +142,12 @@ static void flush_hyp_vcpu(struct pkvm_h
+       hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3 = host_vcpu->arch.vgic_cpu.vgic_v3;
++      /* Bound used_lrs by the number of implemented list registers. */
++      hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3.used_lrs =
++              min_t(unsigned int,
++                    hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3.used_lrs,
++                    hyp_gicv3_nr_lr);
++
+       hyp_vcpu->vcpu.arch.pid = host_vcpu->arch.pid;
+ }
diff --git a/queue-7.1/kvm-arm64-clear-__hyp_running_vcpu-when-flushing-the-pkvm-hyp-vcpu.patch b/queue-7.1/kvm-arm64-clear-__hyp_running_vcpu-when-flushing-the-pkvm-hyp-vcpu.patch
new file mode 100644 (file)
index 0000000..3220176
--- /dev/null
@@ -0,0 +1,43 @@
+From e8042f6e1d7befb2fb6b10a75918642bcd0acf9a Mon Sep 17 00:00:00 2001
+From: Hyunwoo Kim <imv4bel@gmail.com>
+Date: Sun, 7 Jun 2026 02:56:10 +0900
+Subject: KVM: arm64: Clear __hyp_running_vcpu when flushing the pKVM hyp vCPU
+
+From: Hyunwoo Kim <imv4bel@gmail.com>
+
+commit e8042f6e1d7befb2fb6b10a75918642bcd0acf9a upstream.
+
+flush_hyp_vcpu() copies the host vCPU context into the hyp's private
+vCPU on every run. ctxt_to_vcpu() expects a guest context to have a
+NULL __hyp_running_vcpu, which is only ever set on the host context, so
+that it resolves the vCPU via container_of(). While this is generally
+the case, flush_hyp_vcpu() copies the context verbatim and does not
+enforce this, so a value provided by the host is dereferenced at EL2
+(host -> EL2).
+
+Fix by clearing __hyp_running_vcpu after the copy.
+
+Cc: stable@vger.kernel.org
+Fixes: be66e67f1750 ("KVM: arm64: Use the pKVM hyp vCPU structure in handle___kvm_vcpu_run()")
+Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
+Reviewed-by: Fuad Tabba <tabba@google.com>
+Tested-by: Fuad Tabba <tabba@google.com>
+Link: https://patch.msgid.link/20260606175614.83273-2-imv4bel@gmail.com
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm64/kvm/hyp/nvhe/hyp-main.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
++++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+@@ -131,6 +131,9 @@ static void flush_hyp_vcpu(struct pkvm_h
+       hyp_vcpu->vcpu.arch.ctxt        = host_vcpu->arch.ctxt;
++      /* __hyp_running_vcpu must be NULL in a guest context. */
++      hyp_vcpu->vcpu.arch.ctxt.__hyp_running_vcpu = NULL;
++
+       hyp_vcpu->vcpu.arch.mdcr_el2    = host_vcpu->arch.mdcr_el2;
+       hyp_vcpu->vcpu.arch.hcr_el2 &= ~(HCR_TWI | HCR_TWE);
+       hyp_vcpu->vcpu.arch.hcr_el2 |= READ_ONCE(host_vcpu->arch.hcr_el2) &
diff --git a/queue-7.1/kvm-arm64-don-t-leak-pfn-when-kvm_translate_vncr-races-mmu-notifier.patch b/queue-7.1/kvm-arm64-don-t-leak-pfn-when-kvm_translate_vncr-races-mmu-notifier.patch
new file mode 100644 (file)
index 0000000..d69523d
--- /dev/null
@@ -0,0 +1,38 @@
+From 9f76b039a72d7e06374aa96862f0232ed53f7787 Mon Sep 17 00:00:00 2001
+From: Oliver Upton <oupton@kernel.org>
+Date: Tue, 2 Jun 2026 16:54:46 -0700
+Subject: KVM: arm64: Don't leak PFN when kvm_translate_vncr() races MMU notifier
+
+From: Oliver Upton <oupton@kernel.org>
+
+commit 9f76b039a72d7e06374aa96862f0232ed53f7787 upstream.
+
+In the case that kvm_translate_vncr() races with an MMU notifier the
+early return does not release a reference on the faulted in PFN. Add
+the necessary call to kvm_release_faultin_page() for the unused PFN.
+
+Cc: stable@vger.kernel.org
+Fixes: 069a05e535496 ("KVM: arm64: nv: Handle VNCR_EL2-triggered faults")
+Reported-by: Sashiko (local):gemini-3.1-pro
+Signed-off-by: Oliver Upton <oupton@kernel.org>
+Link: https://patch.msgid.link/20260602235450.103057-2-oupton@kernel.org
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm64/kvm/nested.c |    4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+--- a/arch/arm64/kvm/nested.c
++++ b/arch/arm64/kvm/nested.c
+@@ -1327,8 +1327,10 @@ static int kvm_translate_vncr(struct kvm
+       }
+       scoped_guard(write_lock, &vcpu->kvm->mmu_lock) {
+-              if (mmu_invalidate_retry(vcpu->kvm, mmu_seq))
++              if (mmu_invalidate_retry(vcpu->kvm, mmu_seq)) {
++                      kvm_release_faultin_page(vcpu->kvm, page, true, false);
+                       return -EAGAIN;
++              }
+               vt->gva = va;
+               vt->hpa = pfn << PAGE_SHIFT;
diff --git a/queue-7.1/kvm-arm64-nv-avoid-dereferencing-null-vncr-pseudo-tlb.patch b/queue-7.1/kvm-arm64-nv-avoid-dereferencing-null-vncr-pseudo-tlb.patch
new file mode 100644 (file)
index 0000000..08233c5
--- /dev/null
@@ -0,0 +1,104 @@
+From 4be6cbeb93d26994bd1827ddbce391e3c4395c8f Mon Sep 17 00:00:00 2001
+From: Marc Zyngier <maz@kernel.org>
+Date: Sun, 7 Jun 2026 18:57:45 +0100
+Subject: KVM: arm64: nv: Avoid dereferencing NULL VNCR pseudo-TLB
+
+From: Marc Zyngier <maz@kernel.org>
+
+commit 4be6cbeb93d26994bd1827ddbce391e3c4395c8f upstream.
+
+VNCR TLB invalidation occurs from MMU notifiers or TLBI instructions,
+and either can race against a vcpu not being onlined yet (no pseudo-TLB
+allocated). Similarly, the TLB might be invalid, and the invalidation
+should be skipped in this case.
+
+Both kvm_invalidate_vncr_ipa() and kvm_invalidate_vncr_va() are
+expected to perform the same checks, except that the latter doesn't
+check for the allocation and blindly dereferences the pointer.
+
+Solve this by introducing a new iterator built on top of the usual
+kvm_for_each_vcpu() that checks for both of the above conditions,
+and convert the two users to it.
+
+Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
+Link: https://lore.kernel.org/r/aiUvSbrWndQeUPc8@v4bel
+Fixes: 4ffa72ad8f37 ("KVM: arm64: nv: Add S1 TLB invalidation primitive for VNCR_EL2")
+Cc: stable@vger.kernel.org
+Reviewed-by: Oliver Upton <oupton@kernel.org>
+Link: https://patch.msgid.link/20260607175745.297793-1-maz@kernel.org
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm64/kvm/nested.c |   36 +++++++++++++++---------------------
+ 1 file changed, 15 insertions(+), 21 deletions(-)
+
+--- a/arch/arm64/kvm/nested.c
++++ b/arch/arm64/kvm/nested.c
+@@ -904,9 +904,21 @@ static void invalidate_vncr(struct vncr_
+               clear_fixmap(vncr_fixmap(vt->cpu));
+ }
++/*
++ * VNCR TLB invalidation occurs from MMU notifiers or TLBI instructions, and
++ * either can race against a vcpu not being onlined yet (no pseudo-TLB
++ * allocated). Similarly, the TLB might be invalid.  Skip those, as they
++ * obviously don't participate in the invalidation at this stage.
++ */
++#define kvm_for_each_vncr_tlb(idx, vcpup, tlbp, kvm)  \
++      kvm_for_each_vcpu(idx, vcpup, kvm)              \
++              if (((tlbp) = vcpup->arch.vncr_tlb) &&  \
++                  (tlbp)->valid)
++
+ static void kvm_invalidate_vncr_ipa(struct kvm *kvm, u64 start, u64 end)
+ {
+       struct kvm_vcpu *vcpu;
++      struct vncr_tlb *vt;
+       unsigned long i;
+       lockdep_assert_held_write(&kvm->mmu_lock);
+@@ -914,24 +926,9 @@ static void kvm_invalidate_vncr_ipa(stru
+       if (!kvm_has_feat(kvm, ID_AA64MMFR4_EL1, NV_frac, NV2_ONLY))
+               return;
+-      kvm_for_each_vcpu(i, vcpu, kvm) {
+-              struct vncr_tlb *vt = vcpu->arch.vncr_tlb;
++      kvm_for_each_vncr_tlb(i, vcpu, vt, kvm) {
+               u64 ipa_start, ipa_end, ipa_size;
+-              /*
+-               * Careful here: We end-up here from an MMU notifier,
+-               * and this can race against a vcpu not being onlined
+-               * yet, without the pseudo-TLB being allocated.
+-               *
+-               * Skip those, as they obviously don't participate in
+-               * the invalidation at this stage.
+-               */
+-              if (!vt)
+-                      continue;
+-
+-              if (!vt->valid)
+-                      continue;
+-
+               ipa_size = ttl_to_size(pgshift_level_to_ttl(vt->wi.pgshift,
+                                                           vt->wr.level));
+               ipa_start = vt->wr.pa & ~(ipa_size - 1);
+@@ -961,17 +958,14 @@ static void invalidate_vncr_va(struct kv
+                              struct s1e2_tlbi_scope *scope)
+ {
+       struct kvm_vcpu *vcpu;
++      struct vncr_tlb *vt;
+       unsigned long i;
+       lockdep_assert_held_write(&kvm->mmu_lock);
+-      kvm_for_each_vcpu(i, vcpu, kvm) {
+-              struct vncr_tlb *vt = vcpu->arch.vncr_tlb;
++      kvm_for_each_vncr_tlb(i, vcpu, vt, kvm) {
+               u64 va_start, va_end, va_size;
+-              if (!vt->valid)
+-                      continue;
+-
+               va_size = ttl_to_size(pgshift_level_to_ttl(vt->wi.pgshift,
+                                                          vt->wr.level));
+               va_start = vt->gva & ~(va_size - 1);
diff --git a/queue-7.1/kvm-guest_memfd-treat-memslot-binding-offset-size-as-unsigned-values.patch b/queue-7.1/kvm-guest_memfd-treat-memslot-binding-offset-size-as-unsigned-values.patch
new file mode 100644 (file)
index 0000000..196c6f3
--- /dev/null
@@ -0,0 +1,126 @@
+From eba85fee7fc6cf28fec38a5bf3c378bef9a79ca6 Mon Sep 17 00:00:00 2001
+From: Sean Christopherson <seanjc@google.com>
+Date: Tue, 2 Jun 2026 10:09:19 -0700
+Subject: KVM: guest_memfd: Treat memslot binding offset+size as unsigned values
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit eba85fee7fc6cf28fec38a5bf3c378bef9a79ca6 upstream.
+
+When binding a memslot to a guest_memfd file, treat the offset and size as
+unsigned values to fix a bug where the sum of the two can result in a false
+negative when checking for overflow against the size of the file.  Passing
+unsigned values also avoids relying on somewhat obscure checks in other
+flows for safety, and tracks the offset and size as they are intended to be
+tracked, as unsigned values.
+
+On 64-bit kernels, the number of pages a memslot contains and thus the size
+(and offset) of its guest_memfd binding are unsigned 64-bit values.  Taking
+the offset+size as an loff_t instead of a uoff_t inadvertently converts
+the unsigned value to a signed value if the offset and/or size is massive.
+
+Locally storing the offset and size as signed values is benign in and of
+itself (though even that is *extremely* difficult to discern), but
+operating on their sum is not.
+
+For the offset, KVM explicitly checks against a negative value, which might
+seem like a bug as KVM could incorrectly reject a legitimate binding, but
+that's not actually the case as KVM_CREATE_GUEST_MEMFD takes a signed value
+for its size, i.e. a would-be-negative offset is also greater than the
+maximum possible size of any guest_memfd file.
+
+Regarding the size, while KVM lacks an explicit check for a negative value,
+i.e. seemingly has a flawed overflow check, KVM restricts the number of
+pages in a single memslot to the largest positive signed 32-bit value:
+
+        if (id < KVM_USER_MEM_SLOTS &&
+            (mem->memory_size >> PAGE_SHIFT) > KVM_MEM_MAX_NR_PAGES)
+                return -EINVAL;
+
+and so that maximum "size" will ever be is 0x7fffffff000.
+
+The sum of the two is, however, problematic.  While the size is restricted
+by KVM's memslot logic, the offset is not, i.e. the offset is completely
+unchecked until the "offset + size > i_size_read(inode)" check.  If the
+offset is the (nearly) largest possible _positive_ value, then adding size
+to the offset can result in a signed, negative 64-bit value.  When compared
+against the size of the file (guaranteed to be positive), the negative sum
+is always smaller, and KVM incorrectly allows the absurd offset.
+
+Opportunistically add missing includes in kvm_mm.h (instead of relying on
+its parents).
+
+Fixes: a7800aa80ea4 ("KVM: Add KVM_CREATE_GUEST_MEMFD ioctl() for guest-specific backing memory")
+Cc: stable@vger.kernel.org
+Cc: Ackerley Tng <ackerleytng@google.com>
+Reviewed-by: Michael Roth <michael.roth@amd.com>
+Reviewed-by: Ackerley Tng <ackerleytng@google.com>
+Link: https://patch.msgid.link/20260602170921.1304394-2-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ virt/kvm/guest_memfd.c |    8 ++++----
+ virt/kvm/kvm_mm.h      |    7 +++++--
+ 2 files changed, 9 insertions(+), 6 deletions(-)
+
+--- a/virt/kvm/guest_memfd.c
++++ b/virt/kvm/guest_memfd.c
+@@ -640,15 +640,16 @@ int kvm_gmem_create(struct kvm *kvm, str
+ }
+ int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
+-                unsigned int fd, loff_t offset)
++                unsigned int fd, uoff_t offset)
+ {
+-      loff_t size = slot->npages << PAGE_SHIFT;
++      uoff_t size = slot->npages << PAGE_SHIFT;
+       unsigned long start, end;
+       struct gmem_file *f;
+       struct inode *inode;
+       struct file *file;
+       int r = -EINVAL;
++      BUILD_BUG_ON(sizeof(gpa_t) != sizeof(offset));
+       BUILD_BUG_ON(sizeof(gfn_t) != sizeof(slot->gmem.pgoff));
+       file = fget(fd);
+@@ -664,8 +665,7 @@ int kvm_gmem_bind(struct kvm *kvm, struc
+       inode = file_inode(file);
+-      if (offset < 0 || !PAGE_ALIGNED(offset) ||
+-          offset + size > i_size_read(inode))
++      if (!PAGE_ALIGNED(offset) || offset + size > i_size_read(inode))
+               goto err;
+       filemap_invalidate_lock(inode->i_mapping);
+--- a/virt/kvm/kvm_mm.h
++++ b/virt/kvm/kvm_mm.h
+@@ -3,6 +3,9 @@
+ #ifndef __KVM_MM_H__
+ #define __KVM_MM_H__ 1
++#include <linux/kvm.h>
++#include <linux/kvm_types.h>
++
+ /*
+  * Architectures can choose whether to use an rwlock or spinlock
+  * for the mmu_lock.  These macros, for use in common code
+@@ -72,7 +75,7 @@ int kvm_gmem_init(struct module *module)
+ void kvm_gmem_exit(void);
+ int kvm_gmem_create(struct kvm *kvm, struct kvm_create_guest_memfd *args);
+ int kvm_gmem_bind(struct kvm *kvm, struct kvm_memory_slot *slot,
+-                unsigned int fd, loff_t offset);
++                unsigned int fd, uoff_t offset);
+ void kvm_gmem_unbind(struct kvm_memory_slot *slot);
+ #else
+ static inline int kvm_gmem_init(struct module *module)
+@@ -82,7 +85,7 @@ static inline int kvm_gmem_init(struct m
+ static inline void kvm_gmem_exit(void) {};
+ static inline int kvm_gmem_bind(struct kvm *kvm,
+                                        struct kvm_memory_slot *slot,
+-                                       unsigned int fd, loff_t offset)
++                                       unsigned int fd, uoff_t offset)
+ {
+       WARN_ON_ONCE(1);
+       return -EIO;
diff --git a/queue-7.1/kvm-sev-don-t-terminate-snp-vms-on-vmgexit-without-a-registered-ghcb.patch b/queue-7.1/kvm-sev-don-t-terminate-snp-vms-on-vmgexit-without-a-registered-ghcb.patch
new file mode 100644 (file)
index 0000000..b69d332
--- /dev/null
@@ -0,0 +1,47 @@
+From 1797e00bf802d64b859ea18505087daad92019c8 Mon Sep 17 00:00:00 2001
+From: Sean Christopherson <seanjc@google.com>
+Date: Fri, 29 May 2026 20:35:43 +0200
+Subject: KVM: SEV: Don't terminate SNP VMs on #VMGEXIT without a registered GHCB
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit 1797e00bf802d64b859ea18505087daad92019c8 upstream.
+
+If the guest attempts a non-MSR #VMGEXIT without the registered GHCB,
+return a GHCB_HV_RESP_MALFORMED_INPUT+GHCB_ERR_NOT_REGISTERED error to the
+guest instead of exiting KVM_RUN with -EINVAL (and in likelihood killing
+the VM).  KVM has already mapped the requested GHCB, i.e. can cleanly
+report an error, and so exiting with -EINVAL is completely unjustified.
+
+Fixes: 0c76b1d08280 ("KVM: SEV: Add support to handle GHCB GPA register VMGEXIT")
+Cc: stable@vger.kernel.org
+Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
+Reviewed-by: Michael Roth <michael.roth@amd.com>
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Message-ID: <20260501202250.2115252-19-seanjc@google.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Message-ID: <20260529183549.1104619-19-pbonzini@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/svm/sev.c |    9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
+
+--- a/arch/x86/kvm/svm/sev.c
++++ b/arch/x86/kvm/svm/sev.c
+@@ -4522,9 +4522,12 @@ int sev_handle_vmgexit(struct kvm_vcpu *
+       sev_es_sync_from_ghcb(svm);
+       /* SEV-SNP guest requires that the GHCB GPA must be registered */
+-      if (is_sev_snp_guest(vcpu) && !ghcb_gpa_is_registered(svm, ghcb_gpa)) {
+-              vcpu_unimpl(&svm->vcpu, "vmgexit: GHCB GPA [%#llx] is not registered.\n", ghcb_gpa);
+-              return -EINVAL;
++      if (is_sev_snp_guest(vcpu) &&
++          !ghcb_gpa_is_registered(svm, control->ghcb_gpa)) {
++              vcpu_unimpl(vcpu, "vmgexit: GHCB GPA [%#llx] is not registered.\n",
++                          control->ghcb_gpa);
++              svm_vmgexit_bad_input(svm, GHCB_ERR_NOT_REGISTERED);
++              return 1;
+       }
+       ret = sev_es_validate_vmgexit(svm);
diff --git a/queue-7.1/kvm-sev-pin-source-page-for-write-when-adding-cpuid-data-for-snp-guest.patch b/queue-7.1/kvm-sev-pin-source-page-for-write-when-adding-cpuid-data-for-snp-guest.patch
new file mode 100644 (file)
index 0000000..dea5aed
--- /dev/null
@@ -0,0 +1,89 @@
+From f13e900599089b10113ceb36013423f0837c6792 Mon Sep 17 00:00:00 2001
+From: Sean Christopherson <seanjc@google.com>
+Date: Fri, 22 May 2026 15:46:06 -0700
+Subject: KVM: SEV: Pin source page for write when adding CPUID data for SNP guest
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit f13e900599089b10113ceb36013423f0837c6792 upstream.
+
+When populating a guest_memfd instance with the initial CPUID data for an
+SNP guest, acquire a writable pin on the source page as KVM will write back
+the "correct" CPUID information if the userspace provided data is rejected
+by trusted firmware.  Because KVM writes to the source page using a kernel
+mapping, pinning for read could result in KVM clobbering read-only memory.
+
+Note, well-behaved VMMs are unlikely to be affected, as CPUID information
+is almost always dynamically generated by userspace, i.e. it's unlikely for
+the CPUID information to be backed by a read-only mapping.
+
+Fixes: 2a62345b30529 ("KVM: guest_memfd: GUP source pages prior to populating guest memory")
+Cc: stable@vger.kernel.org
+Signed-off-by: Ackerley Tng <ackerleytng@google.com>
+Link: https://patch.msgid.link/20260522-fix-sev-gmem-post-populate-v2-1-3f196bfad5a1@google.com
+[sean: rewrite shortlog and changelog, tag for stable@]
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/svm/sev.c   |    1 +
+ arch/x86/kvm/vmx/tdx.c   |    2 +-
+ include/linux/kvm_host.h |    3 ++-
+ virt/kvm/guest_memfd.c   |    6 ++++--
+ 4 files changed, 8 insertions(+), 4 deletions(-)
+
+--- a/arch/x86/kvm/svm/sev.c
++++ b/arch/x86/kvm/svm/sev.c
+@@ -2470,6 +2470,7 @@ static int snp_launch_update(struct kvm
+       sev_populate_args.type = params.type;
+       count = kvm_gmem_populate(kvm, params.gfn_start, src, npages,
++                                params.type == KVM_SEV_SNP_PAGE_TYPE_CPUID,
+                                 sev_gmem_post_populate, &sev_populate_args);
+       if (count < 0) {
+               argp->error = sev_populate_args.fw_error;
+--- a/arch/x86/kvm/vmx/tdx.c
++++ b/arch/x86/kvm/vmx/tdx.c
+@@ -3185,7 +3185,7 @@ static int tdx_vcpu_init_mem_region(stru
+               };
+               gmem_ret = kvm_gmem_populate(kvm, gpa_to_gfn(region.gpa),
+                                            u64_to_user_ptr(region.source_addr),
+-                                           1, tdx_gmem_post_populate, &arg);
++                                           1, false, tdx_gmem_post_populate, &arg);
+               if (gmem_ret < 0) {
+                       ret = gmem_ret;
+                       break;
+--- a/include/linux/kvm_host.h
++++ b/include/linux/kvm_host.h
+@@ -2601,7 +2601,8 @@ int kvm_arch_gmem_prepare(struct kvm *kv
+ typedef int (*kvm_gmem_populate_cb)(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn,
+                                   struct page *page, void *opaque);
+-long kvm_gmem_populate(struct kvm *kvm, gfn_t gfn, void __user *src, long npages,
++long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src,
++                     long npages, bool may_writeback_src,
+                      kvm_gmem_populate_cb post_populate, void *opaque);
+ #endif
+--- a/virt/kvm/guest_memfd.c
++++ b/virt/kvm/guest_memfd.c
+@@ -858,7 +858,8 @@ out_unlock:
+       return ret;
+ }
+-long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src, long npages,
++long kvm_gmem_populate(struct kvm *kvm, gfn_t start_gfn, void __user *src,
++                     long npages, bool may_writeback_src,
+                      kvm_gmem_populate_cb post_populate, void *opaque)
+ {
+       struct kvm_memory_slot *slot;
+@@ -892,8 +893,9 @@ long kvm_gmem_populate(struct kvm *kvm,
+               if (src) {
+                       unsigned long uaddr = (unsigned long)src + i * PAGE_SIZE;
++                      unsigned int flags = may_writeback_src ? FOLL_WRITE : 0;
+-                      ret = get_user_pages_fast(uaddr, 1, 0, &src_page);
++                      ret = get_user_pages_fast(uaddr, 1, flags, &src_page);
+                       if (ret < 0)
+                               break;
+                       if (ret != 1) {
diff --git a/queue-7.1/kvm-svm-disable-x2avic-rdmsr-interception-for-msrs-kvm-actually-supports.patch b/queue-7.1/kvm-svm-disable-x2avic-rdmsr-interception-for-msrs-kvm-actually-supports.patch
new file mode 100644 (file)
index 0000000..a431c37
--- /dev/null
@@ -0,0 +1,79 @@
+From 7f4b7092d9a173a4271e28c0ed1fc235994e309b Mon Sep 17 00:00:00 2001
+From: Sean Christopherson <seanjc@google.com>
+Date: Thu, 14 May 2026 14:31:14 -0700
+Subject: KVM: SVM: Disable x2AVIC RDMSR interception for MSRs KVM actually supports
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit 7f4b7092d9a173a4271e28c0ed1fc235994e309b upstream.
+
+When toggling x2AVIC on/off, use KVM's curated mask of x2APIC MSRs that
+can/should be passed through to the guest (or not) when 2AVIC is enabled.
+Using the effective list provided by the local APIC emulation fixes
+multiple (classes of) bugs, as the existing hand-coded list of MSRs is
+wrong on multiple fronts:
+
+ - ARBPRI isn't supported by KVM, isn't accelerated by AVIC (for read or
+   write), and its #VMEXIT is fault-like, i.e. requires decoding the
+   instruction.  Disabling interception is nonsensical and suboptimal.
+
+ - DFR and ICR2 aren't supported by x2APIC and so don't need their
+   intercepts disabled for performance reasons.  While the #GP due to
+   x2APIC being abled has higher priority than the trap-like #VMEXIT,
+   disabling interception of unsupported MSRs is confusing and unnecessary.
+
+ - RRR is completely unsupported.
+
+ - AVIC currently fails to pass through the "range of vectors" registers,
+   IRR, ISR, and TMR, as e.g. X2APIC_MSR(APIC_IRR) only affects IRR0, and
+   thus only disables intercept for vectors 31:0 (which are the *least*
+   interesting registers).
+
+ - TMCCT (the current APIC timer count) isn't accelerated by hardware, and
+   generates a fault-like AVIC_UNACCELERATED_ACCESS #VMEXIT, i.e. requires
+   KVM to decode the instruction to figure out what the guest was trying to
+   access.  Note, the only reason this isn't a fatal bug is that the AVIC
+   architecture had the foresight to guard against buggy hypervisors.  E.g.
+   if hardware simply read from the virtual APIC page, the guest would get
+   garbage (because the timer is emulated in software).
+
+Fixes: 4d1d7942e36a ("KVM: SVM: Introduce logic to (de)activate x2AVIC mode")
+Cc: stable@vger.kernel.org
+Reviewed-by: Naveen N Rao (AMD) <naveen@kernel.org>
+Link: https://patch.msgid.link/20260514213115.1637082-3-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/svm/avic.c |   13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+--- a/arch/x86/kvm/svm/avic.c
++++ b/arch/x86/kvm/svm/avic.c
+@@ -122,6 +122,9 @@ static u32 x2avic_max_physical_id;
+ static void avic_set_x2apic_msr_interception(struct vcpu_svm *svm,
+                                            bool intercept)
+ {
++      struct kvm_vcpu *vcpu = &svm->vcpu;
++      u64 rd_regs;
++
+       static const u32 x2avic_passthrough_msrs[] = {
+               X2APIC_MSR(APIC_ID),
+               X2APIC_MSR(APIC_LVR),
+@@ -162,9 +165,15 @@ static void avic_set_x2apic_msr_intercep
+       if (!x2avic_enabled)
+               return;
++      rd_regs = kvm_x2apic_disable_read_intercept_reg_mask(vcpu);
++
++      for_each_set_bit(i, (unsigned long *)&rd_regs, BITS_PER_TYPE(rd_regs))
++              svm_set_intercept_for_msr(vcpu, APIC_BASE_MSR + i,
++                                        MSR_TYPE_R, intercept);
++
+       for (i = 0; i < ARRAY_SIZE(x2avic_passthrough_msrs); i++)
+-              svm_set_intercept_for_msr(&svm->vcpu, x2avic_passthrough_msrs[i],
+-                                        MSR_TYPE_RW, intercept);
++              svm_set_intercept_for_msr(vcpu, x2avic_passthrough_msrs[i],
++                                        MSR_TYPE_W, intercept);
+       svm->x2avic_msrs_intercepted = intercept;
+ }
diff --git a/queue-7.1/kvm-svm-only-disable-x2avic-wrmsr-interception-for-msrs-that-are-accelerated.patch b/queue-7.1/kvm-svm-only-disable-x2avic-wrmsr-interception-for-msrs-that-are-accelerated.patch
new file mode 100644 (file)
index 0000000..3e1dd07
--- /dev/null
@@ -0,0 +1,100 @@
+From 8c63179d975f2029c948ecce622f72af616dbff7 Mon Sep 17 00:00:00 2001
+From: Sean Christopherson <seanjc@google.com>
+Date: Thu, 14 May 2026 14:31:15 -0700
+Subject: KVM: SVM: Only disable x2AVIC WRMSR interception for MSRs that are accelerated
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit 8c63179d975f2029c948ecce622f72af616dbff7 upstream.
+
+When x2AVIC is enabled, disable WRMSR interception only for MSRs that are
+actually accelerated by hardware.  Disabling interception for MSRs that
+aren't accelerated is functionally "fine", and in some cases a weird "win"
+for performance, but only for cases that should never be triggered by a
+well-behaved VM (writes to read-only registers; the #GP will typically
+occur in the guest without taking a #VMEXIT, even for fault-like exits).
+
+But overall, disabling interception for MSRs that aren't accelerated is at
+best confusing and unintuitive, and at worst introduces avoidable risk, as
+the APM's documentation is imperfect and contradictory.  The table in
+"15.29.3.1 Virtual APIC Register Accesses" of simply states that such
+writes generate exits, where as "Section 15.29.10 x2AVIC" says:
+
+  x2APIC MSR intercept checks and access checks have higher priority than
+  AVIC access permission checks.
+
+CPU behavior follows the latter (which makes perfect sense), but all in
+all there's simply no reason to disable interception just to make a #GP
+faster.
+
+Note, the set of MSRs that are passed through for write is identical to
+VMX's set when IPI virtualization is enabled.  This is not a coincidence,
+and is another motiviating factor for cleaning up the intercepts, as x2AVIC
+is functionally equivalent to APICv+IPIv.
+
+Fixes: 4d1d7942e36a ("KVM: SVM: Introduce logic to (de)activate x2AVIC mode")
+Cc: stable@vger.kernel.org
+Reviewed-by: Naveen N Rao (AMD) <naveen@kernel.org>
+Link: https://patch.msgid.link/20260514213115.1637082-4-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/svm/avic.c |   40 ++++------------------------------------
+ 1 file changed, 4 insertions(+), 36 deletions(-)
+
+--- a/arch/x86/kvm/svm/avic.c
++++ b/arch/x86/kvm/svm/avic.c
+@@ -124,39 +124,6 @@ static void avic_set_x2apic_msr_intercep
+ {
+       struct kvm_vcpu *vcpu = &svm->vcpu;
+       u64 rd_regs;
+-
+-      static const u32 x2avic_passthrough_msrs[] = {
+-              X2APIC_MSR(APIC_ID),
+-              X2APIC_MSR(APIC_LVR),
+-              X2APIC_MSR(APIC_TASKPRI),
+-              X2APIC_MSR(APIC_ARBPRI),
+-              X2APIC_MSR(APIC_PROCPRI),
+-              X2APIC_MSR(APIC_EOI),
+-              X2APIC_MSR(APIC_RRR),
+-              X2APIC_MSR(APIC_LDR),
+-              X2APIC_MSR(APIC_DFR),
+-              X2APIC_MSR(APIC_SPIV),
+-              X2APIC_MSR(APIC_ISR),
+-              X2APIC_MSR(APIC_TMR),
+-              X2APIC_MSR(APIC_IRR),
+-              X2APIC_MSR(APIC_ESR),
+-              X2APIC_MSR(APIC_ICR),
+-              X2APIC_MSR(APIC_ICR2),
+-
+-              /*
+-               * Note!  Always intercept LVTT, as TSC-deadline timer mode
+-               * isn't virtualized by hardware, and the CPU will generate a
+-               * #GP instead of a #VMEXIT.
+-               */
+-              X2APIC_MSR(APIC_LVTTHMR),
+-              X2APIC_MSR(APIC_LVTPC),
+-              X2APIC_MSR(APIC_LVT0),
+-              X2APIC_MSR(APIC_LVT1),
+-              X2APIC_MSR(APIC_LVTERR),
+-              X2APIC_MSR(APIC_TMICT),
+-              X2APIC_MSR(APIC_TMCCT),
+-              X2APIC_MSR(APIC_TDCR),
+-      };
+       int i;
+       if (intercept == svm->x2avic_msrs_intercepted)
+@@ -171,9 +138,10 @@ static void avic_set_x2apic_msr_intercep
+               svm_set_intercept_for_msr(vcpu, APIC_BASE_MSR + i,
+                                         MSR_TYPE_R, intercept);
+-      for (i = 0; i < ARRAY_SIZE(x2avic_passthrough_msrs); i++)
+-              svm_set_intercept_for_msr(vcpu, x2avic_passthrough_msrs[i],
+-                                        MSR_TYPE_W, intercept);
++      svm_set_intercept_for_msr(vcpu, X2APIC_MSR(APIC_TASKPRI), MSR_TYPE_W, intercept);
++      svm_set_intercept_for_msr(vcpu, X2APIC_MSR(APIC_EOI), MSR_TYPE_W, intercept);
++      svm_set_intercept_for_msr(vcpu, X2APIC_MSR(APIC_SELF_IPI), MSR_TYPE_W, intercept);
++      svm_set_intercept_for_msr(vcpu, X2APIC_MSR(APIC_ICR), MSR_TYPE_W, intercept);
+       svm->x2avic_msrs_intercepted = intercept;
+ }
diff --git a/queue-7.1/kvm-tdx-account-all-non-transient-page-allocations-for-per-td-structures.patch b/queue-7.1/kvm-tdx-account-all-non-transient-page-allocations-for-per-td-structures.patch
new file mode 100644 (file)
index 0000000..2e21991
--- /dev/null
@@ -0,0 +1,81 @@
+From a8b2924676ec42d76597f849baba31acc3ba1bfc Mon Sep 17 00:00:00 2001
+From: Sean Christopherson <seanjc@google.com>
+Date: Wed, 28 Jan 2026 17:14:35 -0800
+Subject: KVM: TDX: Account all non-transient page allocations for per-TD structures
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit a8b2924676ec42d76597f849baba31acc3ba1bfc upstream.
+
+Account all non-transient allocations associated with a single TD (or its
+vCPUs), as KVM's ABI is that allocations that are active for the lifetime
+of a VM are accounted.  Leave temporary allocations, i.e. allocations that
+are freed within a single function/ioctl, unaccounted, to again align with
+KVM's existing behavior, e.g. see commit dd103407ca31 ("KVM: X86: Remove
+unnecessary GFP_KERNEL_ACCOUNT for temporary variables").
+
+Fixes: 8d032b683c29 ("KVM: TDX: create/destroy VM structure")
+Fixes: a50f673f25e0 ("KVM: TDX: Do TDX specific vcpu initialization")
+Cc: stable@vger.kernel.org
+Reviewed-by: Kai Huang <kai.huang@intel.com>
+Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
+Link: https://patch.msgid.link/20260129011517.3545883-4-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/vmx/tdx.c |   14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+--- a/arch/x86/kvm/vmx/tdx.c
++++ b/arch/x86/kvm/vmx/tdx.c
+@@ -2387,20 +2387,20 @@ static int __tdx_td_init(struct kvm *kvm
+       ret = -ENOMEM;
+-      tdr_page = alloc_page(GFP_KERNEL);
++      tdr_page = alloc_page(GFP_KERNEL_ACCOUNT);
+       if (!tdr_page)
+               goto free_hkid;
+       kvm_tdx->td.tdcs_nr_pages = tdx_sysinfo->td_ctrl.tdcs_base_size / PAGE_SIZE;
+       /* TDVPS = TDVPR(4K page) + TDCX(multiple 4K pages), -1 for TDVPR. */
+       kvm_tdx->td.tdcx_nr_pages = tdx_sysinfo->td_ctrl.tdvps_base_size / PAGE_SIZE - 1;
+-      tdcs_pages = kzalloc_objs(*kvm_tdx->td.tdcs_pages,
+-                                kvm_tdx->td.tdcs_nr_pages);
++      tdcs_pages = kzalloc_objs(*kvm_tdx->td.tdcs_pages, kvm_tdx->td.tdcs_nr_pages,
++                                GFP_KERNEL_ACCOUNT);
+       if (!tdcs_pages)
+               goto free_tdr;
+       for (i = 0; i < kvm_tdx->td.tdcs_nr_pages; i++) {
+-              tdcs_pages[i] = alloc_page(GFP_KERNEL);
++              tdcs_pages[i] = alloc_page(GFP_KERNEL_ACCOUNT);
+               if (!tdcs_pages[i])
+                       goto free_tdcs;
+       }
+@@ -2875,7 +2875,7 @@ static int tdx_td_vcpu_init(struct kvm_v
+       int ret, i;
+       u64 err;
+-      page = alloc_page(GFP_KERNEL);
++      page = alloc_page(GFP_KERNEL_ACCOUNT);
+       if (!page)
+               return -ENOMEM;
+       tdx->vp.tdvpr_page = page;
+@@ -2888,14 +2888,14 @@ static int tdx_td_vcpu_init(struct kvm_v
+       tdx->vp.tdvpr_pa = page_to_phys(tdx->vp.tdvpr_page);
+       tdx->vp.tdcx_pages = kcalloc(kvm_tdx->td.tdcx_nr_pages, sizeof(*tdx->vp.tdcx_pages),
+-                                   GFP_KERNEL);
++                                   GFP_KERNEL_ACCOUNT);
+       if (!tdx->vp.tdcx_pages) {
+               ret = -ENOMEM;
+               goto free_tdvpr;
+       }
+       for (i = 0; i < kvm_tdx->td.tdcx_nr_pages; i++) {
+-              page = alloc_page(GFP_KERNEL);
++              page = alloc_page(GFP_KERNEL_ACCOUNT);
+               if (!page) {
+                       ret = -ENOMEM;
+                       goto free_tdcx;
diff --git a/queue-7.1/kvm-vmx-handle-bad-values-on-proxied-writes-to-lbr-msrs.patch b/queue-7.1/kvm-vmx-handle-bad-values-on-proxied-writes-to-lbr-msrs.patch
new file mode 100644 (file)
index 0000000..a98368e
--- /dev/null
@@ -0,0 +1,59 @@
+From ca674df13b195eb6d124ab059799d4e03fa40624 Mon Sep 17 00:00:00 2001
+From: Xuanqing Shi <1356292400@qq.com>
+Date: Tue, 26 May 2026 19:26:17 -0700
+Subject: KVM: VMX: Handle bad values on proxied writes to LBR MSRs
+
+From: Xuanqing Shi <1356292400@qq.com>
+
+commit ca674df13b195eb6d124ab059799d4e03fa40624 upstream.
+
+Use the "safe" WRMSR API when writing LBRs on behalf of the guest (or host
+userspace), and propagate any errors back to the instigator, as the value
+being written is untrusted.  E.g. if the guest (or host userspace) attempts
+to set reserved bits in LBR_SELECT, then KVM needs to return an error, and
+not WARN on the bad value.
+
+Continue using the "unsafe" version of RDMSR, as it should be impossible to
+reach the helper with a completely bogus MSR, i.e. WARNing on RDMSR failure
+is very desirable, e.g. to make KVM bugs more visible.
+
+  unchecked MSR access error: WRMSR to 0x1c8 (tried to write 0x0000000000004000)
+  Call Trace:
+   intel_pmu_set_msr+0x4e0/0x7f0 [kvm_intel]
+   kvm_pmu_set_msr+0x17e/0x1c0 [kvm]
+   kvm_set_msr_common+0xc76/0x1440 [kvm]
+   vmx_set_msr+0x5e6/0x1570 [kvm_intel]
+   kvm_emulate_wrmsr+0x54/0x1d0 [kvm]
+   vmx_handle_exit+0x7fc/0x970 [kvm_intel]
+
+Fixes: 1b5ac3226a1a ("KVM: vmx/pmu: Pass-through LBR msrs when the guest LBR event is ACTIVE")
+Cc: stable@vger.kernel.org
+Signed-off-by: Xuanqing Shi <1356292400@qq.com>
+[sean: rework changelog, only modify WRMSR path, tag for stable@]
+Link: https://patch.msgid.link/20260527022617.3973884-1-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/vmx/pmu_intel.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/arch/x86/kvm/vmx/pmu_intel.c
++++ b/arch/x86/kvm/vmx/pmu_intel.c
+@@ -308,13 +308,15 @@ static bool intel_pmu_handle_lbr_msrs_ac
+        */
+       local_irq_disable();
+       if (lbr_desc->event->state == PERF_EVENT_STATE_ACTIVE) {
++              int err = 0;
++
+               if (read)
+                       rdmsrq(index, msr_info->data);
+               else
+-                      wrmsrq(index, msr_info->data);
++                      err = wrmsrq_safe(index, msr_info->data);
+               __set_bit(INTEL_PMC_IDX_FIXED_VLBR, vcpu_to_pmu(vcpu)->pmc_in_use);
+               local_irq_enable();
+-              return true;
++              return !err;
+       }
+       clear_bit(INTEL_PMC_IDX_FIXED_VLBR, vcpu_to_pmu(vcpu)->pmc_in_use);
+       local_irq_enable();
diff --git a/queue-7.1/kvm-vmx-refresh-guest_pending_dbg_exceptions.bs-on-all-injected-dbs.patch b/queue-7.1/kvm-vmx-refresh-guest_pending_dbg_exceptions.bs-on-all-injected-dbs.patch
new file mode 100644 (file)
index 0000000..54af893
--- /dev/null
@@ -0,0 +1,98 @@
+From c5bad4fa2d5dfd8c25140051a9807eba387a19b8 Mon Sep 17 00:00:00 2001
+From: Sean Christopherson <seanjc@google.com>
+Date: Fri, 15 May 2026 15:26:29 -0700
+Subject: KVM: VMX: Refresh GUEST_PENDING_DBG_EXCEPTIONS.BS on all injected #DBs
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit c5bad4fa2d5dfd8c25140051a9807eba387a19b8 upstream.
+
+Move KVM's stuffing of GUEST_PENDING_DBG_EXCEPTIONS.BS when RFLAGS.TF=1 and
+MOV/POP SS or STI blocking is active into the exception injection code so
+that KVM fixes up the VMCS for all injected #DBs, not only those that are
+reflected back into the guest after #DB interception.  E.g. if KVM queues
+a #DB in the emulator, or more importantly if userspace does save/restore
+exactly on the #DB+shadow boundary, then KVM needs to massage the VMCS to
+avoid the VM-Entry consistency check.
+
+Opportunistically update the wording of the comment to describe the
+behavior as a workaround of flawed CPU behavior/architecture, to make it
+clear that the *only* thing KVM is doing is fudging around a consistency
+check.  Per the SDM:
+
+  There are no pending debug exceptions after VM entry if any of the
+  following are true:
+
+    * The VM entry is vectoring with one of the following interruption
+      types: external interrupt, non-maskable interrupt (NMI), hardware
+      exception, or privileged software exception.
+
+I.e. forcing GUEST_PENDING_DBG_EXCEPTIONS.BS does *not* impact guest-
+visible behavior.
+
+Fixes: b9bed78e2fa9 ("KVM: VMX: Set vmcs.PENDING_DBG.BS on #DB in STI/MOVSS blocking shadow")
+Cc: stable@vger.kernel.org
+Reported-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
+Closes: https://lore.kernel.org/all/b1a294bc9ed4dae532474a5dc6c8cb6e5962de7c.1757416809.git.houwenlong.hwl@antgroup.com
+Reviewed-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
+Link: https://patch.msgid.link/20260515222638.1949982-2-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/vmx/vmx.c |   35 ++++++++++++++++++-----------------
+ 1 file changed, 18 insertions(+), 17 deletions(-)
+
+--- a/arch/x86/kvm/vmx/vmx.c
++++ b/arch/x86/kvm/vmx/vmx.c
+@@ -1908,6 +1908,24 @@ void vmx_inject_exception(struct kvm_vcp
+       u32 intr_info = ex->vector | INTR_INFO_VALID_MASK;
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
++      /*
++       * When injecting a #DB, single-stepping is enabled in RFLAGS, and STI
++       * or MOV-SS blocking is active, set vmcs.PENDING_DBG_EXCEPTIONS.BS to
++       * prevent a false positive from VM-Entry consistency check.  VM-Entry
++       * asserts that a single-step #DB _must_ be pending in this scenario,
++       * as the previous instruction cannot have toggled RFLAGS.TF 0=>1
++       * (because STI and POP/MOV don't modify RFLAGS), therefore the one
++       * instruction delay when activating single-step breakpoints must have
++       * already expired.  However, the CPU isn't smart enough to peek at
++       * vmcs.VM_ENTRY_INTR_INFO_FIELD and so doesn't realize that yes, there
++       * is indeed a #DB pending/imminent.
++       */
++      if (ex->vector == DB_VECTOR &&
++          (vmx_get_rflags(vcpu) & X86_EFLAGS_TF) &&
++          vmx_get_interrupt_shadow(vcpu))
++              vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS,
++                          vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS) | DR6_BS);
++
+       kvm_deliver_exception_payload(vcpu, ex);
+       if (ex->has_error_code) {
+@@ -5477,26 +5495,9 @@ static int handle_exception_nmi(struct k
+                        * avoid single-step #DB and MTF updates, as ICEBP is
+                        * higher priority.  Note, skipping ICEBP still clears
+                        * STI and MOVSS blocking.
+-                       *
+-                       * For all other #DBs, set vmcs.PENDING_DBG_EXCEPTIONS.BS
+-                       * if single-step is enabled in RFLAGS and STI or MOVSS
+-                       * blocking is active, as the CPU doesn't set the bit
+-                       * on VM-Exit due to #DB interception.  VM-Entry has a
+-                       * consistency check that a single-step #DB is pending
+-                       * in this scenario as the previous instruction cannot
+-                       * have toggled RFLAGS.TF 0=>1 (because STI and POP/MOV
+-                       * don't modify RFLAGS), therefore the one instruction
+-                       * delay when activating single-step breakpoints must
+-                       * have already expired.  Note, the CPU sets/clears BS
+-                       * as appropriate for all other VM-Exits types.
+                        */
+                       if (is_icebp(intr_info))
+                               WARN_ON(!skip_emulated_instruction(vcpu));
+-                      else if ((vmx_get_rflags(vcpu) & X86_EFLAGS_TF) &&
+-                               (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) &
+-                                (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)))
+-                              vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS,
+-                                          vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS) | DR6_BS);
+                       kvm_queue_exception_p(vcpu, DB_VECTOR, dr6);
+                       return 1;
diff --git a/queue-7.1/kvm-x86-add-dedicated-api-for-getting-mask-of-accelerated-x2apic-msrs.patch b/queue-7.1/kvm-x86-add-dedicated-api-for-getting-mask-of-accelerated-x2apic-msrs.patch
new file mode 100644 (file)
index 0000000..1829c67
--- /dev/null
@@ -0,0 +1,97 @@
+From 8ba621f335a519b47cb7d3e3f4f15b5101b3a56f Mon Sep 17 00:00:00 2001
+From: Sean Christopherson <seanjc@google.com>
+Date: Thu, 14 May 2026 14:31:13 -0700
+Subject: KVM: x86: Add dedicated API for getting mask of accelerated x2APIC MSRs
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit 8ba621f335a519b47cb7d3e3f4f15b5101b3a56f upstream.
+
+Add a dedicated local APIC API, kvm_x2apic_disable_intercept_reg_mask(),
+to provide the mask of x2APIC registers whose MSRs can and should be passed
+through to the guest when x2APIC virtualization is enable, and use it in
+lieu of the open-coded equivalent VMX logic.  Providing a common helper
+will allow sharing the logic with SVM (x2AVIC), and as a bonus eliminates
+the somewhat confusing code where KVM enables interception for MSR_TYPE_RW,
+even though only the READ case actually needs to be updated.
+
+No functional change intended.
+
+Cc: stable@vger.kernel.org
+Reviewed-by: Naveen N Rao (AMD) <naveen@kernel.org>
+Link: https://patch.msgid.link/20260514213115.1637082-2-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/lapic.c   |   21 +++++++++++++++++++--
+ arch/x86/kvm/lapic.h   |    2 +-
+ arch/x86/kvm/vmx/vmx.c |    3 +--
+ 3 files changed, 21 insertions(+), 5 deletions(-)
+
+--- a/arch/x86/kvm/lapic.c
++++ b/arch/x86/kvm/lapic.c
+@@ -1732,7 +1732,7 @@ static inline struct kvm_lapic *to_lapic
+ #define APIC_REGS_MASK(first, count) \
+       (APIC_REG_MASK(first) * ((1ull << (count)) - 1))
+-u64 kvm_lapic_readable_reg_mask(struct kvm_lapic *apic)
++static u64 kvm_lapic_readable_reg_mask(struct kvm_lapic *apic)
+ {
+       /* Leave bits '0' for reserved and write-only registers. */
+       u64 valid_reg_mask =
+@@ -1768,7 +1768,24 @@ u64 kvm_lapic_readable_reg_mask(struct k
+       return valid_reg_mask;
+ }
+-EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_lapic_readable_reg_mask);
++
++u64 kvm_x2apic_disable_read_intercept_reg_mask(struct kvm_vcpu *vcpu)
++{
++      if (WARN_ON_ONCE(!lapic_in_kernel(vcpu)))
++              return 0;
++
++      /*
++       * TMMCT, a.k.a. the current APIC timer count, reads aren't accelerated
++       * by hardware (Intel or AMD) as the timer is emulated in software (by
++       * KVM), i.e. reads from the virtual APIC page would return garbage.
++       * Intercept RDMSR, as handling the fault-like APIC-access VM-Exit is
++       * more expensive than handling a RDMSR VM-Exit (the APIC-access exit
++       * requires slow emulation of the code stream).
++       */
++      return kvm_lapic_readable_reg_mask(vcpu->arch.apic) &
++             ~APIC_REG_MASK(APIC_TMCCT);
++}
++EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_x2apic_disable_read_intercept_reg_mask);
+ static int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
+                             void *data)
+--- a/arch/x86/kvm/lapic.h
++++ b/arch/x86/kvm/lapic.h
+@@ -157,7 +157,7 @@ int kvm_hv_vapic_msr_read(struct kvm_vcp
+ int kvm_lapic_set_pv_eoi(struct kvm_vcpu *vcpu, u64 data, unsigned long len);
+ void kvm_lapic_exit(void);
+-u64 kvm_lapic_readable_reg_mask(struct kvm_lapic *apic);
++u64 kvm_x2apic_disable_read_intercept_reg_mask(struct kvm_vcpu *vcpu);
+ static inline void kvm_lapic_set_irr(int vec, struct kvm_lapic *apic)
+ {
+--- a/arch/x86/kvm/vmx/vmx.c
++++ b/arch/x86/kvm/vmx/vmx.c
+@@ -4159,7 +4159,7 @@ static void vmx_update_msr_bitmap_x2apic
+        * mode, only the current timer count needs on-demand emulation by KVM.
+        */
+       if (mode & MSR_BITMAP_MODE_X2APIC_APICV)
+-              msr_bitmap[read_idx] = ~kvm_lapic_readable_reg_mask(vcpu->arch.apic);
++              msr_bitmap[read_idx] = ~kvm_x2apic_disable_read_intercept_reg_mask(vcpu);
+       else
+               msr_bitmap[read_idx] = ~0ull;
+       msr_bitmap[write_idx] = ~0ull;
+@@ -4172,7 +4172,6 @@ static void vmx_update_msr_bitmap_x2apic
+                                 !(mode & MSR_BITMAP_MODE_X2APIC));
+       if (mode & MSR_BITMAP_MODE_X2APIC_APICV) {
+-              vmx_enable_intercept_for_msr(vcpu, X2APIC_MSR(APIC_TMCCT), MSR_TYPE_RW);
+               vmx_disable_intercept_for_msr(vcpu, X2APIC_MSR(APIC_EOI), MSR_TYPE_W);
+               vmx_disable_intercept_for_msr(vcpu, X2APIC_MSR(APIC_SELF_IPI), MSR_TYPE_W);
+               if (enable_ipiv)
diff --git a/queue-7.1/kvm-x86-ensure-vendor-s-exit-handler-runs-before-fastpath-userspace-exits.patch b/queue-7.1/kvm-x86-ensure-vendor-s-exit-handler-runs-before-fastpath-userspace-exits.patch
new file mode 100644 (file)
index 0000000..93a7009
--- /dev/null
@@ -0,0 +1,69 @@
+From 0ffedf43910e44b76c2c1db4e9fbf12b268190c1 Mon Sep 17 00:00:00 2001
+From: Sean Christopherson <seanjc@google.com>
+Date: Thu, 23 Apr 2026 09:26:27 -0700
+Subject: KVM: x86: Ensure vendor's exit handler runs before fastpath userspace exits
+
+From: Sean Christopherson <seanjc@google.com>
+
+commit 0ffedf43910e44b76c2c1db4e9fbf12b268190c1 upstream.
+
+Move the handling of fastpath userspace exits into vendor code to ensure
+KVM runs vendor specific operations that need to run before userspace gains
+control of the vCPU.  E.g. for VMX (and soon to be for SVM as well), KVM
+needs to flush the PML buffer prior to exiting to userspace, otherwise any
+memory written by the final KVM_RUN might never be flagged as dirty.
+
+Note, waiting to snapshot CR0 and CR3 until svm_handle_exit() is flawed in
+general, as that risks consuming stale state in a fastpath handler.  That
+will be addressed in a future change.
+
+Fixes: f7f39c50edb9 ("KVM: x86: Exit to userspace if fastpath triggers one on instruction skip")
+Cc: stable@vger.kernel.org
+Cc: Nikunj A. Dadhania <nikunj@amd.com>
+Reviewed-by: Nikunj A. Dadhania <nikunj@amd.com>
+Reviewed-by: Kai Huang <kai.huang@intel.com>
+Link: https://patch.msgid.link/20260423162628.490962-2-seanjc@google.com
+Signed-off-by: Sean Christopherson <seanjc@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/kvm/svm/svm.c |    3 +++
+ arch/x86/kvm/vmx/vmx.c |    3 +++
+ arch/x86/kvm/x86.c     |    3 ---
+ 3 files changed, 6 insertions(+), 3 deletions(-)
+
+--- a/arch/x86/kvm/svm/svm.c
++++ b/arch/x86/kvm/svm/svm.c
+@@ -3663,6 +3663,9 @@ static int svm_handle_exit(struct kvm_vc
+                       vcpu->arch.cr3 = svm->vmcb->save.cr3;
+       }
++      if (unlikely(exit_fastpath == EXIT_FASTPATH_EXIT_USERSPACE))
++              return 0;
++
+       if (is_guest_mode(vcpu)) {
+               int vmexit;
+--- a/arch/x86/kvm/vmx/vmx.c
++++ b/arch/x86/kvm/vmx/vmx.c
+@@ -6698,6 +6698,9 @@ static int __vmx_handle_exit(struct kvm_
+       if (enable_pml && !is_guest_mode(vcpu))
+               vmx_flush_pml_buffer(vcpu);
++      if (unlikely(exit_fastpath == EXIT_FASTPATH_EXIT_USERSPACE))
++              return 0;
++
+       /*
+        * KVM should never reach this point with a pending nested VM-Enter.
+        * More specifically, short-circuiting VM-Entry to emulate L2 due to
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -11578,9 +11578,6 @@ static int vcpu_enter_guest(struct kvm_v
+       if (vcpu->arch.apic_attention)
+               kvm_lapic_sync_from_vapic(vcpu);
+-      if (unlikely(exit_fastpath == EXIT_FASTPATH_EXIT_USERSPACE))
+-              return 0;
+-
+       r = kvm_x86_call(handle_exit)(vcpu, exit_fastpath);
+       return r;
diff --git a/queue-7.1/landlock-account-all-audit-data-allocations-to-user-space.patch b/queue-7.1/landlock-account-all-audit-data-allocations-to-user-space.patch
new file mode 100644 (file)
index 0000000..7482ce8
--- /dev/null
@@ -0,0 +1,79 @@
+From b232bd12789fa57405b5092f28788be97aae9999 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= <mic@digikod.net>
+Date: Wed, 13 May 2026 20:03:08 +0200
+Subject: landlock: Account all audit data allocations to user space
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Mickaël Salaün <mic@digikod.net>
+
+commit b232bd12789fa57405b5092f28788be97aae9999 upstream.
+
+Mark the kzalloc_flex() of struct landlock_details with
+GFP_KERNEL_ACCOUNT so the allocation is charged to the calling task,
+like the other Landlock per-domain allocations which have used
+GFP_KERNEL_ACCOUNT forever.
+
+Every property of landlock_details is caller-attributable: allocated by
+landlock_restrict_self(2), owned by the caller's landlock_hierarchy,
+contents are the caller's pid, uid, comm, and exe_path, lifetime bounded
+by the caller's domain.  While the caller may not know nor control the
+size of this allocation (i.e. exe_path), this data should still be
+accounted for it.
+
+The deciding factor is whether userspace can trigger the allocation, not
+whether the size of the data is known nor controlled by the caller.
+This aligns with the kmemcg accounting policy established by commit
+5d097056c9a0 ("kmemcg: account certain kmem allocations to memcg").
+
+No new failure modes: the hierarchy and ruleset are allocated before
+details and are already accounted, so landlock_restrict_self(2) already
+returns -ENOMEM under memcg pressure.  This change widens that existing
+failure window slightly; it does not introduce a new error code.
+
+Cc: Günther Noack <gnoack@google.com>
+Cc: Paul Moore <paul@paul-moore.com>
+Cc: stable@vger.kernel.org
+Fixes: 1d636984e088 ("landlock: Add AUDIT_LANDLOCK_DOMAIN and log domain status")
+Link: https://patch.msgid.link/20260513180309.165840-1-mic@digikod.net
+Signed-off-by: Mickaël Salaün <mic@digikod.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ security/landlock/domain.c |    9 +++++----
+ security/landlock/domain.h |    5 +----
+ 2 files changed, 6 insertions(+), 8 deletions(-)
+
+--- a/security/landlock/domain.c
++++ b/security/landlock/domain.c
+@@ -90,11 +90,12 @@ static struct landlock_details *get_curr
+               return ERR_CAST(buffer);
+       /*
+-       * Create the new details according to the path's length.  Do not
+-       * allocate with GFP_KERNEL_ACCOUNT because it is independent from the
+-       * caller.
++       * Create the new details according to the path's length.  Account to
++       * the calling task's memcg, like the other Landlock per-domain
++       * allocations, even if it may not control the related size.
+        */
+-      details = kzalloc_flex(*details, exe_path, path_size);
++      details =
++              kzalloc_flex(*details, exe_path, path_size, GFP_KERNEL_ACCOUNT);
+       if (!details)
+               return ERR_PTR(-ENOMEM);
+--- a/security/landlock/domain.h
++++ b/security/landlock/domain.h
+@@ -33,10 +33,7 @@ enum landlock_log_status {
+  * Rarely accessed, mainly when logging the first domain's denial.
+  *
+  * The contained pointers are initialized at the domain creation time and never
+- * changed again.  Contrary to most other Landlock object types, this one is
+- * not allocated with GFP_KERNEL_ACCOUNT because its size may not be under the
+- * caller's control (e.g. unknown exe_path) and the data is not explicitly
+- * requested nor used by tasks.
++ * changed again.
+  */
+ struct landlock_details {
+       /**
diff --git a/queue-7.1/landlock-set-audit_net.sk-for-socket-access-checks.patch b/queue-7.1/landlock-set-audit_net.sk-for-socket-access-checks.patch
new file mode 100644 (file)
index 0000000..35814a0
--- /dev/null
@@ -0,0 +1,125 @@
+From d936e1a9170f9cadaa5f37586b1dfe6f20f98799 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= <mic@digikod.net>
+Date: Fri, 12 Jun 2026 19:27:55 +0200
+Subject: landlock: Set audit_net.sk for socket access checks
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Mickaël Salaün <mic@digikod.net>
+
+commit d936e1a9170f9cadaa5f37586b1dfe6f20f98799 upstream.
+
+Set audit_net.sk in current_check_access_socket() to provide the socket
+object to audit_log_lsm_data().  This makes Landlock consistent with
+AppArmor, which always sets .sk for socket operations, and with
+SELinux's generic socket permission checks.
+
+The socket's local and foreign address information (laddr, lport, faddr,
+fport) is logged by the shared lsm_audit.c infrastructure when the
+socket has bound or connected state.  Fields with zero values are
+suppressed by print_ipv4_addr()/print_ipv6_addr(), so the audit output
+is unchanged for the common case of bind denials on unbound sockets.
+For connect denials after a prior bind, the bound local address (laddr,
+lport) appears before the existing sockaddr fields (daddr, dest).
+
+No existing fields are removed or reordered, and the new field names
+(laddr, lport, faddr, fport) are standard audit fields already emitted
+by other LSMs through the same lsm_audit.c code path.
+
+Add a connect_tcp_bound audit test that binds to an allowed port and
+then connects to a denied one, verifying that the denial record reports
+laddr/lport from the bound socket in addition to the connect
+destination.
+
+Cc: Günther Noack <gnoack@google.com>
+Cc: Tingmao Wang <m@maowtm.org>
+Cc: stable@vger.kernel.org
+Fixes: 9f74411a40ce ("landlock: Log TCP bind and connect denials")
+Link: https://patch.msgid.link/20260612172757.1003481-1-mic@digikod.net
+Signed-off-by: Mickaël Salaün <mic@digikod.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ security/landlock/net.c                     |    1 
+ tools/testing/selftests/landlock/net_test.c |   62 ++++++++++++++++++++++++++++
+ 2 files changed, 63 insertions(+)
+
+--- a/security/landlock/net.c
++++ b/security/landlock/net.c
+@@ -198,6 +198,7 @@ static int current_check_access_socket(s
+               return 0;
+       audit_net.family = address->sa_family;
++      audit_net.sk = sock->sk;
+       landlock_log_denial(subject,
+                           &(struct landlock_request){
+                                   .type = LANDLOCK_REQUEST_NET_ACCESS,
+--- a/tools/testing/selftests/landlock/net_test.c
++++ b/tools/testing/selftests/landlock/net_test.c
+@@ -2026,4 +2026,66 @@ TEST_F(audit, connect)
+       EXPECT_EQ(0, close(sock_fd));
+ }
++static int matches_log_tcp_bound(int audit_fd, const char *const addr,
++                               __u16 lport, __u16 dport)
++{
++      static const char log_template[] = REGEX_LANDLOCK_PREFIX
++              " blockers=net\\.connect_tcp laddr=%s lport=%u daddr=%s dest=%u$";
++      /* Slack for two addresses and two port numbers. */
++      char log_match[sizeof(log_template) + 40];
++      int log_match_len;
++
++      log_match_len = snprintf(log_match, sizeof(log_match), log_template,
++                               addr, lport, addr, dport);
++      if (log_match_len > sizeof(log_match))
++              return -E2BIG;
++
++      return audit_match_record(audit_fd, AUDIT_LANDLOCK_ACCESS, log_match,
++                                NULL);
++}
++
++/*
++ * After a bind() to an allowed port, a denied connect must report laddr/lport
++ * from the bound socket (made available through audit_net.sk) in addition to
++ * the connect sockaddr's daddr/dest.
++ */
++TEST_F(audit, connect_tcp_bound)
++{
++      const struct landlock_ruleset_attr ruleset_attr = {
++              .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
++                                    LANDLOCK_ACCESS_NET_CONNECT_TCP,
++      };
++      const struct landlock_net_port_attr rule_bind = {
++              .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
++              .port = self->srv0.port,
++      };
++      struct service_fixture srv_remote;
++      struct audit_records records;
++      int ruleset_fd, sock_fd;
++
++      /* Uses a second port as the denied connect target. */
++      ASSERT_EQ(0, set_service(&srv_remote, variant->prot, 1));
++
++      ruleset_fd =
++              landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
++      ASSERT_LE(0, ruleset_fd);
++      ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
++                                     &rule_bind, 0));
++      enforce_ruleset(_metadata, ruleset_fd);
++      EXPECT_EQ(0, close(ruleset_fd));
++
++      sock_fd = socket_variant(&self->srv0);
++      ASSERT_LE(0, sock_fd);
++      EXPECT_EQ(0, bind_variant(sock_fd, &self->srv0));
++      EXPECT_EQ(-EACCES, connect_variant(sock_fd, &srv_remote));
++      EXPECT_EQ(0, matches_log_tcp_bound(self->audit_fd, variant->addr,
++                                         self->srv0.port, srv_remote.port));
++
++      EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
++      EXPECT_EQ(0, records.access);
++      EXPECT_EQ(1, records.domain);
++
++      EXPECT_EQ(0, close(sock_fd));
++}
++
+ TEST_HARNESS_MAIN
diff --git a/queue-7.1/loongarch-kvm-add-missing-slots_lock-for-device-register-unregister.patch b/queue-7.1/loongarch-kvm-add-missing-slots_lock-for-device-register-unregister.patch
new file mode 100644 (file)
index 0000000..162f932
--- /dev/null
@@ -0,0 +1,77 @@
+From aeded601d6aceb57cdda4b2701d2ee00c43a8b69 Mon Sep 17 00:00:00 2001
+From: Zeng Chi <zengchi@kylinos.cn>
+Date: Thu, 11 Jun 2026 20:46:44 +0800
+Subject: LoongArch: KVM: Add missing slots_lock for device register/unregister
+
+From: Zeng Chi <zengchi@kylinos.cn>
+
+commit aeded601d6aceb57cdda4b2701d2ee00c43a8b69 upstream.
+
+kvm_io_bus_register_dev() and kvm_io_bus_unregister_dev() should be
+called under kvm->slots_lock. The unregister calls in ipi.c, eiointc.c
+and pch_pic.c were also missing this protection. Add it to match the
+register side.
+
+Cc: stable@vger.kernel.org
+Reviewed-by: Bibo Mao <maobibo@loongson.cn>
+Signed-off-by: Zeng Chi <zengchi@kylinos.cn>
+Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/loongarch/kvm/intc/eiointc.c |    6 ++++++
+ arch/loongarch/kvm/intc/ipi.c     |    2 ++
+ arch/loongarch/kvm/intc/pch_pic.c |    2 ++
+ 3 files changed, 10 insertions(+)
+
+--- a/arch/loongarch/kvm/intc/eiointc.c
++++ b/arch/loongarch/kvm/intc/eiointc.c
+@@ -645,10 +645,14 @@ static int kvm_eiointc_create(struct kvm
+       device = &s->device_vext;
+       kvm_iodevice_init(device, &kvm_eiointc_virt_ops);
++      mutex_lock(&kvm->slots_lock);
+       ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS,
+                       EIOINTC_VIRT_BASE, EIOINTC_VIRT_SIZE, device);
++      mutex_unlock(&kvm->slots_lock);
+       if (ret < 0) {
++              mutex_lock(&kvm->slots_lock);
+               kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &s->device);
++              mutex_unlock(&kvm->slots_lock);
+               kfree(s);
+               return ret;
+       }
+@@ -667,8 +671,10 @@ static void kvm_eiointc_destroy(struct k
+       kvm = dev->kvm;
+       eiointc = kvm->arch.eiointc;
++      mutex_lock(&kvm->slots_lock);
+       kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device);
+       kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device_vext);
++      mutex_unlock(&kvm->slots_lock);
+       kfree(eiointc);
+       kfree(dev);
+ }
+--- a/arch/loongarch/kvm/intc/ipi.c
++++ b/arch/loongarch/kvm/intc/ipi.c
+@@ -447,7 +447,9 @@ static void kvm_ipi_destroy(struct kvm_d
+       kvm = dev->kvm;
+       ipi = kvm->arch.ipi;
++      mutex_lock(&kvm->slots_lock);
+       kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &ipi->device);
++      mutex_unlock(&kvm->slots_lock);
+       kfree(ipi);
+       kfree(dev);
+ }
+--- a/arch/loongarch/kvm/intc/pch_pic.c
++++ b/arch/loongarch/kvm/intc/pch_pic.c
+@@ -481,7 +481,9 @@ static void kvm_pch_pic_destroy(struct k
+       kvm = dev->kvm;
+       s = kvm->arch.pch_pic;
+       /* unregister pch pic device and free it's memory */
++      mutex_lock(&kvm->slots_lock);
+       kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &s->device);
++      mutex_unlock(&kvm->slots_lock);
+       kfree(s);
+       kfree(dev);
+ }
diff --git a/queue-7.1/revert-svcrdma-use-contiguous-pages-for-rdma-read-sink-buffers.patch b/queue-7.1/revert-svcrdma-use-contiguous-pages-for-rdma-read-sink-buffers.patch
new file mode 100644 (file)
index 0000000..692b11b
--- /dev/null
@@ -0,0 +1,289 @@
+From a39f0ce0c9da20986b429e2db3e4e8739035d61b Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Sat, 6 Jun 2026 22:24:56 -0400
+Subject: Revert "svcrdma: Use contiguous pages for RDMA Read sink buffers"
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+commit a39f0ce0c9da20986b429e2db3e4e8739035d61b upstream.
+
+Jonathan Flynn reports that commit 18755b8c2f24 ("svcrdma: Use
+contiguous pages for RDMA Read sink buffers") regresses NFS/RDMA
+WRITE throughput from 73.9 GiB/s to 30.3 GiB/s on a 128-core
+single-NUMA-node server driving dual 400Gb/s links with 640 nfsd
+threads. Server CPU utilization rises from 8.5% to 76%, with
+roughly three quarters of all cycles spent spinning on zone->lock.
+
+The sink buffers are allocated as high-order page blocks, split
+into single pages so each sub-page carries an independent refcount,
+and later released one page at a time through folio batches. The
+per-CPU page caches cannot satisfy an allocation stream whose alloc
+order differs from its free order, so every sink buffer page makes
+a round trip through the buddy allocator's free lists, serialized
+on the zone lock of the single NUMA node. The rq_pages entries that
+the split pages displace, bulk-allocated moments earlier by
+svc_alloc_arg(), are freed without ever being used, doubling the
+allocator traffic.
+
+The regression cannot be addressed trivially. Revert the commit
+now; a reworked approach can return in an upcoming merge window.
+
+Reported-by: Jonathan Flynn <jonathan.flynn@hammerspace.com>
+Reported-by: Mike Snitzer <snitzer@kernel.org>
+Closes: https://lore.kernel.org/linux-nfs/aiHlPmeZq3WgMwoJ@kernel.org/
+Closes: https://lore.kernel.org/linux-nfs/3cb119b4b2a8aada30c0c60286778a54@mail.gmail.com/
+Fixes: 18755b8c2f24 ("svcrdma: Use contiguous pages for RDMA Read sink buffers")
+Cc: stable@vger.kernel.org
+Tested-by: Jonathan Flynn <jonathan.flynn@hammerspace.com>
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/sunrpc/xprtrdma/svc_rdma_rw.c |  223 --------------------------------------
+ 1 file changed, 223 deletions(-)
+
+--- a/net/sunrpc/xprtrdma/svc_rdma_rw.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c
+@@ -754,216 +754,6 @@ int svc_rdma_prepare_reply_chunk(struct
+       return xdr->len;
+ }
+-/*
+- * Cap contiguous RDMA Read sink allocations at order-4.
+- * Higher orders risk allocation failure under
+- * __GFP_NORETRY, which would negate the benefit of the
+- * contiguous fast path.
+- */
+-#define SVC_RDMA_CONTIG_MAX_ORDER     4
+-
+-/**
+- * svc_rdma_alloc_read_pages - Allocate physically contiguous pages
+- * @nr_pages: number of pages needed
+- * @order: on success, set to the allocation order
+- *
+- * Attempts a higher-order allocation, falling back to smaller orders.
+- * The returned pages are split immediately so each sub-page has its
+- * own refcount and can be freed independently.
+- *
+- * Returns a pointer to the first page on success, or NULL if even
+- * order-1 allocation fails.
+- */
+-static struct page *
+-svc_rdma_alloc_read_pages(unsigned int nr_pages, unsigned int *order)
+-{
+-      unsigned int o;
+-      struct page *page;
+-
+-      o = min(get_order(nr_pages << PAGE_SHIFT),
+-              SVC_RDMA_CONTIG_MAX_ORDER);
+-
+-      while (o >= 1) {
+-              page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN,
+-                                 o);
+-              if (page) {
+-                      split_page(page, o);
+-                      *order = o;
+-                      return page;
+-              }
+-              o--;
+-      }
+-      return NULL;
+-}
+-
+-/*
+- * svc_rdma_fill_contig_bvec - Replace rq_pages with a contiguous allocation
+- * @rqstp: RPC transaction context
+- * @head: context for ongoing I/O
+- * @bv: bvec entry to fill
+- * @pages_left: number of data pages remaining in the segment
+- * @len_left: bytes remaining in the segment
+- *
+- * On success, fills @bv with a bvec spanning the contiguous range and
+- * advances rc_curpage/rc_page_count. Returns the byte length covered,
+- * or zero if the allocation failed or would overrun rq_maxpages.
+- */
+-static unsigned int
+-svc_rdma_fill_contig_bvec(struct svc_rqst *rqstp,
+-                        struct svc_rdma_recv_ctxt *head,
+-                        struct bio_vec *bv, unsigned int pages_left,
+-                        unsigned int len_left)
+-{
+-      unsigned int order, npages, chunk_pages, chunk_len, i;
+-      struct page *page;
+-
+-      page = svc_rdma_alloc_read_pages(pages_left, &order);
+-      if (!page)
+-              return 0;
+-      npages = 1 << order;
+-
+-      if (head->rc_curpage + npages > rqstp->rq_maxpages) {
+-              for (i = 0; i < npages; i++)
+-                      __free_page(page + i);
+-              return 0;
+-      }
+-
+-      /*
+-       * Replace rq_pages[] entries with pages from the contiguous
+-       * allocation. If npages exceeds chunk_pages, the extra pages
+-       * stay in rq_pages[] for later reuse or normal rqst teardown.
+-       */
+-      for (i = 0; i < npages; i++) {
+-              svc_rqst_page_release(rqstp,
+-                                    rqstp->rq_pages[head->rc_curpage + i]);
+-              rqstp->rq_pages[head->rc_curpage + i] = page + i;
+-      }
+-
+-      chunk_pages = min(npages, pages_left);
+-      chunk_len = min_t(unsigned int, chunk_pages << PAGE_SHIFT, len_left);
+-      bvec_set_page(bv, page, chunk_len, 0);
+-      head->rc_page_count += chunk_pages;
+-      head->rc_curpage += chunk_pages;
+-      return chunk_len;
+-}
+-
+-/*
+- * svc_rdma_fill_page_bvec - Add a single rq_page to the bvec array
+- * @head: context for ongoing I/O
+- * @ctxt: R/W context whose bvec array is being filled
+- * @cur: page to add
+- * @bvec_idx: pointer to current bvec index, not advanced on merge
+- * @len_left: bytes remaining in the segment
+- *
+- * If @cur is physically contiguous with the preceding bvec, it is
+- * merged by extending that bvec's length. Otherwise a new bvec
+- * entry is created. Returns the byte length covered.
+- */
+-static unsigned int
+-svc_rdma_fill_page_bvec(struct svc_rdma_recv_ctxt *head,
+-                      struct svc_rdma_rw_ctxt *ctxt, struct page *cur,
+-                      unsigned int *bvec_idx, unsigned int len_left)
+-{
+-      unsigned int chunk_len = min_t(unsigned int, PAGE_SIZE, len_left);
+-
+-      head->rc_page_count++;
+-      head->rc_curpage++;
+-
+-      if (*bvec_idx > 0) {
+-              struct bio_vec *prev = &ctxt->rw_bvec[*bvec_idx - 1];
+-
+-              if (page_to_phys(prev->bv_page) + prev->bv_offset +
+-                  prev->bv_len == page_to_phys(cur)) {
+-                      prev->bv_len += chunk_len;
+-                      return chunk_len;
+-              }
+-      }
+-
+-      bvec_set_page(&ctxt->rw_bvec[*bvec_idx], cur, chunk_len, 0);
+-      (*bvec_idx)++;
+-      return chunk_len;
+-}
+-
+-/**
+- * svc_rdma_build_read_segment_contig - Build RDMA Read WR with contiguous pages
+- * @rqstp: RPC transaction context
+- * @head: context for ongoing I/O
+- * @segment: co-ordinates of remote memory to be read
+- *
+- * Greedily allocates higher-order pages to cover the segment,
+- * building one bvec per contiguous chunk. Each allocation is
+- * split so sub-pages have independent refcounts. When a
+- * higher-order allocation fails, remaining pages are covered
+- * individually, merging adjacent pages into the preceding bvec
+- * when they are physically contiguous. The split sub-pages
+- * replace entries in rq_pages[] so downstream cleanup is
+- * unchanged.
+- *
+- * Returns:
+- *   %0: the Read WR was constructed successfully
+- *   %-ENOMEM: allocation failed
+- *   %-EIO: a DMA mapping error occurred
+- */
+-static int svc_rdma_build_read_segment_contig(struct svc_rqst *rqstp,
+-                                            struct svc_rdma_recv_ctxt *head,
+-                                            const struct svc_rdma_segment *segment)
+-{
+-      struct svcxprt_rdma *rdma = svc_rdma_rqst_rdma(rqstp);
+-      struct svc_rdma_chunk_ctxt *cc = &head->rc_cc;
+-      unsigned int nr_data_pages, bvec_idx;
+-      struct svc_rdma_rw_ctxt *ctxt;
+-      unsigned int len_left;
+-      int ret;
+-
+-      nr_data_pages = PAGE_ALIGN(segment->rs_length) >> PAGE_SHIFT;
+-      if (head->rc_curpage + nr_data_pages > rqstp->rq_maxpages)
+-              return -ENOMEM;
+-
+-      ctxt = svc_rdma_get_rw_ctxt(rdma, nr_data_pages);
+-      if (!ctxt)
+-              return -ENOMEM;
+-
+-      bvec_idx = 0;
+-      len_left = segment->rs_length;
+-      while (len_left) {
+-              unsigned int pages_left = PAGE_ALIGN(len_left) >> PAGE_SHIFT;
+-              unsigned int chunk_len = 0;
+-
+-              if (pages_left >= 2)
+-                      chunk_len = svc_rdma_fill_contig_bvec(rqstp, head,
+-                                                            &ctxt->rw_bvec[bvec_idx],
+-                                                            pages_left, len_left);
+-              if (chunk_len) {
+-                      bvec_idx++;
+-              } else {
+-                      struct page *cur =
+-                              rqstp->rq_pages[head->rc_curpage];
+-                      chunk_len = svc_rdma_fill_page_bvec(head, ctxt, cur,
+-                                                          &bvec_idx,
+-                                                          len_left);
+-              }
+-
+-              len_left -= chunk_len;
+-      }
+-
+-      ctxt->rw_nents = bvec_idx;
+-
+-      head->rc_pageoff = offset_in_page(segment->rs_length);
+-      if (head->rc_pageoff)
+-              head->rc_curpage--;
+-
+-      ret = svc_rdma_rw_ctx_init(rdma, ctxt, segment->rs_offset,
+-                                 segment->rs_handle, segment->rs_length,
+-                                 DMA_FROM_DEVICE);
+-      if (ret < 0)
+-              return -EIO;
+-      percpu_counter_inc(&svcrdma_stat_read);
+-
+-      list_add(&ctxt->rw_list, &cc->cc_rwctxts);
+-      cc->cc_sqecount += ret;
+-      return 0;
+-}
+-
+ /**
+  * svc_rdma_build_read_segment - Build RDMA Read WQEs to pull one RDMA segment
+  * @rqstp: RPC transaction context
+@@ -990,14 +780,6 @@ static int svc_rdma_build_read_segment(s
+       if (check_add_overflow(head->rc_pageoff, len, &total))
+               return -EINVAL;
+       nr_bvec = PAGE_ALIGN(total) >> PAGE_SHIFT;
+-
+-      if (head->rc_pageoff == 0 && nr_bvec >= 2) {
+-              ret = svc_rdma_build_read_segment_contig(rqstp, head,
+-                                                       segment);
+-              if (ret != -ENOMEM)
+-                      return ret;
+-      }
+-
+       ctxt = svc_rdma_get_rw_ctxt(rdma, nr_bvec);
+       if (!ctxt)
+               return -ENOMEM;
+@@ -1343,11 +1125,6 @@ static void svc_rdma_clear_rqst_pages(st
+ {
+       unsigned int i;
+-      /*
+-       * Move only pages containing RPC data into rc_pages[]. Pages
+-       * from a contiguous allocation that were not used for the
+-       * payload remain in rq_pages[] for subsequent reuse.
+-       */
+       for (i = 0; i < head->rc_page_count; i++) {
+               head->rc_pages[i] = rqstp->rq_pages[i];
+               rqstp->rq_pages[i] = NULL;
diff --git a/queue-7.1/selftests-landlock-explicitly-disable-audit-in-teardowns.patch b/queue-7.1/selftests-landlock-explicitly-disable-audit-in-teardowns.patch
new file mode 100644 (file)
index 0000000..c18e4ac
--- /dev/null
@@ -0,0 +1,107 @@
+From 0302cd72fe196aee933e3fb76f6d175d1ab0e843 Mon Sep 17 00:00:00 2001
+From: Maximilian Heyne <mheyne@amazon.de>
+Date: Fri, 29 May 2026 20:03:41 +0000
+Subject: selftests/landlock: Explicitly disable audit in teardowns
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Maximilian Heyne <mheyne@amazon.de>
+
+commit 0302cd72fe196aee933e3fb76f6d175d1ab0e843 upstream.
+
+I'm seeing sporadic selftest failures, such as
+
+  #  RUN           scoped_audit.connect_to_child ...
+  # scoped_abstract_unix_test.c:314:connect_to_child:Expected 0 (0) == records.access (8)
+  # connect_to_child: Test failed
+  #          FAIL  scoped_audit.connect_to_child
+  not ok 19 scoped_audit.connect_to_child
+
+This seems similar to what commit 3647a4977fb73d ("selftests/landlock:
+Drain stale audit records on init") tried to fix. However, the added
+drain loop is not effective. When setting the AUDIT_STATUS_PID, the
+kauditd_thread is woken up starting to send messages from the hold queue
+to the netlink. Depending on scheduling of this kthread not all messages
+might be send via the netlink in the 1 us interval.
+
+Therefore, instead of trying to drain the queue, let's just disable
+audit when running non-audit tests or more precisely disable it after
+audit-tests. This way we won't generate any new audit message that could
+interfere with the other tests.
+
+The comment saying that on process exit audit will be disabled is wrong.
+The closed file descriptor just causes an auditd_reset(), not a
+disablement. So future messages will be queued in the hold queue.
+
+Cc: stable@vger.kernel.org
+Fixes: 6a500b22971c ("selftests/landlock: Add tests for audit flags and domain IDs")
+Signed-off-by: Maximilian Heyne <mheyne@amazon.de>
+Link: https://patch.msgid.link/20260529-welsh-nagoya-b4d9ca60@mheyne-amazon
+[mic: Fix FD leak, update subject, call audit_cleanup() in audit_exec teardown]
+Signed-off-by: Mickaël Salaün <mic@digikod.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/landlock/audit.h      |   21 ++++++++-------------
+ tools/testing/selftests/landlock/audit_test.c |    4 +---
+ 2 files changed, 9 insertions(+), 16 deletions(-)
+
+--- a/tools/testing/selftests/landlock/audit.h
++++ b/tools/testing/selftests/landlock/audit.h
+@@ -494,10 +494,9 @@ static int audit_init_filter_exe(struct
+ static int audit_cleanup(int audit_fd, struct audit_filter *filter)
+ {
+       struct audit_filter new_filter;
++      int err = 0;
+       if (audit_fd < 0 || !filter) {
+-              int err;
+-
+               /*
+                * Simulates audit_init_with_exe_filter() when called from
+                * FIXTURE_TEARDOWN_PARENT().
+@@ -508,23 +507,19 @@ static int audit_cleanup(int audit_fd, s
+               filter = &new_filter;
+               err = audit_init_filter_exe(filter, NULL);
+-              if (err) {
+-                      close(audit_fd);
+-                      return err;
+-              }
++              if (err)
++                      goto err_close;
+       }
+       /* Filters might not be in place. */
+       audit_filter_exe(audit_fd, filter, AUDIT_DEL_RULE);
+       audit_filter_drop(audit_fd, AUDIT_DEL_RULE);
+-      /*
+-       * Because audit_cleanup() might not be called by the test auditd
+-       * process, it might not be possible to explicitly set it.  Anyway,
+-       * AUDIT_STATUS_ENABLED will implicitly be set to 0 when the auditd
+-       * process will exit.
+-       */
+-      return close(audit_fd);
++      err = audit_set_status(audit_fd, AUDIT_STATUS_ENABLED, 0);
++
++err_close:
++      close(audit_fd);
++      return err;
+ }
+ static int audit_init_with_exe_filter(struct audit_filter *filter)
+--- a/tools/testing/selftests/landlock/audit_test.c
++++ b/tools/testing/selftests/landlock/audit_test.c
+@@ -849,10 +849,8 @@ FIXTURE_SETUP(audit_exec)
+ FIXTURE_TEARDOWN(audit_exec)
+ {
+       set_cap(_metadata, CAP_AUDIT_CONTROL);
+-      EXPECT_EQ(0, audit_filter_exe(self->audit_fd, &self->audit_filter,
+-                                    AUDIT_DEL_RULE));
++      EXPECT_EQ(0, audit_cleanup(self->audit_fd, &self->audit_filter));
+       clear_cap(_metadata, CAP_AUDIT_CONTROL);
+-      EXPECT_EQ(0, close(self->audit_fd));
+ }
+ TEST_F(audit_exec, signal_and_open)
diff --git a/queue-7.1/selftests-landlock-filter-dealloc-records-in-audit_count_records.patch b/queue-7.1/selftests-landlock-filter-dealloc-records-in-audit_count_records.patch
new file mode 100644 (file)
index 0000000..c12b242
--- /dev/null
@@ -0,0 +1,161 @@
+From 26679fad81a471428707d2dd7b0418204c52b7e4 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= <mic@digikod.net>
+Date: Wed, 13 May 2026 12:51:08 +0200
+Subject: selftests/landlock: Filter dealloc records in audit_count_records()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Mickaël Salaün <mic@digikod.net>
+
+commit 26679fad81a471428707d2dd7b0418204c52b7e4 upstream.
+
+audit_count_records() counts both AUDIT_LANDLOCK_DOMAIN allocation and
+deallocation records in records.domain .  Domain deallocation is tied to
+asynchronous credential freeing via kworker threads
+(landlock_put_ruleset_deferred), so the dealloc record can arrive after
+the drain in audit_init() and after the preceding audit_match_record()
+call.  This causes flaky failures in tests that assert an exact
+records.domain count: a stale dealloc record from a previous test's
+domain inflates the count by one.
+
+Observed on x86_64 under build configurations that delay the kworker
+firing the dealloc callback (e.g. coverage instrumentation): the
+audit_layout1 tests in fs_test.c intermittently saw records.domain == 2
+where 1 was expected.  The fix is in the shared helper, so those
+existing checks become robust without needing a fs_test.c edit.
+
+Filter audit_count_records() with a regex to skip records containing
+deallocation status.  The remaining domain records (allocation, emitted
+synchronously during landlock_log_denial()) are deterministic.
+Deallocation records are already tested explicitly via
+matches_log_domain_deallocated() in audit_test.c, which uses its own
+domain-ID-based filtering and longer timeout.
+
+With this filter in place, re-add the records.domain == 0 checks that
+were removed in commit 3647a4977fb7 ("selftests/landlock: Drain stale
+audit records on init") as a workaround for this race.
+
+Cc: Günther Noack <gnoack@google.com>
+Cc: stable@vger.kernel.org
+Depends-on: 07c2572a8757 ("selftests/landlock: Skip stale records in audit_match_record()")
+Fixes: 6a500b22971c ("selftests/landlock: Add tests for audit flags and domain IDs")
+Tested-by: Günther Noack <gnoack3000@gmail.com>
+Link: https://patch.msgid.link/20260513105112.140137-1-mic@digikod.net
+Signed-off-by: Mickaël Salaün <mic@digikod.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/landlock/audit.h                     |   39 +++++++----
+ tools/testing/selftests/landlock/audit_test.c                |    2 
+ tools/testing/selftests/landlock/ptrace_test.c               |    1 
+ tools/testing/selftests/landlock/scoped_abstract_unix_test.c |    1 
+ 4 files changed, 30 insertions(+), 13 deletions(-)
+
+--- a/tools/testing/selftests/landlock/audit.h
++++ b/tools/testing/selftests/landlock/audit.h
+@@ -381,18 +381,24 @@ struct audit_records {
+ };
+ /*
+- * WARNING: Do not assert records.domain == 0 without a preceding
+- * audit_match_record() call.  Domain deallocation records are emitted
+- * asynchronously from kworker threads and can arrive after the drain in
+- * audit_init(), corrupting the domain count.  A preceding audit_match_record()
+- * call consumes stale records while scanning, making the assertion safe in
+- * practice because stale deallocation records arrive before the expected access
+- * records.
++ * Counts remaining audit records by type, skipping domain deallocation records.
++ * Deallocation records are emitted asynchronously from kworker threads after a
++ * previous test's child has exited, so they can arrive after the drain in
++ * audit_init() and after the preceding audit_match_record() call.  Allocation
++ * records are emitted synchronously during landlock_log_denial() in the current
++ * test's syscall context, so only those are counted in records->domain.
+  */
+ static int audit_count_records(int audit_fd, struct audit_records *records)
+ {
++      static const char dealloc_pattern[] = REGEX_LANDLOCK_PREFIX
++              " status=deallocated ";
+       struct audit_message msg;
+-      int err;
++      regex_t dealloc_re;
++      int ret, err = 0;
++
++      ret = regcomp(&dealloc_re, dealloc_pattern, 0);
++      if (ret)
++              return -ENOMEM;
+       records->access = 0;
+       records->domain = 0;
+@@ -402,9 +408,8 @@ static int audit_count_records(int audit
+               err = audit_recv(audit_fd, &msg);
+               if (err) {
+                       if (err == -EAGAIN)
+-                              return 0;
+-                      else
+-                              return err;
++                              err = 0;
++                      break;
+               }
+               switch (msg.header.nlmsg_type) {
+@@ -412,12 +417,20 @@ static int audit_count_records(int audit
+                       records->access++;
+                       break;
+               case AUDIT_LANDLOCK_DOMAIN:
+-                      records->domain++;
++                      ret = regexec(&dealloc_re, msg.data, 0, NULL, 0);
++                      if (ret == REG_NOMATCH) {
++                              records->domain++;
++                      } else if (ret != 0) {
++                              err = -EIO;
++                              goto out;
++                      }
+                       break;
+               }
+       } while (true);
+-      return 0;
++out:
++      regfree(&dealloc_re);
++      return err;
+ }
+ static int audit_init(void)
+--- a/tools/testing/selftests/landlock/audit_test.c
++++ b/tools/testing/selftests/landlock/audit_test.c
+@@ -730,6 +730,7 @@ TEST_F(audit_flags, signal)
+               } else {
+                       EXPECT_EQ(1, records.access);
+               }
++              EXPECT_EQ(0, records.domain);
+               /* Updates filter rules to match the drop record. */
+               set_cap(_metadata, CAP_AUDIT_CONTROL);
+@@ -915,6 +916,7 @@ TEST_F(audit_exec, signal_and_open)
+       /* Tests that there was no denial until now. */
+       EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
+       EXPECT_EQ(0, records.access);
++      EXPECT_EQ(0, records.domain);
+       /*
+        * Wait for the child to do a first denied action by layer1 and
+--- a/tools/testing/selftests/landlock/ptrace_test.c
++++ b/tools/testing/selftests/landlock/ptrace_test.c
+@@ -342,6 +342,7 @@ TEST_F(audit, trace)
+       /* Makes sure there is no superfluous logged records. */
+       EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
+       EXPECT_EQ(0, records.access);
++      EXPECT_EQ(0, records.domain);
+       yama_ptrace_scope = get_yama_ptrace_scope();
+       ASSERT_LE(0, yama_ptrace_scope);
+--- a/tools/testing/selftests/landlock/scoped_abstract_unix_test.c
++++ b/tools/testing/selftests/landlock/scoped_abstract_unix_test.c
+@@ -312,6 +312,7 @@ TEST_F(scoped_audit, connect_to_child)
+       /* Makes sure there is no superfluous logged records. */
+       EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
+       EXPECT_EQ(0, records.access);
++      EXPECT_EQ(0, records.domain);
+       ASSERT_EQ(0, pipe2(pipe_child, O_CLOEXEC));
+       ASSERT_EQ(0, pipe2(pipe_parent, O_CLOEXEC));
diff --git a/queue-7.1/selftests-landlock-increase-default-audit-socket-timeout.patch b/queue-7.1/selftests-landlock-increase-default-audit-socket-timeout.patch
new file mode 100644 (file)
index 0000000..3c1b891
--- /dev/null
@@ -0,0 +1,213 @@
+From d8dfb4c7faa87c3e41a8678f38f136c2c7c036fa Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= <mic@digikod.net>
+Date: Wed, 13 May 2026 12:51:09 +0200
+Subject: selftests/landlock: Increase default audit socket timeout
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Mickaël Salaün <mic@digikod.net>
+
+commit d8dfb4c7faa87c3e41a8678f38f136c2c7c036fa upstream.
+
+matches_log_fs() and other audit_match_record() callers intermittently
+return -EAGAIN under heavy debug configs (KASAN, lockdep).  The audit
+record delivery pipeline is asynchronous: landlock_log_denial() queues
+the record to audit_queue, and kauditd_thread dequeues and delivers via
+netlink.  Under debug configs, kauditd scheduling between
+audit_log_end() and netlink_unicast() can exceed a syscall round trip
+(more than 1 usec), which was the value of the socket timeout used for
+the recvfrom() calls.
+
+The observed failure [1] is an EAGAIN error code (-11) which means that
+the access record had not arrived within the 1 usec timeout of
+recvfrom().  The expected record does arrive, but only after
+matches_log_fs() has already returned.  It is then consumed by a later
+audit_count_records() call, making records.access == 1 instead of 0.
+
+Switch the default socket timeout to the slow value (1 second) so all
+audit_match_record() callers wait long enough for kauditd delivery, and
+lower it to the fast value (1 usec) only on the two paths that expect no
+record: audit_count_records() and the expected_domain_id == 0 probe in
+matches_log_domain_deallocated().  audit_init() drains stale records
+with the fast timeout (terminating on -EAGAIN once the backlog is empty)
+and switches to the patient default before returning.  1 second gives
+~10x margin over the observed maximum (~100 ms, while the happy path is
+~23 us).
+
+Rename the timeval constants to reflect their new roles:
+- audit_tv_dom_drop (1 second) -> audit_tv_default: default socket
+  timeout, patient enough for asynchronous kauditd delivery.
+- audit_tv_default (1 usec) -> audit_tv_fast: fast timeout for paths
+  that expect no record (drain, audit_count_records(), probes).
+
+Invert the conditional in matches_log_domain_deallocated().  Check
+setsockopt returns on both the lower and restore paths; preserve the
+first error via !err when the restore fails after a prior error so the
+actionable return code is not masked by a bookkeeping failure.
+
+Cc: Günther Noack <gnoack@google.com>
+Cc: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
+Cc: stable@vger.kernel.org
+Depends-on: 07c2572a8757 ("selftests/landlock: Skip stale records in audit_match_record()")
+Fixes: 6a500b22971c ("selftests/landlock: Add tests for audit flags and domain IDs")
+Reported-by: Günther Noack <gnoack3000@gmail.com>
+Closes: https://lore.kernel.org/r/20260402.eb5c4e85f472@gnoack.org [1]
+Reported-by: kernel test robot <oliver.sang@intel.com>
+Closes: https://lore.kernel.org/oe-lkp/202605111649.a8b30a62-lkp@intel.com
+Closes: https://lore.kernel.org/oe-lkp/202604300436.a07fae12-lkp@intel.com
+Tested-by: Günther Noack <gnoack3000@gmail.com>
+Link: https://patch.msgid.link/20260513105112.140137-2-mic@digikod.net
+Signed-off-by: Mickaël Salaün <mic@digikod.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/landlock/audit.h |   80 ++++++++++++++++++++++++-------
+ 1 file changed, 63 insertions(+), 17 deletions(-)
+
+--- a/tools/testing/selftests/landlock/audit.h
++++ b/tools/testing/selftests/landlock/audit.h
+@@ -45,17 +45,25 @@ struct audit_message {
+       };
+ };
+-static const struct timeval audit_tv_dom_drop = {
++static const struct timeval audit_tv_default = {
+       /*
+-       * Because domain deallocation is tied to asynchronous credential
+-       * freeing, receiving such event may take some time.  In practice,
+-       * on a small VM, it should not exceed 100k usec, but let's wait up
+-       * to 1 second to be safe.
++       * Default socket timeout for audit_match_record() callers that expect a
++       * record to arrive.  Asynchronous kauditd delivery can exceed 1 usec
++       * under heavy debug configs (KASAN, lockdep), where kauditd_thread
++       * scheduling between audit_log_end() and netlink_unicast() takes longer
++       * than the previous 1 usec timeout. 1 second is a generous ceiling: on
++       * the happy path, kauditd delivers within dozens of usec.
+        */
+       .tv_sec = 1,
+ };
+-static const struct timeval audit_tv_default = {
++static const struct timeval audit_tv_fast = {
++      /*
++       * Fast timeout for paths that expect no record (audit_init() drain,
++       * audit_count_records(), probes).  Causes audit_recv() to return
++       * -EAGAIN once the socket buffer is empty, naturally terminating the
++       * read loop.
++       */
+       .tv_usec = 1,
+ };
+@@ -334,8 +342,13 @@ static int __maybe_unused matches_log_do
+  * Matches a domain deallocation record.  When expected_domain_id is non-zero,
+  * the pattern includes the specific domain ID so that stale deallocation
+  * records from a previous test (with a different domain ID) are skipped by
+- * audit_match_record(), and the socket timeout is temporarily increased to
+- * audit_tv_dom_drop to wait for the asynchronous kworker deallocation.
++ * audit_match_record(), waiting for the asynchronous kworker deallocation with
++ * the default patient timeout.
++ *
++ * When expected_domain_id is zero, the caller is probing for any dealloc record
++ * that may or may not arrive.  Temporarily lowers the socket timeout to
++ * audit_tv_fast for this probe so it returns promptly when no record is
++ * pending; restores audit_tv_default after.
+  */
+ static int __maybe_unused
+ matches_log_domain_deallocated(int audit_fd, unsigned int num_denials,
+@@ -361,16 +374,21 @@ matches_log_domain_deallocated(int audit
+       if (log_match_len >= sizeof(log_match))
+               return -E2BIG;
+-      if (expected_domain_id)
+-              setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO,
+-                         &audit_tv_dom_drop, sizeof(audit_tv_dom_drop));
++      if (!expected_domain_id) {
++              if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO,
++                             &audit_tv_fast, sizeof(audit_tv_fast)))
++                      return -errno;
++      }
+       err = audit_match_record(audit_fd, AUDIT_LANDLOCK_DOMAIN, log_match,
+                                domain_id);
+-      if (expected_domain_id)
+-              setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default,
+-                         sizeof(audit_tv_default));
++      if (!expected_domain_id) {
++              if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO,
++                             &audit_tv_default, sizeof(audit_tv_default)) &&
++                  !err)
++                      err = -errno;
++      }
+       return err;
+ }
+@@ -387,6 +405,11 @@ struct audit_records {
+  * audit_init() and after the preceding audit_match_record() call.  Allocation
+  * records are emitted synchronously during landlock_log_denial() in the current
+  * test's syscall context, so only those are counted in records->domain.
++ *
++ * Temporarily lowers SO_RCVTIMEO to audit_tv_fast for the read loop: this is a
++ * "no record expected" path that should terminate on the first -EAGAIN.  The
++ * default patient timeout is restored on exit for subsequent
++ * audit_match_record() callers.
+  */
+ static int audit_count_records(int audit_fd, struct audit_records *records)
+ {
+@@ -403,6 +426,12 @@ static int audit_count_records(int audit
+       records->access = 0;
+       records->domain = 0;
++      if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_fast,
++                     sizeof(audit_tv_fast))) {
++              err = -errno;
++              goto out;
++      }
++
+       do {
+               memset(&msg, 0, sizeof(msg));
+               err = audit_recv(audit_fd, &msg);
+@@ -429,6 +458,10 @@ static int audit_count_records(int audit
+       } while (true);
+ out:
++      if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default,
++                     sizeof(audit_tv_default)) &&
++          !err)
++              err = -errno;
+       regfree(&dealloc_re);
+       return err;
+ }
+@@ -449,9 +482,9 @@ static int audit_init(void)
+       if (err)
+               goto err_close;
+-      /* Sets a timeout for negative tests. */
+-      err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default,
+-                       sizeof(audit_tv_default));
++      /* Uses the fast timeout to drain stale records below. */
++      err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_fast,
++                       sizeof(audit_tv_fast));
+       if (err) {
+               err = -errno;
+               goto err_close;
+@@ -467,6 +500,19 @@ static int audit_init(void)
+       while (audit_recv(fd, NULL) == 0)
+               ;
++      /*
++       * Restores the default timeout for audit_match_record() callers that
++       * expect a record to arrive.  Paths that expect no record restore the
++       * fast timeout locally (audit_count_records(), the expected_domain_id
++       * == 0 probe in matches_log_domain_deallocated()).
++       */
++      err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default,
++                       sizeof(audit_tv_default));
++      if (err) {
++              err = -errno;
++              goto err_close;
++      }
++
+       return fd;
+ err_close:
index 3f686228f6e5b8b17b0154861be52a5b6269733c..d60aab4c9e3dd3e9d6484998ab625c03632cd7da 100644 (file)
@@ -428,3 +428,42 @@ selftests-mm-pagemap_ioctl-use-the-correct-page-size-for-transact_test.patch
 selftests-mm-fix-ksft_process_madv.sh-test-category.patch
 nouveau-vmm-fix-another-spt-lpt-race.patch
 bpf-reject-bpf_map_type_inode_storage-creation-if-bpf-lsm-is-uninitialized.patch
+iommu-vt-d-avoid-warning-in-sva-unbind-path.patch
+iommu-amd-don-t-split-flush-for-amd_iommu_domain_flush_all.patch
+iommufd-use-sizeof-hdr-instead-of-sizeof-hdr-in-veventq-read.patch
+iommufd-fix-data_len-byte-count-vs-element-count-mismatch.patch
+iommufd-move-vevent-memory-allocation-outside-spinlock.patch
+iommufd-set-veventq_depth-upper-bound.patch
+iommufd-rewind-header-length-in-done-if-iommufd_veventq_fops_read-fails.patch
+iommufd-reject-invalid-read-count-in-iommufd_veventq_fops_read.patch
+iommufd-propagate-allocation-failure-in-iommufd_veventq_deliver_fetch.patch
+iommufd-reject-invalid-read-count-in-iommufd_fault_fops_read.patch
+iommufd-break-the-loop-on-failure-in-iommufd_fault_fops_read.patch
+iommufd-avoid-partial-fault-group-delivery-in-iommufd_fault_fops_read.patch
+iommufd-set-upper-bounds-on-cache-invalidation-entry_num-and-entry_len.patch
+audit-fix-removal-of-dangling-executable-rules.patch
+landlock-set-audit_net.sk-for-socket-access-checks.patch
+selftests-landlock-explicitly-disable-audit-in-teardowns.patch
+landlock-account-all-audit-data-allocations-to-user-space.patch
+selftests-landlock-filter-dealloc-records-in-audit_count_records.patch
+selftests-landlock-increase-default-audit-socket-timeout.patch
+kvm-arm64-nv-avoid-dereferencing-null-vncr-pseudo-tlb.patch
+loongarch-kvm-add-missing-slots_lock-for-device-register-unregister.patch
+kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-vcpu.patch
+kvm-arm64-clear-__hyp_running_vcpu-when-flushing-the-pkvm-hyp-vcpu.patch
+kvm-sev-pin-source-page-for-write-when-adding-cpuid-data-for-snp-guest.patch
+kvm-svm-disable-x2avic-rdmsr-interception-for-msrs-kvm-actually-supports.patch
+kvm-svm-only-disable-x2avic-wrmsr-interception-for-msrs-that-are-accelerated.patch
+kvm-vmx-refresh-guest_pending_dbg_exceptions.bs-on-all-injected-dbs.patch
+kvm-sev-don-t-terminate-snp-vms-on-vmgexit-without-a-registered-ghcb.patch
+kvm-vmx-handle-bad-values-on-proxied-writes-to-lbr-msrs.patch
+kvm-tdx-account-all-non-transient-page-allocations-for-per-td-structures.patch
+kvm-x86-ensure-vendor-s-exit-handler-runs-before-fastpath-userspace-exits.patch
+kvm-guest_memfd-treat-memslot-binding-offset-size-as-unsigned-values.patch
+kvm-x86-add-dedicated-api-for-getting-mask-of-accelerated-x2apic-msrs.patch
+kvm-arm64-don-t-leak-pfn-when-kvm_translate_vncr-races-mmu-notifier.patch
+udmabuf-fix-dma-direction-mismatch-in-release_udmabuf.patch
+dma-buf-udmabuf-skip-redundant-cpu-sync-to-fix-cacheline-eexist-warning.patch
+svcrdma-wake-sq-waiters-when-the-transport-closes.patch
+revert-svcrdma-use-contiguous-pages-for-rdma-read-sink-buffers.patch
+fpga-dfl-afu-validate-dma-mapping-length-in-afu_dma_map_region.patch
diff --git a/queue-7.1/svcrdma-wake-sq-waiters-when-the-transport-closes.patch b/queue-7.1/svcrdma-wake-sq-waiters-when-the-transport-closes.patch
new file mode 100644 (file)
index 0000000..9267ddf
--- /dev/null
@@ -0,0 +1,216 @@
+From e5248a7426030db1e126363f72afdb3b71339a5c Mon Sep 17 00:00:00 2001
+From: Chuck Lever <chuck.lever@oracle.com>
+Date: Fri, 22 May 2026 14:13:57 -0400
+Subject: svcrdma: wake sq waiters when the transport closes
+
+From: Chuck Lever <chuck.lever@oracle.com>
+
+commit e5248a7426030db1e126363f72afdb3b71339a5c upstream.
+
+Threads parked in svc_rdma_sq_wait() on sc_sq_ticket_wait or
+sc_send_wait can hang indefinitely in TASK_UNINTERRUPTIBLE state
+across transport teardown, pinning svc_xprt references and
+blocking svc_rdma_free().
+
+The close path sets XPT_CLOSE before invoking xpo_detach and both
+wait_event predicates include an XPT_CLOSE term, but the
+predicates are re-evaluated only on wakeup. sc_sq_ticket_wait has
+no completion-driven wake path; it is advanced solely by the
+chained ticket handoff inside svc_rdma_sq_wait() itself. Without
+an explicit wake at close, parked threads never observe
+XPT_CLOSE, hold their svc_xprt_get reference forever, and
+svc_rdma_free() blocks on xpt_ref dropping to zero.
+
+Two close entry points reach this transport. Local teardown runs
+svc_rdma_detach() from svc_handle_xprt() -> svc_delete_xprt() ->
+xpo_detach() on a worker thread. A remote disconnect arrives at
+svc_rdma_cma_handler(), which calls svc_xprt_deferred_close():
+that sets XPT_CLOSE and enqueues the transport but does not
+access either RDMA waitqueue, so a worker already parked in
+svc_rdma_sq_wait() never re-evaluates its predicate. With every
+worker parked on this transport, no thread is available to run
+the local teardown either, and the wake site there is
+unreachable.
+
+Introduce svc_rdma_xprt_deferred_close(), a thin svcrdma wrapper
+that calls svc_xprt_deferred_close() and then wakes both
+sc_sq_ticket_wait and sc_send_wait. Convert the svcrdma producers
+that called svc_xprt_deferred_close() directly:
+svc_rdma_cma_handler(), qp_event_handler(),
+svc_rdma_post_send_err(), svc_rdma_wc_send(), the sendto drop
+path, the rw completion error paths, and the recvfrom flush and
+read-list error paths.
+
+Wake both waitqueues from svc_rdma_detach() as well. The
+synchronous svc_xprt_close() path (backchannel ENOTCONN, device
+removal via svc_rdma_xprt_done) reaches detach without flowing
+through svc_xprt_deferred_close() and therefore does not invoke
+the new helper.
+
+Fixes: ccc89b9d1ed2 ("svcrdma: Add fair queuing for Send Queue access")
+Cc: stable@vger.kernel.org
+Assisted-by: kres (claude-opus-4-7)
+Signed-off-by: Chris Mason <clm@meta.com>
+[ cel: add svc_rdma_xprt_deferred_close() to complete the fix ]
+Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/sunrpc/svc_rdma.h          |    1 +
+ net/sunrpc/xprtrdma/svc_rdma_recvfrom.c  |    4 ++--
+ net/sunrpc/xprtrdma/svc_rdma_rw.c        |    6 +++---
+ net/sunrpc/xprtrdma/svc_rdma_sendto.c    |    6 +++---
+ net/sunrpc/xprtrdma/svc_rdma_transport.c |   30 ++++++++++++++++++++++++++++--
+ 5 files changed, 37 insertions(+), 10 deletions(-)
+
+--- a/include/linux/sunrpc/svc_rdma.h
++++ b/include/linux/sunrpc/svc_rdma.h
+@@ -328,6 +328,7 @@ extern int svc_rdma_result_payload(struc
+                                  unsigned int length);
+ /* svc_rdma_transport.c */
++extern void svc_rdma_xprt_deferred_close(struct svcxprt_rdma *rdma);
+ extern struct svc_xprt_class svc_rdma_class;
+ #ifdef CONFIG_SUNRPC_BACKCHANNEL
+ extern struct svc_xprt_class svc_rdma_bc_class;
+--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+@@ -377,7 +377,7 @@ flushed:
+               trace_svcrdma_wc_recv_err(wc, &ctxt->rc_cid);
+ dropped:
+       svc_rdma_recv_ctxt_put(rdma, ctxt);
+-      svc_xprt_deferred_close(&rdma->sc_xprt);
++      svc_rdma_xprt_deferred_close(rdma);
+ }
+ /**
+@@ -1001,7 +1001,7 @@ out_readlist:
+               if (ret == -EINVAL)
+                       svc_rdma_send_error(rdma_xprt, ctxt, ret);
+               svc_rdma_recv_ctxt_put(rdma_xprt, ctxt);
+-              svc_xprt_deferred_close(xprt);
++              svc_rdma_xprt_deferred_close(rdma_xprt);
+               return ret;
+       }
+       return 0;
+--- a/net/sunrpc/xprtrdma/svc_rdma_rw.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c
+@@ -313,7 +313,7 @@ static void svc_rdma_reply_done(struct i
+               trace_svcrdma_wc_reply_err(wc, &cc->cc_cid);
+       }
+-      svc_xprt_deferred_close(&rdma->sc_xprt);
++      svc_rdma_xprt_deferred_close(rdma);
+ }
+ /**
+@@ -345,7 +345,7 @@ static void svc_rdma_write_done(struct i
+        * some of the outgoing RPC message. Signal the loss
+        * to the client by closing the connection.
+        */
+-      svc_xprt_deferred_close(&rdma->sc_xprt);
++      svc_rdma_xprt_deferred_close(rdma);
+ }
+ /**
+@@ -390,7 +390,7 @@ static void svc_rdma_wc_read_done(struct
+        */
+       svc_rdma_cc_release(rdma, cc, DMA_FROM_DEVICE);
+       svc_rdma_recv_ctxt_put(rdma, ctxt);
+-      svc_xprt_deferred_close(&rdma->sc_xprt);
++      svc_rdma_xprt_deferred_close(rdma);
+ }
+ /*
+--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+@@ -395,7 +395,7 @@ int svc_rdma_post_send_err(struct svcxpr
+                          int sqecount, int ret)
+ {
+       trace_svcrdma_sq_post_err(rdma, cid, ret);
+-      svc_xprt_deferred_close(&rdma->sc_xprt);
++      svc_rdma_xprt_deferred_close(rdma);
+       /* If even one WR was posted, a Send completion will
+        * return the reserved SQ slots.
+@@ -437,7 +437,7 @@ flushed:
+       else
+               trace_svcrdma_wc_send_flush(wc, &ctxt->sc_cid);
+       svc_rdma_send_ctxt_put(rdma, ctxt);
+-      svc_xprt_deferred_close(&rdma->sc_xprt);
++      svc_rdma_xprt_deferred_close(rdma);
+ }
+ /**
+@@ -1158,7 +1158,7 @@ put_ctxt:
+       svc_rdma_send_ctxt_put(rdma, sctxt);
+ drop_connection:
+       trace_svcrdma_send_err(rqstp, ret);
+-      svc_xprt_deferred_close(&rdma->sc_xprt);
++      svc_rdma_xprt_deferred_close(rdma);
+       return -ENOTCONN;
+ }
+--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
+@@ -98,10 +98,27 @@ struct svc_xprt_class svc_rdma_class = {
+       .xcl_ident = XPRT_TRANSPORT_RDMA,
+ };
++/**
++ * svc_rdma_xprt_deferred_close - Close an RDMA transport (deferred)
++ * @rdma: transport to close
++ */
++void svc_rdma_xprt_deferred_close(struct svcxprt_rdma *rdma)
++{
++      svc_xprt_deferred_close(&rdma->sc_xprt);
++
++      /* Release parked sc_sq_ticket_wait and sc_send_wait waiters.
++       * Once XPT_CLOSE is observed each returns -ENOTCONN.
++       */
++      wake_up_all(&rdma->sc_sq_ticket_wait);
++      wake_up_all(&rdma->sc_send_wait);
++}
++
+ /* QP event handler */
+ static void qp_event_handler(struct ib_event *event, void *context)
+ {
+       struct svc_xprt *xprt = context;
++      struct svcxprt_rdma *rdma =
++              container_of(xprt, struct svcxprt_rdma, sc_xprt);
+       trace_svcrdma_qp_error(event, (struct sockaddr *)&xprt->xpt_remote);
+       switch (event->event) {
+@@ -119,7 +136,7 @@ static void qp_event_handler(struct ib_e
+       case IB_EVENT_QP_ACCESS_ERR:
+       case IB_EVENT_DEVICE_FATAL:
+       default:
+-              svc_xprt_deferred_close(xprt);
++              svc_rdma_xprt_deferred_close(rdma);
+               break;
+       }
+ }
+@@ -340,7 +357,7 @@ static int svc_rdma_cma_handler(struct r
+               svc_xprt_enqueue(xprt);
+               break;
+       case RDMA_CM_EVENT_DISCONNECTED:
+-              svc_xprt_deferred_close(xprt);
++              svc_rdma_xprt_deferred_close(rdma);
+               break;
+       default:
+               break;
+@@ -597,6 +614,15 @@ static void svc_rdma_detach(struct svc_x
+               container_of(xprt, struct svcxprt_rdma, sc_xprt);
+       rdma_disconnect(rdma->sc_cm_id);
++
++      /*
++       * Most close paths go through svc_rdma_xprt_deferred_close(),
++       * which wakes the SQ waitqueues. svc_xprt_close() reaches
++       * detach without that helper, so wake any threads parked in
++       * svc_rdma_sq_wait() here as well.
++       */
++      wake_up_all(&rdma->sc_sq_ticket_wait);
++      wake_up_all(&rdma->sc_send_wait);
+ }
+ /**
diff --git a/queue-7.1/udmabuf-fix-dma-direction-mismatch-in-release_udmabuf.patch b/queue-7.1/udmabuf-fix-dma-direction-mismatch-in-release_udmabuf.patch
new file mode 100644 (file)
index 0000000..b3d9145
--- /dev/null
@@ -0,0 +1,70 @@
+From fb7b1a0ab25a6077d26cb3829e31743972d4f31d Mon Sep 17 00:00:00 2001
+From: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
+Date: Sun, 15 Mar 2026 04:27:22 +0500
+Subject: udmabuf: fix DMA direction mismatch in release_udmabuf()
+
+From: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
+
+commit fb7b1a0ab25a6077d26cb3829e31743972d4f31d upstream.
+
+begin_cpu_udmabuf() maps the sg_table with the caller-provided direction
+(e.g., DMA_TO_DEVICE for a write-only sync), and caches it in ubuf->sg
+for reuse.  However, release_udmabuf() always unmaps this sg_table with
+a hardcoded DMA_BIDIRECTIONAL, regardless of the direction that was
+originally used for the mapping.
+
+With CONFIG_DMA_API_DEBUG=y this produces:
+
+  DMA-API: misc udmabuf: device driver frees DMA memory with different
+  direction [device address=0x000000044a123000] [size=4096 bytes]
+  [mapped with DMA_TO_DEVICE] [unmapped with DMA_BIDIRECTIONAL]
+
+The issue was found during video playback when GStreamer performed a
+write-only DMA_BUF_IOCTL_SYNC on a udmabuf.  It can be reproduced
+with CONFIG_DMA_API_DEBUG=y by creating a udmabuf from a memfd,
+performing a write-only sync (DMA_BUF_SYNC_WRITE without
+DMA_BUF_SYNC_READ), and closing the file descriptor.
+
+Fix this by storing the DMA direction used when the sg_table is first
+created in begin_cpu_udmabuf(), and passing that same direction to
+put_sg_table() in release_udmabuf().
+
+Fixes: 284562e1f348 ("udmabuf: implement begin_cpu_access/end_cpu_access hooks")
+Cc: stable@vger.kernel.org
+Signed-off-by: Mikhail Gavrilov <mikhail.v.gavrilov@gmail.com>
+Reviewed-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
+Signed-off-by: Vivek Kasireddy <vivek.kasireddy@intel.com>
+Link: https://patch.msgid.link/20260314232722.15555-1-mikhail.v.gavrilov@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/dma-buf/udmabuf.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/dma-buf/udmabuf.c
++++ b/drivers/dma-buf/udmabuf.c
+@@ -40,6 +40,7 @@ struct udmabuf {
+       struct folio **pinned_folios;
+       struct sg_table *sg;
++      enum dma_data_direction sg_dir;
+       struct miscdevice *device;
+       pgoff_t *offsets;
+ };
+@@ -235,7 +236,7 @@ static void release_udmabuf(struct dma_b
+       struct device *dev = ubuf->device->this_device;
+       if (ubuf->sg)
+-              put_sg_table(dev, ubuf->sg, DMA_BIDIRECTIONAL);
++              put_sg_table(dev, ubuf->sg, ubuf->sg_dir);
+       deinit_udmabuf(ubuf);
+       kfree(ubuf);
+@@ -253,6 +254,8 @@ static int begin_cpu_udmabuf(struct dma_
+               if (IS_ERR(ubuf->sg)) {
+                       ret = PTR_ERR(ubuf->sg);
+                       ubuf->sg = NULL;
++              } else {
++                      ubuf->sg_dir = direction;
+               }
+       } else {
+               dma_sync_sgtable_for_cpu(dev, ubuf->sg, direction);