* [PATCH] KVM: arm64: Only free fully unmapped tables in stage2_free_walker()
@ 2025-09-04 10:17 Oliver Upton
2025-09-05 7:31 ` Marc Zyngier
2025-09-05 9:41 ` Oliver Upton
0 siblings, 2 replies; 4+ messages in thread
From: Oliver Upton @ 2025-09-04 10:17 UTC (permalink / raw)
To: kvmarm
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Raghavendra Rao Ananta, Oliver Upton
syzkaller caught a terminal use-after-free in the free walker resulting
from a premature put_page() on a partially unmapped page table.
Previously KVM performed a single walk covering the entire IPA space,
but now that the range of the walk is up to KVM_PGTABLE_MIN_BLOCK_LEVEL
worth of memory it is possibly to only partially free a table.
Fix it by only dropping the table reference if the page count of the
table is 1 (i.e. no longer contains valid PTEs).
Fixes: e9abe311f356 ("KVM: arm64: Reschedule as needed when destroying the stage-2 page-tables")
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
---
arch/arm64/kvm/hyp/pgtable.c | 33 +++++++++++++++++++++++++++------
1 file changed, 27 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index c36f282a175d..50b8fb7cc59f 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -1535,20 +1535,41 @@ size_t kvm_pgtable_stage2_pgd_size(u64 vtcr)
return kvm_pgd_pages(ia_bits, start_level) * PAGE_SIZE;
}
-static int stage2_free_walker(const struct kvm_pgtable_visit_ctx *ctx,
- enum kvm_pgtable_walk_flags visit)
+static int stage2_free_leaf(const struct kvm_pgtable_visit_ctx *ctx)
{
struct kvm_pgtable_mm_ops *mm_ops = ctx->mm_ops;
- if (!stage2_pte_is_counted(ctx->old))
+ mm_ops->put_page(ctx->ptep);
+ return 0;
+}
+
+static int stage2_free_table_post(const struct kvm_pgtable_visit_ctx *ctx)
+{
+ struct kvm_pgtable_mm_ops *mm_ops = ctx->mm_ops;
+ kvm_pte_t *childp = kvm_pte_follow(ctx->old, mm_ops);
+
+ if (mm_ops->page_count(childp) != 1)
return 0;
mm_ops->put_page(ctx->ptep);
+ mm_ops->put_page(childp);
+ return 0;
+}
- if (kvm_pte_table(ctx->old, ctx->level))
- mm_ops->put_page(kvm_pte_follow(ctx->old, mm_ops));
+static int stage2_free_walker(const struct kvm_pgtable_visit_ctx *ctx,
+ enum kvm_pgtable_walk_flags visit)
+{
+ if (!stage2_pte_is_counted(ctx->old))
+ return 0;
- return 0;
+ switch (visit) {
+ case KVM_PGTABLE_WALK_LEAF:
+ return stage2_free_leaf(ctx);
+ case KVM_PGTABLE_WALK_TABLE_POST:
+ return stage2_free_table_post(ctx);
+ default:
+ return -EINVAL;
+ }
}
void kvm_pgtable_stage2_destroy_range(struct kvm_pgtable *pgt,
--
2.39.5
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] KVM: arm64: Only free fully unmapped tables in stage2_free_walker()
2025-09-04 10:17 [PATCH] KVM: arm64: Only free fully unmapped tables in stage2_free_walker() Oliver Upton
@ 2025-09-05 7:31 ` Marc Zyngier
2025-09-05 7:37 ` Alexander Potapenko
2025-09-05 9:41 ` Oliver Upton
1 sibling, 1 reply; 4+ messages in thread
From: Marc Zyngier @ 2025-09-05 7:31 UTC (permalink / raw)
To: Oliver Upton
Cc: kvmarm, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Raghavendra Rao Ananta
On Thu, 04 Sep 2025 11:17:46 +0100,
Oliver Upton <oliver.upton@linux.dev> wrote:
>
> syzkaller caught a terminal use-after-free in the free walker resulting
> from a premature put_page() on a partially unmapped page table.
> Previously KVM performed a single walk covering the entire IPA space,
> but now that the range of the walk is up to KVM_PGTABLE_MIN_BLOCK_LEVEL
> worth of memory it is possibly to only partially free a table.
>
> Fix it by only dropping the table reference if the page count of the
> table is 1 (i.e. no longer contains valid PTEs).
>
> Fixes: e9abe311f356 ("KVM: arm64: Reschedule as needed when destroying the stage-2 page-tables")
> Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
Reviewed-by: Marc Zyngier <maz@kernel.org>
M.
--
Jazz isn't dead. It just smells funny.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] KVM: arm64: Only free fully unmapped tables in stage2_free_walker()
2025-09-05 7:31 ` Marc Zyngier
@ 2025-09-05 7:37 ` Alexander Potapenko
0 siblings, 0 replies; 4+ messages in thread
From: Alexander Potapenko @ 2025-09-05 7:37 UTC (permalink / raw)
To: Marc Zyngier
Cc: Oliver Upton, kvmarm, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Raghavendra Rao Ananta
On Fri, Sep 5, 2025 at 9:32 AM Marc Zyngier <maz@kernel.org> wrote:
>
> On Thu, 04 Sep 2025 11:17:46 +0100,
> Oliver Upton <oliver.upton@linux.dev> wrote:
> >
> > syzkaller caught a terminal use-after-free in the free walker resulting
> > from a premature put_page() on a partially unmapped page table.
> > Previously KVM performed a single walk covering the entire IPA space,
> > but now that the range of the walk is up to KVM_PGTABLE_MIN_BLOCK_LEVEL
> > worth of memory it is possibly to only partially free a table.
> >
> > Fix it by only dropping the table reference if the page count of the
> > table is 1 (i.e. no longer contains valid PTEs).
> >
> > Fixes: e9abe311f356 ("KVM: arm64: Reschedule as needed when destroying the stage-2 page-tables")
> > Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
>
> Reviewed-by: Marc Zyngier <maz@kernel.org>
Tested-by: Alexander Potapenko <glider@google.com>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] KVM: arm64: Only free fully unmapped tables in stage2_free_walker()
2025-09-04 10:17 [PATCH] KVM: arm64: Only free fully unmapped tables in stage2_free_walker() Oliver Upton
2025-09-05 7:31 ` Marc Zyngier
@ 2025-09-05 9:41 ` Oliver Upton
1 sibling, 0 replies; 4+ messages in thread
From: Oliver Upton @ 2025-09-05 9:41 UTC (permalink / raw)
To: kvmarm, Oliver Upton
Cc: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
Raghavendra Rao Ananta
On Thu, 04 Sep 2025 03:17:46 -0700, Oliver Upton wrote:
> syzkaller caught a terminal use-after-free in the free walker resulting
> from a premature put_page() on a partially unmapped page table.
> Previously KVM performed a single walk covering the entire IPA space,
> but now that the range of the walk is up to KVM_PGTABLE_MIN_BLOCK_LEVEL
> worth of memory it is possibly to only partially free a table.
>
> Fix it by only dropping the table reference if the page count of the
> table is 1 (i.e. no longer contains valid PTEs).
>
> [...]
Applied to fixes, thanks!
[1/1] KVM: arm64: Only free fully unmapped tables in stage2_free_walker()
https://git.kernel.org/kvmarm/kvmarm/c/3095864771d8
--
Best,
Oliver
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-09-05 9:41 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-04 10:17 [PATCH] KVM: arm64: Only free fully unmapped tables in stage2_free_walker() Oliver Upton
2025-09-05 7:31 ` Marc Zyngier
2025-09-05 7:37 ` Alexander Potapenko
2025-09-05 9:41 ` Oliver Upton
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.