From: Tian Zheng <zhengtian10@huawei.com>
To: <sashiko-reviews@lists.linux.dev>
Cc: <kvm@vger.kernel.org>, <kvmarm@lists.linux.dev>,
Oliver Upton <oupton@kernel.org>, Marc Zyngier <maz@kernel.org>
Subject: Re: [PATCH v4 6/6] KVM: arm64: Add auto HDBSS enable/disable on dirty logging change
Date: Mon, 31 Aug 2026 20:23:26 +0800 [thread overview]
Message-ID: <8a593c94-3fa5-4504-bbd3-4f9bbaf78264@huawei.com> (raw)
In-Reply-To: <20260709113436.951C81F000E9@smtp.kernel.org>
On 7/9/2026 7:34 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:
> - [Critical] Freeing HDBSS buffers synchronously in `kvm_arm_disable_hdbss_global()` without kicking vCPUs causes a hardware Use-After-Free and host memory corruption.
> - [High] The patch fails to enforce eager page table splitting when `KVM_DIRTY_LOG_INITIALLY_SET` is used, violating the HDBSS requirement.
> - [High] Global enable/disable functions mutate per-vCPU HDBSS state across all vCPUs without proper locking or KVM request mechanisms.
> - [High] Missing `kvm_unshare_hyp()` on the vCPU creation error path breaks pKVM memory ownership.
> - [High] Memslots are accessed without SRCU protection when flushing the HDBSS buffer.
> - [Medium] The dynamically calculated HDBSS buffer order is never saved, causing newly created vCPUs to allocate incorrect 1-page buffers.
> - [Medium] A conditional check in `kvm_arm_vcpu_destroy` leaks HDBSS buffers if a TOCTOU race left a vCPU with an allocated buffer while `enable_hdbss` is false.
> - [Medium] Missing immediate Context Synchronization Events (ISB) for control-plane system registers.
> --
>
> --- Patch [6]: [PATCH v4 6/6] KVM: arm64: Add auto HDBSS enable/disable on dirty logging change ---
> commit c993a05c79f4338df277681c6534d32f65490e56
> Author: eillon <yezhenyu2@huawei.com>
>
> KVM: arm64: Add auto HDBSS enable/disable on dirty logging change
>
> This commit adds VM-level HDBSS enable/disable support tied to dirty logging
> changes. It automatically enables HDBSS when dirty logging starts and disables
> it when all memslots stop dirty logging.
>
>> diff --git a/arch/arm64/kvm/dirty_bit.c b/arch/arm64/kvm/dirty_bit.c
>> index 002366337637c..c5bf866c23ef2 100644
>> --- a/arch/arm64/kvm/dirty_bit.c
>> +++ b/arch/arm64/kvm/dirty_bit.c
> [ ... ]
>> +static int kvm_arm_enable_hdbss_global(struct kvm *kvm)
>> +{
>> + int err;
>> + unsigned long i;
>> + unsigned int order;
>> + struct kvm_vcpu *vcpu;
> [ ... ]
>> + /* Turn it on */
>> + order = hdbss_auto_select_order(kvm);
>> + kvm_for_each_vcpu(i, vcpu, kvm) {
>> + err = kvm_arm_vcpu_alloc_hdbss(vcpu, order);
>
> [Severity: Medium]
> Will newly created vCPUs allocate buffers of the correct size?
>
> The optimal HDBSS buffer order is calculated here based on memslot sizes and
> used to allocate buffers for currently online vCPUs, but the value doesn't
> seem to be saved to kvm->arch.hdbss_order.
>
> When a new vCPU is created later, it appears kvm_arch_vcpu_create() allocates
> its buffer using the uninitialized kvm->arch.hdbss_order:
>
> arch/arm64/kvm/arm.c:kvm_arch_vcpu_create() {
> ...
> err = kvm_arm_vcpu_alloc_hdbss(vcpu, vcpu->kvm->arch.hdbss_order);
> ...
> }
>
> Could this cause new vCPUs to receive order-0 buffers instead of the
> dynamically selected size, leading to mismatched sizes and excessive
> buffer-full exits?
>
Addressed by redesign in v5. The dynamic order calculation is removed.
The buffer size is now stored in kvm->arch.hdbss_buffer_size (bytes),
set either by the user via KVM_CAP_ARM_HDBSS_BUFFER_SIZE (before vCPU
creation), or by kvm_arch_dirty_ring_size_updated() when dirty-ring is
configured, or defaults to PAGE_SIZE. Since it is stored in kvm->arch
before any vCPU exists, all vCPUs — including later-created ones —
allocate a consistent size.
> [Severity: High]
> Is it safe to directly mutate per-vCPU HDBSS state across all vCPUs from the
> thread handling the memslot ioctl?
>
> This loop directly calls kvm_arm_vcpu_alloc_hdbss() to mutate vcpu->arch.hdbss
> without holding vcpu->mutex or using the KVM vCPU requests framework.
>
> Could concurrently running vCPUs undergoing a context switch (like
> __load_hdbss) or fault path read partially updated, torn, or freed state,
> leading to unpredictable hardware register programming?
>
>> + if (err)
>> + goto error_alloc;
>> + }
> [ ... ]
>> +void kvm_arm_disable_hdbss_global(struct kvm *kvm)
>> +{
>> + unsigned long i;
>> + struct kvm_vcpu *vcpu;
>> +
>> + if (!kvm->arch.enable_hdbss) /* Already Off */
>> + return;
>> +
>> + /* Turn it off */
>> + kvm->arch.mmu.vtcr &= ~(VTCR_EL2_HD | VTCR_EL2_HDBSS | VTCR_EL2_HA);
>> +
>> + kvm_for_each_vcpu(i, vcpu, kvm)
>> + kvm_arm_vcpu_free_hdbss(vcpu);
>
Addressed by redesign in v5. Enable/disable no longer touch any per-vCPU
state. Buffers are pre-allocated at vCPU creation, and enable/disable
only flips VTCR bits in kvm->arch.mmu.vtcr (a VM-level field written
only from the memslot-ioctl path under slots_lock) followed by a kick.
vCPUs pick up the new VTCR when __load_stage2() reprograms vtcr_el2 on
re-entry.
> [Severity: Critical]
> Does this code risk hardware use-after-free and host memory corruption?
>
> When dirty logging is disabled, the enable_hdbss flag and VTCR_EL2 bits are
> cleared, and the physical pages are immediately freed. Since this occurs under
> kvm->slots_lock, which does not prevent vCPUs from executing in guest mode,
> running vCPUs could continue executing with their hardware VTCR_EL2 and
> HDBSSBR_EL2 registers still active.
>
> Should this function force running vCPUs to exit (e.g., via kvm_vcpu_kick() or
> a KVM request) before freeing the physical pages to prevent the hardware MMU
> from asynchronously writing dirty page records into newly freed memory?
>
>> +
>> + kvm->arch.enable_hdbss = false;
>> +}
> [ ... ]
>> diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
>> index 949fb895add6a..484f48dae0003 100644
>> --- a/arch/arm64/kvm/mmu.c
>> +++ b/arch/arm64/kvm/mmu.c
>> @@ -2588,6 +2588,9 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
>> {
>> bool log_dirty_pages = new && new->flags & KVM_MEM_LOG_DIRTY_PAGES;
> [ ... ]
>> if (log_dirty_pages) {
>>
>> if (change == KVM_MR_DELETE)
>> return;
>>
>> /*
>> * Huge and normal pages are write-protected and split
>> * on either of these two cases:
>> *
>> * 1. with initial-all-set: gradually with CLEAR ioctls,
>> */
>> if (kvm_dirty_log_manual_protect_and_init_set(kvm))
>> return;
>
Valid point, addressed by redesign in v5. kvm_arm_disable_hdbss_global()
no longer frees buffers at all — it only clears the VTCR HDBSS bits and
kicks vCPUs out of guest mode via KVM_REQ_OUTSIDE_GUEST_MODE. Buffers
are allocated at vCPU creation and freed only at vCPU destruction
(PML-style), so there is no window where the MMU can write into freed
memory.
> [Severity: High]
> Does this early return violate the HDBSS requirement for eager page table
> splitting?
>
> The commit message states that enabling HDBSS requires disabling lazy split so
> that all block mappings are eagerly broken down before the buffer starts
> recording. However, if userspace utilizes KVM_DIRTY_LOG_INITIALLY_SET, this
> path returns early without calling kvm_mmu_split_memory_region().
>
> Since HDBSS was already globally enabled earlier in this function, could it
> now operate on block mappings instead of page-granularity tables, defeating
> the hardware expectation and corrupting the dirty log state?
>
Not an issue in the v5 design. With KVM_DIRTY_LOG_INITIALLY_SET,
userspace clears the bitmap via CLEAR ioctls; the clear path
write-protects, and v5's wrprotect strips DBM from blocks (->RO) so the
first write faults and triggers the split, while level-3 pages go WC
(DBM=1, S2AP_W=0) and are re-tracked by HDBSS. Since v5 supports lazy
split in the HDBSS flow, the early return on INITIALLY_SET does not
break dirty tracking.
> [Severity: Medium]
> Can a Time-of-Check to Time-of-Use (TOCTOU) race leak HDBSS buffers during
> vCPU destruction?
>
> Looking at kvm_arm_vcpu_destroy() in arch/arm64/kvm/reset.c:
>
> kvm_arm_vcpu_destroy() {
> ...
> if (vcpu->kvm->arch.enable_hdbss)
> kvm_arm_vcpu_free_hdbss(vcpu);
> ...
> }
>
> If KVM_CREATE_VCPU allocates an HDBSS buffer but kvm_arm_disable_hdbss_global()
> runs before the vCPU is added to online_vcpus, the global disable loop would
> miss the vCPU and clear enable_hdbss. When the VM is destroyed, the condition
> would evaluate to false, skipping the cleanup.
>
> Since kvm_arm_vcpu_free_hdbss() natively checks for the existence of the
> buffer, is the outer check against enable_hdbss necessary?
>
Addressed in v5. kvm_arm_vcpu_destroy() calls kvm_arm_vcpu_free_hdbss()
unconditionally (the function itself checks for buffer existence), and
the enable_hdbss conditional — along with the flag itself — no longer
exists.
> [Severity: High]
> Does the vCPU creation error path break pKVM memory ownership by missing a
> call to kvm_unshare_hyp()?
>
> In arch/arm64/kvm/arm.c, kvm_arch_vcpu_create() shares the vCPU struct memory
> with the hypervisor. If the new allocation fails, the function cleans up and
> returns the error:
>
> kvm_arch_vcpu_create() {
> ...
> if (vcpu->kvm->arch.enable_hdbss) {
> err = kvm_arm_vcpu_alloc_hdbss(vcpu, vcpu->kvm->arch.hdbss_order);
> if (err)
> kvm_vgic_vcpu_destroy(vcpu);
> }
>
> return err;
> }
>
> Could the memory for the vcpu struct be subsequently freed back to the host
> allocator while still marked as shared with the hypervisor, violating pKVM
> trust boundaries and triggering a hypervisor panic upon reuse?
>
Not applicable. HDBSS is VHE-only. The error path does not touch pKVM
ownership — it simply cleans up the local allocation. pKVM support is
explicitly out of scope and left as future work.
> [Severity: High]
> Does flushing the HDBSS buffer access memslots without SRCU protection?
>
> kvm_flush_hdbss_buffer() processes dirty pages by resolving GFNs via
> kvm_vcpu_mark_page_dirty():
>
> arch/arm64/kvm/dirty_bit.c:kvm_flush_hdbss_buffer() {
> ...
> kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
> ...
> }
>
> This internal function requires srcu_read_lock(&kvm->srcu) to safely access
> the KVM memslots array. However, kvm_flush_hdbss_buffer() is invoked from
> kvm_arch_vcpu_put() and check_vcpu_requests(), neither of which hold the SRCU
> read lock.
>
> Could this create a use-after-free risk when memslots are concurrently
> modified?
>
Valid point, addressed in v5. kvm_flush_hdbss_buffer() now holds
srcu_read_lock(&kvm->srcu) around the loop that resolves GFNs through
the memslots, and releases it before resetting HDBSSPROD_EL2.
> [Severity: Medium]
> Are immediate Context Synchronization Events (ISB) missing for control-plane
> system registers?
>
> The ARM64 subsystem rules require that every write to a control-plane system
> register must be followed by an isb() as the very next instruction.
>
> In arch/arm64/kvm/dirty_bit.c, a memory store executes between the write and
> the isb():
>
> kvm_flush_hdbss_buffer() {
> ...
> write_sysreg_s(0, SYS_HDBSSPROD_EL2);
> vcpu->arch.hdbss.hdbssprod_el2 = 0;
> isb();
> ...
> }
>
> Similarly, in arch/arm64/kvm/hyp/vhe/switch.c, two sysreg writes occur
> back-to-back without an intervening isb():
>
> __load_hdbss() {
> ...
> write_sysreg_s(vcpu->arch.hdbss.hdbssbr_el2, SYS_HDBSSBR_EL2);
> write_sysreg_s(vcpu->arch.hdbss.hdbssprod_el2, SYS_HDBSSPROD_EL2);
> ...
> }
>
> Could these patterns risk observing undefined pipeline state?
>
Duplicate of the ISB comments on patches 4/5.
Thanks!
Tian
next prev parent reply other threads:[~2026-08-31 12:23 UTC|newest]
Thread overview: 90+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-09 10:40 [PATCH v4 0/6] Support the FEAT_HDBSS introduced in Armv9.5 Tian Zheng
2026-07-09 10:40 ` [PATCH v4 1/6] KVM: arm64: Enable eager hugepage splitting if HDBSS is available Tian Zheng
2026-07-09 11:03 ` sashiko-bot
2026-08-31 8:52 ` Tian Zheng
2026-07-09 10:40 ` [PATCH v4 2/6] KVM: arm64: Add support for FEAT_HDBSS Tian Zheng
2026-07-09 11:00 ` sashiko-bot
2026-08-31 8:55 ` Tian Zheng
2026-07-09 10:40 ` [PATCH v4 3/6] KVM: arm64: Add auto DBM support for hardware dirty tracking Tian Zheng
2026-07-09 11:14 ` sashiko-bot
2026-08-31 9:14 ` Tian Zheng
2026-07-13 11:17 ` Leonardo Bras
2026-07-14 1:14 ` Tian Zheng
2026-07-14 7:23 ` Marc Zyngier
2026-07-14 7:44 ` Tian Zheng
2026-07-14 10:20 ` Leonardo Bras
2026-07-16 7:39 ` Oliver Upton
2026-07-17 3:58 ` Tian Zheng
2026-07-17 15:21 ` Leonardo Bras
2026-07-20 12:58 ` Leonardo Bras
2026-07-29 8:51 ` Tian Zheng
2026-07-29 15:16 ` Leonardo Bras
2026-08-03 1:33 ` Tian Zheng
2026-08-03 4:04 ` Tian Zheng
2026-08-03 10:21 ` Leonardo Bras
2026-08-03 13:57 ` Tian Zheng
2026-08-03 16:32 ` Leonardo Bras
2026-08-03 16:34 ` Leonardo Bras
2026-08-04 4:54 ` Tian Zheng
2026-08-04 11:10 ` Leonardo Bras
2026-08-05 3:41 ` Tian Zheng
2026-08-10 11:01 ` Leonardo Bras
2026-08-21 15:58 ` Leonardo Bras
2026-08-31 12:36 ` Tian Zheng
2026-09-01 17:22 ` Leonardo Bras
2026-09-07 3:17 ` Tian Zheng
2026-09-07 10:50 ` Leonardo Bras
2026-08-31 12:33 ` Tian Zheng
2026-08-05 3:43 ` Tian Zheng
2026-07-28 8:49 ` Tian Zheng
2026-07-09 10:40 ` [PATCH v4 4/6] KVM: arm64: Add HDBSS per-vCPU buffer management Tian Zheng
2026-07-09 11:15 ` sashiko-bot
2026-08-31 9:37 ` Tian Zheng
2026-07-13 13:39 ` Leonardo Bras
2026-07-14 7:15 ` Tian Zheng
2026-07-14 10:47 ` Leonardo Bras
2026-07-15 9:16 ` Tian Zheng
2026-07-15 14:28 ` Leonardo Bras
2026-07-17 4:06 ` Tian Zheng
2026-07-09 10:40 ` [PATCH v4 5/6] KVM: arm64: Add HDBSS fault handling and buffer flush Tian Zheng
2026-07-09 11:26 ` sashiko-bot
2026-08-31 13:57 ` Tian Zheng
2026-07-13 14:06 ` Leonardo Bras
2026-07-14 7:38 ` Tian Zheng
2026-07-14 10:50 ` Leonardo Bras
2026-07-14 13:27 ` Tian Zheng
2026-07-14 14:19 ` Leonardo Bras
2026-07-17 6:51 ` Tian Zheng
2026-07-17 15:44 ` Leonardo Bras
2026-07-21 8:53 ` Inochi Amaoto
2026-07-21 14:18 ` Leonardo Bras
2026-07-22 5:14 ` Inochi Amaoto
2026-07-22 11:04 ` Leonardo Bras
2026-07-23 1:17 ` Inochi Amaoto
2026-07-28 7:52 ` Tian Zheng
2026-07-29 15:30 ` Leonardo Bras
2026-08-03 3:15 ` Tian Zheng
2026-08-03 10:43 ` Leonardo Bras
2026-08-04 8:26 ` Tian Zheng
2026-08-03 3:22 ` Tian Zheng
2026-08-03 10:24 ` Leonardo Bras
2026-07-09 10:40 ` [PATCH v4 6/6] KVM: arm64: Add auto HDBSS enable/disable on dirty logging change Tian Zheng
2026-07-09 11:34 ` sashiko-bot
2026-08-31 12:23 ` Tian Zheng [this message]
2026-07-13 14:50 ` Leonardo Bras
2026-07-14 8:58 ` Tian Zheng
2026-07-14 11:16 ` Leonardo Bras
2026-07-14 14:33 ` Leonardo Bras
2026-07-16 8:37 ` Tian Zheng
2026-07-17 7:23 ` Tian Zheng
2026-07-17 15:50 ` Leonardo Bras
2026-07-16 7:15 ` Tian Zheng
2026-07-17 15:53 ` Leonardo Bras
2026-07-13 10:31 ` [PATCH v4 0/6] Support the FEAT_HDBSS introduced in Armv9.5 Leonardo Bras
2026-07-13 16:27 ` Leonardo Bras
2026-07-14 10:39 ` Tian Zheng
2026-07-14 11:20 ` Leonardo Bras
2026-07-14 13:29 ` Tian Zheng
2026-07-14 9:37 ` Tian Zheng
2026-07-14 10:19 ` Leonardo Bras
2026-07-14 13:34 ` Tian Zheng
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8a593c94-3fa5-4504-bbd3-4f9bbaf78264@huawei.com \
--to=zhengtian10@huawei.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=maz@kernel.org \
--cc=oupton@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox