From: Leonardo Bras <leo.bras@arm.com>
To: sashiko-reviews@lists.linux.dev
Cc: Leonardo Bras <leo.bras@arm.com>, Marc Zyngier <maz@kernel.org>,
Oliver Upton <oupton@kernel.org>,
kvmarm@lists.linux.dev, kvm@vger.kernel.org
Subject: Re: [PATCH v2 12/13] KVM: arm64: Add hardware-accelerated dirty-ring cleaning routine
Date: Mon, 29 Jun 2026 18:26:49 +0100 [thread overview]
Message-ID: <akKq2fvsUWPxuCHU@LeoBrasDK> (raw)
In-Reply-To: <20260629114921.2E78C1F000E9@smtp.kernel.org>
On Mon, Jun 29, 2026 at 11:49:20AM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
>
> New issues:
> - [Critical] Unvalidated userspace memory accesses in dirty ring clearing lead to host DoS and memory corruption.
> - [High] Missing TLB invalidation and DSB in dirty ring hardware path.
> - [High] Hardware buffer allocation lacks strict physical alignment guarantees.
>
> Pre-existing issues:
> - [High] Missing architecturally required context synchronization (ISB) after control register writes.
> - [High] Unsafe wfi() polling loop causes lost wakeups and CPU lockups.
> - [Medium] Hardware dirty log clearing erroneously falls back to software due to incorrect return value processing.
> --
>
> commit 9f463875fd0f7eddcaa7053b557d7a2cc21e83c1
> Author: Leonardo Bras <leo.bras@arm.com>
>
> KVM: arm64: Add hardware-accelerated dirty-ring cleaning routine
>
> This commit implements an arm64 version of kvm_arch_dirty_ring_clear using
> FEAT_HACDBS. It translates dirty-ring entries into HDBSS entries and uses
> the hardware mechanism to mark writable-dirty pages as clean. Invalid
> entries are then cleared, falling back to software cleaning on error.
>
> > diff --git a/arch/arm64/kvm/dirty_bit.c b/arch/arm64/kvm/dirty_bit.c
> > --- a/arch/arm64/kvm/dirty_bit.c
> > +++ b/arch/arm64/kvm/dirty_bit.c
> [ ... ]
> > static int dirty_bit_clear(struct kvm *kvm, u64 *hw_entries, int size)
> > {
> > u64 hcr_el2;
> > int ret;
> >
> > preempt_disable();
> >
> > hcr_el2 = read_sysreg(HCR_EL2);
> > write_sysreg(hcr_el2 | HCR_EL2_VM, HCR_EL2);
> > __load_stage2(&kvm->arch.mmu);
>
> [Severity: High]
> This is a pre-existing issue, but does this missing ISB after control register
> writes expose the pipeline to undefined architectural states?
>
> Writing to HCR_EL2 requires an immediate context synchronization event.
> Executing __load_stage2 immediately after without an isb means it might
> operate under a stale configuration.
See prev patches
>
> >
> > hacdbs_start(hw_entries, size);
> >
> > do {
> > wfi();
> > } while (this_cpu_read(hacdbs_pcp.status) == HACDBS_RUNNING);
>
> [Severity: High]
> This is a pre-existing issue, but can this unprotected wfi wait loop cause
> a lost wakeup and an indefinite CPU stall?
>
> Because local interrupts are not masked around this check and wait, a timely
> interrupt could satisfy the condition prematurely before wfi executes.
>
iden
> [ ... ]
> > if (idx != 0) {
> > ret = dirty_bit_clear(kvm, hw_entries, idx);
> > *flush = *flush || ret > 0;
> > }
> > out_err:
> > if (unlikely(ret != idx)) {
>
> [Severity: Medium]
> This is a pre-existing issue, but does this logic incorrectly evaluate a
> successful batch outcome as an error?
>
> If the loop finishes exactly on a batch boundary, idx is reset to 0, but ret
> holds the success count of the previous batch. This causes the mismatch check
> to evaluate to true, forcing a -EAGAIN return and triggering an unnecessary
> software fallback.
>
iden
> [ ... ]
> > @@ -256,6 +256,72 @@ int __kvm_arch_dirty_log_clear(struct kvm *kvm,
> > return ret;
> > }
> >
> > +int __kvm_arch_dirty_ring_clear(struct kvm *kvm, struct kvm_dirty_ring *ring,
> > + int *nr_entries_reset)
> > +{
> > + u64 *hw_entries;
> > + u64 slot_offset = 0;
> > + u64 ttwl;
> > + int i, ret;
> > + u32 slot = -1;
> > +
> > + if (signal_pending(current))
> > + return -EINTR;
> > +
> > + ttwl = HDBSS_ENTRY_TTWL(KVM_PGTABLE_LAST_LEVEL);
> > +
> > + hw_entries = kmalloc(max(ring->size * sizeof(u64), PAGE_SIZE), GFP_KERNEL);
>
> [Severity: High]
> Does this kmalloc call lack the strict physical alignment guarantees required
> by the hardware accelerator?
>
> Since kmalloc does not guarantee natural physical alignment for large buffers,
> is it possible for physical address truncation to occur? This could cause the
> hardware accelerator to parse unaligned memory and corrupt arbitrary page DBM
> bits.
I recall it had size-alignmen guarantees. Largest buffer size should be
64k x 8B, so it should be ok.
>
> > + if (!hw_entries)
> > + return -ENOMEM;
> > +
> > + for (i = 0; i < ring->size; i++) {
> > + struct kvm_dirty_gfn *entry;
> > + gfn_t gfn;
> > +
> > + entry = &ring->dirty_gfns[(ring->reset_index + i) &
> > + (ring->size - 1)];
> > +
> > + if (!kvm_dirty_gfn_harvested(entry))
> > + break;
> > +
> > + if (entry->slot != slot) {
> > + struct kvm_memory_slot *memslot;
> > +
> > + memslot = kvm_dirty_ring_get_memslot(kvm, entry->slot);
> > + slot = entry->slot;
> > + slot_offset = memslot->base_gfn;
>
> [Severity: Critical]
> Can an invalid, user-provided entry->slot lead to a NULL pointer dereference
> here?
>
> The memslot pointer is dereferenced directly to read base_gfn without a NULL
> check.
>
> > + }
> > +
> > + gfn = slot_offset + entry->offset;
>
Correct. I have to verify the return value of get_memslot before using it.
Will do in v3
> [Severity: Critical]
> Is entry->offset validated against the memslot bounds?
>
> Using an unvalidated user-provided offset here allows arbitrary Stage-2 GPA
> computation. This could enable Stage-2 memory corruption or privilege
> escalation.
Correct. Will verify the offset against memslot size before this.
Will be done in v3.
>
> > +
> > + hw_entries[i] = (gfn_to_gpa(gfn) & HDBSS_ENTRY_IPA) |
> > + ttwl | HDBSS_ENTRY_VALID;
> > + }
> > +
> > + ret = dirty_bit_clear(kvm, hw_entries, i);
>
> [Severity: High]
> Does this path miss an architecturally required TLB invalidation and DSB?
>
> dirty_bit_clear relies on the caller to handle the TLBI (as noted in its
> internal comments for the log clearing path), but this ring clearing routine
> appears to jump directly to invalidating the entries and returning.
There is a dsb() and then a TLBI before returning to guest.
>
> This could leave stale writable TLB entries in the guest.
>
> > +
> > + /* Set as invalid all successfully cleaned entries */
> > + for (int j = 0; j < ret; j++) {
> [ ... ]
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260629111820.1873540-1-leo.bras@arm.com?part=12
Thanks!
Leo
next prev parent reply other threads:[~2026-06-29 17:26 UTC|newest]
Thread overview: 47+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-29 11:17 [PATCH v2 00/13] KVM Dirty-bit cleaning hw accelerator (HACDBS) Leonardo Bras
2026-06-29 11:17 ` [PATCH v2 01/13] KVM: arm64: HDBSS bits Leonardo Bras
2026-06-29 11:34 ` sashiko-bot
2026-06-29 12:57 ` Leonardo Bras
2026-06-29 11:17 ` [PATCH v2 02/13] KVM: arm64: Enable eager hugepage splitting if HDBSS is available Leonardo Bras
2026-06-29 11:36 ` sashiko-bot
2026-06-29 14:47 ` Leonardo Bras
2026-06-29 17:06 ` Oliver Upton
2026-06-30 12:58 ` Leonardo Bras
2026-06-30 15:44 ` Oliver Upton
2026-06-30 17:09 ` Leonardo Bras
2026-06-30 18:43 ` Oliver Upton
2026-06-29 11:17 ` [PATCH v2 03/13] arm64/cpufeature: Add system-wide FEAT_HACDBS detection Leonardo Bras
2026-06-29 11:17 ` [PATCH v2 04/13] arm64/sysreg: Add HACDBS consumer and base registers Leonardo Bras
2026-06-29 11:17 ` [PATCH v2 05/13] KVM: arm64: Detect (via ACPI) and initialize HACDBSIRQ Leonardo Bras
2026-06-29 11:32 ` sashiko-bot
2026-06-29 15:43 ` Leonardo Bras
2026-06-29 16:52 ` Vladimir Murzin
2026-06-30 14:52 ` Leonardo Bras
2026-06-29 17:22 ` Oliver Upton
2026-06-30 14:50 ` Leonardo Bras
2026-06-30 16:03 ` Oliver Upton
2026-06-30 17:19 ` Leonardo Bras
2026-06-29 11:17 ` [PATCH v2 06/13] KVM: arm64: dirty_bit: Add base FEAT_HACDBS cleaning routine Leonardo Bras
2026-06-29 11:29 ` sashiko-bot
2026-06-29 15:54 ` Leonardo Bras
2026-06-29 17:36 ` Oliver Upton
2026-06-30 14:59 ` Leonardo Bras
2026-06-30 19:06 ` Oliver Upton
2026-06-29 11:17 ` [PATCH v2 07/13] kvm: Add arch-generic interface for hw-accelerated dirty-bitmap cleaning Leonardo Bras
2026-06-29 11:38 ` sashiko-bot
2026-06-29 16:07 ` Leonardo Bras
2026-06-29 11:17 ` [PATCH v2 08/13] KVM: arm64: Add hardware-accelerated dirty-bitmap cleaning routine Leonardo Bras
2026-06-29 11:45 ` sashiko-bot
2026-06-29 16:49 ` Leonardo Bras
2026-06-29 11:17 ` [PATCH v2 09/13] KVM: arm64: Dirty-bitmap: avoid splitting previously split blocks Leonardo Bras
2026-06-29 11:39 ` sashiko-bot
2026-06-29 17:07 ` Leonardo Bras
2026-06-29 11:17 ` [PATCH v2 10/13] kvm/dirty_ring: Introduce get_memslot and move helpers to header Leonardo Bras
2026-06-29 11:17 ` [PATCH v2 11/13] kvm/dirty_ring: Add arch-generic interface for hw-accelerated dirty-ring cleaning Leonardo Bras
2026-06-29 11:49 ` sashiko-bot
2026-06-29 17:09 ` Leonardo Bras
2026-06-29 11:18 ` [PATCH v2 12/13] KVM: arm64: Add hardware-accelerated dirty-ring cleaning routine Leonardo Bras
2026-06-29 11:49 ` sashiko-bot
2026-06-29 17:26 ` Leonardo Bras [this message]
2026-06-29 11:18 ` [PATCH v2 13/13] KVM: arm64: Enable KVM_HW_DIRTY_BIT Leonardo Bras
2026-06-29 11:52 ` sashiko-bot
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=akKq2fvsUWPxuCHU@LeoBrasDK \
--to=leo.bras@arm.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