Re: [PATCH 02/14] KVM: arm64: Tear down unlinked stage-2 subtree after break-before-make

From: Oliver Upton
Date: Fri Sep 09 2022 - 06:05:39 EST


On Tue, Sep 06, 2022 at 02:35:47PM +0000, Quentin Perret wrote:
> Hi Oliver,
>
> On Tuesday 30 Aug 2022 at 19:41:20 (+0000), Oliver Upton wrote:
> > static int stage2_map_walk_table_pre(u64 addr, u64 end, u32 level,
> > kvm_pte_t *ptep,
> > struct stage2_map_data *data)
> > {
> > - if (data->anchor)
> > - return 0;
> > + struct kvm_pgtable_mm_ops *mm_ops = data->mm_ops;
> > + kvm_pte_t *childp = kvm_pte_follow(*ptep, mm_ops);
> > + struct kvm_pgtable *pgt = data->mmu->pgt;
> > + int ret;
> >
> > if (!stage2_leaf_mapping_allowed(addr, end, level, data))
> > return 0;
> >
> > - data->childp = kvm_pte_follow(*ptep, data->mm_ops);
> > kvm_clear_pte(ptep);
> >
> > /*
> > @@ -782,8 +786,13 @@ static int stage2_map_walk_table_pre(u64 addr, u64 end, u32 level,
> > * individually.
> > */
> > kvm_call_hyp(__kvm_tlb_flush_vmid, data->mmu);
> > - data->anchor = ptep;
> > - return 0;
> > +
> > + ret = stage2_map_walk_leaf(addr, end, level, ptep, data);
> > +
> > + mm_ops->put_page(ptep);
> > + mm_ops->free_removed_table(childp, level + 1, pgt);
>
> By the look of it, __kvm_pgtable_visit() has saved the table PTE on the
> stack prior to calling the TABLE_PRE callback, and it then uses the PTE
> from its stack and does kvm_pte_follow() to find the childp, and walks
> from there. Would that be a UAF now?

Sure would, I suppose the actual UAF is hidden by the use of RCU later
in the series. Nonetheless, I'm going to adopt David's suggestion of
just rereading the PTE which should tidy this up.

Thanks for catching this.

--
Best,
Oliver