All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Alexandru Elisei" <alexandru.elisei@arm.com>
Cc: "Marc Zyngier" <maz@kernel.org>,
	kvmarm@lists.linux.dev, linux-perf-users@vger.kernel.org,
	"Oliver Upton" <oupton@kernel.org>
Subject: Re: [RFC PATCH v7 27/28] KVM: arm64: Handle dirty page logging when SPE feature is set
Date: Thu, 03 Sep 2026 17:06:12 +0000	[thread overview]
Message-ID: <20260903170613.671FC1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260903160623.315525-28-alexandru.elisei@arm.com>

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Memory Protection Bypass / Privilege Escalation via Unconditional Stage-2 Write-Enable
- [High] Logic Error and EL2 Hypercall Argument Corruption due to flawed `nr_pages` calculation
- [High] Logical Inconsistency / State Desynchronization causing missed VCPU kicks and unexpected guest exits
- [Medium] Kernel preemption bug via `smp_processor_id()` in a preemptible context
--

commit 45c89e608abbd3e8f9c8b944b7e7d74478d5db12
Author: Alexandru Elisei <alexandru.elisei@arm.com>
Subject: KVM: arm64: Handle dirty page logging when SPE feature is set

This commit aims to avoid profiling blackout windows by preventing VCPU
execution when the SPE buffer is enabled and dirty page logging is active.
It introduces dirty logging synchronization constraints and automatic guest
exits for the KVM/ARM64 SPE implementation.

> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index 7c7d0616db53a..73f321b3ed2dc 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -1172,6 +1172,15 @@ static int kvm_vcpu_suspend(struct kvm_vcpu *vcpu)
>  	return 1;
>  }
>  
> +static void kvm_vcpu_prepare_exit_fail_entry(struct kvm_vcpu *vcpu, u64 reason)
> +{
> +	struct kvm_run *run = vcpu->run;
> +
> +	run->exit_reason = KVM_EXIT_FAIL_ENTRY;
> +	run->fail_entry.hardware_entry_failure_reason = reason;
> +	run->fail_entry.cpu = smp_processor_id();

[Severity: Medium]
Is it safe to use smp_processor_id() here? This function is newly invoked by
check_vcpu_requests() when handling KVM_REQ_SPE_EXIT_DIRTY_LOGGING. Because
check_vcpu_requests() executes in the KVM run loop before preempt_disable()
is called, the context remains preemptible. This will trigger a kernel
warning if CONFIG_DEBUG_PREEMPT is enabled, and records an unreliable CPU ID
since the thread can migrate immediately afterward.

[ ... ]
> diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
> index b74dd5ce1efd3..07e43f607eae7 100644
> --- a/arch/arm64/kvm/hyp/pgtable.c
> +++ b/arch/arm64/kvm/hyp/pgtable.c
> @@ -1293,6 +1293,14 @@ int kvm_pgtable_stage2_wrprotect(struct kvm_pgtable *pgt, u64 addr, u64 size)
>  					KVM_PGTABLE_WALK_IGNORE_EAGAIN);
>  }
>  
> +int kvm_pgtable_stage2_write_enable(struct kvm_pgtable *pgt, u64 addr, u64 size)
> +{
> +	return stage2_update_leaf_attrs(pgt, addr, size,
> +					KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W, 0,
> +					NULL, NULL,
> +					KVM_PGTABLE_WALK_IGNORE_EAGAIN);
> +}

[Severity: High]
Can this lead to a memory protection bypass? By unconditionally adding the
KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W bit to all valid leaf PTEs, this doesn't
appear to validate if the underlying host memory mapping actually permits
writes. If a guest reads unallocated shared memory while dirty logging is on,
KVM maps the host's zero page as read-only at stage 2. Once dirty logging is
disabled, this blindly grants write access to it.

[ ... ]
> diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
> index 8e4c6e4bec123..5ba2fa8010cc9 100644
> --- a/arch/arm64/kvm/pkvm.c
> +++ b/arch/arm64/kvm/pkvm.c
> @@ -488,6 +488,33 @@ int pkvm_pgtable_stage2_unmap(struct kvm_pgtable *pgt, u64 addr, u64 size)
>  	return __pkvm_pgtable_stage2_unshare(pgt, addr, addr + size);
>  }
>  
> +int pkvm_pgtable_stage2_write_enable(struct kvm_pgtable *pgt, u64 addr, u64 size)
> +{
[ ... ]
> +	lockdep_assert_held(&kvm->mmu_lock);
> +	for_each_mapping_in_range_safe(pgt, addr, addr + size, mapping) {
> +		gfn = max(addr >> PAGE_SHIFT, mapping->gfn);
> +		nr_pages = min_t(u64, end_gfn - gfn, mapping->nr_pages);

[Severity: High]
Does this calculation span past the end of the mapping? If the requested
address starts in the middle of an existing mapping, gfn is offset from
mapping->gfn. Because the offset isn't subtracted from mapping->nr_pages,
the EL1 host passes an out-of-bounds nr_pages to the EL2 hypervisor. This
could cause the hypercall to fail or inadvertently write-enable pages beyond
the intended mapping.

> +		ret = kvm_call_hyp_nvhe(__pkvm_host_write_enable_guest, handle, gfn,
> +					nr_pages);
> +		if (WARN_ON(ret))
> +			break;
> +	}
> +
> +	return ret;
> +}

[ ... ]
> diff --git a/arch/arm64/kvm/spe.c b/arch/arm64/kvm/spe.c
> index e5f3d0dea7c54..f3310465f40eb 100644
> --- a/arch/arm64/kvm/spe.c
> +++ b/arch/arm64/kvm/spe.c
[ ... ]
> +void kvm_spe_add_dirty_logging(struct kvm *kvm, const struct kvm_memory_slot *slot)
> +{
> +	struct kvm_vcpu *vcpu;
> +	unsigned long i;
> +
> +	lockdep_assert_held(&kvm->slots_lock);
> +
> +	/*
> +	 * No point in handling a regular memslot, because they cannot guarantee
> +	 * that memory remains mapped at stage 2.
> +	 *
> +	 * Memory described by a read-only memslot is always read-only, so SPE
> +	 * cannot write to it anyway.
> +	 */
> +	if (!kvm_slot_has_gmem(slot) || (slot->flags & KVM_MEM_READONLY))
> +		return;

[Severity: High]
Does this cause unexpected guest exits and missed VCPU kicks for regular
memslots? Here in kvm_spe_add_dirty_logging(), regular memslots are skipped,
so running VCPUs aren't kicked when dirty logging starts.

> +
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		if (!vcpu_has_spe(vcpu))
> +			continue;
> +		kvm_make_request(KVM_REQ_SPE_HANDLE_DIRTY_LOGGING, vcpu);
> +		if (vcpu_has_run_once(vcpu))
> +			__kvm_vcpu_kick(vcpu, true);
> +	}
> +}
> +
> +void kvm_spe_remove_dirty_logging(struct kvm *kvm, const struct kvm_memory_slot *slot)
> +{
> +	phys_addr_t start, end;
> +	struct kvm_vcpu *vcpu;
> +	unsigned long i;
> +
> +	lockdep_assert_held(&kvm->slots_lock);
> +
> +	if (!kvm_slot_has_gmem(slot) || (slot->flags & KVM_MEM_READONLY))
> +		return;
> +
> +	kvm_for_each_vcpu(i, vcpu, kvm) {
> +		/*
> +		 * Write-enabling an entire memslot can be expensive, do it only
> +		 * if the VM has SPE.
> +		 */
> +		if (vcpu_has_spe(vcpu)) {
> +			start = slot->base_gfn << PAGE_SHIFT;
> +			end = (slot->base_gfn + slot->npages) << PAGE_SHIFT;
> +
> +			write_lock(&kvm->mmu_lock);
> +			kvm_stage2_write_enable_range(&kvm->arch.mmu, start, end);

[Severity: High]
Does this blindly write-enable the entire shared stage-2 memslot? Combined
with the unconditional KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W addition in
kvm_pgtable_stage2_write_enable(), this allows a malicious guest to gain write
access to read-only host memory (like the global shared zero page) if it
was previously mapped as read-only.

> +			write_unlock(&kvm->mmu_lock);
> +			kvm_flush_remote_tlbs_memslot(kvm, slot);
> +			return;
> +		}
> +	}
> +}
> +
> +static bool kvm_spe_should_exit_dirty_logging(struct kvm_vcpu *vcpu)
> +{
> +	struct kvm *kvm = vcpu->kvm;
> +	u64 pmblimitr, pmbsr;
> +
> +	if (!atomic_read(&kvm->nr_memslots_dirty_logging))
> +		return false;

[Severity: High]
Because regular memslots were skipped in kvm_spe_add_dirty_logging(), they
weren't protected. However, this check relies on the global
nr_memslots_dirty_logging counter, which increments for all memslots.
Could this mismatch cause unexpected guest exits when a VM enables standard
dirty logging (e.g., VGA framebuffers) while utilizing SPE?

> +
> +	pmblimitr = __vcpu_sys_reg(vcpu, PMBLIMITR_EL1);
> +	pmbsr = __vcpu_sys_reg(vcpu, PMBSR_EL1);
> +
> +	return FIELD_GET(PMBLIMITR_EL1_E, pmblimitr) && !FIELD_GET(PMBSR_EL1_S, pmbsr);
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260903160623.315525-1-alexandru.elisei@arm.com?part=27

  reply	other threads:[~2026-09-03 17:06 UTC|newest]

Thread overview: 66+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-03 16:05 [RFC PATCH v7 00/28] KVM: arm64: Add Statistical Profiling Extension (SPE) support Alexandru Elisei
2026-09-03 16:05 ` [RFC PATCH v7 01/28] arm64/sysreg: Add the nVM field to PMBLIMITR_EL1 Alexandru Elisei
2026-09-03 16:14   ` sashiko-bot
2026-09-03 16:05 ` [RFC PATCH v7 02/28] arm64/sysreg: Define MDCR_EL2.E2PB values Alexandru Elisei
2026-09-03 16:12   ` sashiko-bot
2026-09-03 16:05 ` [RFC PATCH v7 03/28] KVM: arm64: Add CONFIG_KVM_ARM_SPE Kconfig option Alexandru Elisei
2026-09-03 16:13   ` sashiko-bot
2026-09-03 16:05 ` [RFC PATCH v7 04/28] perf: arm_spe_pmu: Move struct arm_spe_pmu to a separate header file Alexandru Elisei
2026-09-03 16:11   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 05/28] perf: arm_spe_pmu: Add PMBIDR_EL1 and PMSIDR_EL1 to struct arm_spe_pmu Alexandru Elisei
2026-09-03 16:11   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 06/28] KVM: arm64: Add KVM_CAP_ARM_SPE capability Alexandru Elisei
2026-09-03 16:15   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 07/28] KVM: arm64: Add KVM_ARM_VCPU_SPE VCPU feature Alexandru Elisei
2026-09-03 16:21   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 08/28] HACK! KVM: arm64: Disable SPE virtualization if protected KVM is enabled Alexandru Elisei
2026-09-03 16:21   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 09/28] HACK! KVM: arm64: Enable SPE virtualization only in VHE mode Alexandru Elisei
2026-09-03 16:15   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 10/28] HACK! KVM: arm64: Disable SPE virtualization if nested virt is enabled Alexandru Elisei
2026-09-03 16:20   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 11/28] KVM: arm64: Add a new VCPU device control group for SPE Alexandru Elisei
2026-09-03 16:22   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 12/28] KVM: arm64: Add SPE VCPU device attribute to set the interrupt number Alexandru Elisei
2026-09-03 16:27   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 13/28] KVM: arm64: Add SPE VCPU device attribute to set the SPE device Alexandru Elisei
2026-09-03 16:39   ` sashiko-bot
2026-09-04  9:32     ` Alexandru Elisei
2026-09-03 16:06 ` [RFC PATCH v7 14/28] KVM: arm64: Add SPE VCPU device attribute to initialize SPE Alexandru Elisei
2026-09-03 16:28   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 15/28] KVM: arm64: Use PMSVer from the assigned SPE instance Alexandru Elisei
2026-09-03 16:41   ` sashiko-bot
2026-09-04 10:26     ` Alexandru Elisei
2026-09-03 16:06 ` [RFC PATCH v7 16/28] KVM: arm64: Add SPE system registers to VCPU context Alexandru Elisei
2026-09-03 16:32   ` sashiko-bot
2026-09-04 10:28     ` Alexandru Elisei
2026-09-03 16:06 ` [RFC PATCH v7 17/28] KVM: arm64: Apply a RES0 mask to PMBLIMITR_EL1 writes Alexandru Elisei
2026-09-03 16:37   ` sashiko-bot
2026-09-04 10:41     ` Alexandru Elisei
2026-09-03 16:06 ` [RFC PATCH v7 18/28] KVM: arm64: config: Use functions from spe.c to test FEAT_SPE_{FnE,FDS} Alexandru Elisei
2026-09-03 16:40   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 19/28] KVM: arm64: VHE: Context switch SPE state Alexandru Elisei
2026-09-03 16:43   ` sashiko-bot
2026-09-04 11:35     ` Alexandru Elisei
2026-09-03 16:06 ` [RFC PATCH v7 20/28] KVM: arm64: Allow guest SPE physical timestamps only if kernel allows it Alexandru Elisei
2026-09-03 16:48   ` sashiko-bot
2026-09-04 13:45     ` Alexandru Elisei
2026-09-03 16:06 ` [RFC PATCH v7 21/28] KVM: arm64: Handle SPE maintenance interrupts Alexandru Elisei
2026-09-03 16:58   ` sashiko-bot
2026-09-04 14:04     ` Alexandru Elisei
2026-09-03 16:06 ` [RFC PATCH v7 22/28] arm64: errata: Disable SPE in KVM Alexandru Elisei
2026-09-03 16:50   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 23/28] KVM: arm64: Add kvm-arm.ignore_spe_errata kernel parameter Alexandru Elisei
2026-09-03 16:46   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 24/28] arm64: errata: Don't enable guest buffer if misprogrammed Alexandru Elisei
2026-09-03 17:00   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 25/28] KVM: arm64: at: Use callback for reading descriptor Alexandru Elisei
2026-09-03 16:51   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 26/28] KVM: arm64: Map memory on a SPE stage 2 fault Alexandru Elisei
2026-09-03 17:08   ` sashiko-bot
2026-09-03 16:06 ` [RFC PATCH v7 27/28] KVM: arm64: Handle dirty page logging when SPE feature is set Alexandru Elisei
2026-09-03 17:06   ` sashiko-bot [this message]
2026-09-04 14:41     ` Alexandru Elisei
2026-09-03 16:06 ` [RFC PATCH v7 28/28] KVM: arm64: Allow the creation of a SPE enabled VM Alexandru Elisei
2026-09-03 16:59   ` sashiko-bot
2026-09-04 14:09     ` Alexandru Elisei

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=20260903170613.671FC1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=alexandru.elisei@arm.com \
    --cc=kvmarm@lists.linux.dev \
    --cc=linux-perf-users@vger.kernel.org \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.