[PATCH v2 3/3] KVM: arm64: Add fail-safe for refcounted pages in __pkvm_hyp_donate_host

Fuad Tabba tabba at google.com
Thu May 21 06:07:40 PDT 2026


On Thu, 21 May 2026 at 11:22, Vincent Donnefort <vdonnefort at google.com> wrote:
>
> A previous bug in __pkvm_init_vm error path showed that the hypervisor
> could leak refcounted pages, (i.e. losing access to a page while its
> refcount is still elevated). This poses a threat to the pKVM state
> machine.
>
> Address this by introducing a fail-safe in n __pkvm_hyp_donate_host.

Stray n.

> Transitions are not a hot path so added security is worth the extra
> check.
>
> Signed-off-by: Vincent Donnefort <vdonnefort at google.com>

Reviewed-by: Fuad Tabba <tabba at google.com>
Tested-by: Fuad Tabba <tabba at google.com>

Cheers,
/fuad



>
> diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
> index 42b0b648f32f..bb97d05b9b25 100644
> --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c
> +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
> @@ -855,6 +855,16 @@ static int __hyp_check_page_state_range(phys_addr_t phys, u64 size, enum pkvm_pa
>         return 0;
>  }
>
> +static int __hyp_check_page_count_range(phys_addr_t phys, u64 size)
> +{
> +       for_each_hyp_page(page, phys, size) {
> +               if (page->refcount)
> +                       return -EBUSY;
> +       }
> +
> +       return 0;
> +}
> +
>  static bool guest_pte_is_poisoned(kvm_pte_t pte)
>  {
>         if (kvm_pte_valid(pte))
> @@ -1053,7 +1063,6 @@ int __pkvm_guest_unshare_host(struct pkvm_hyp_vcpu *vcpu, u64 gfn)
>  int __pkvm_host_unshare_hyp(u64 pfn)
>  {
>         u64 phys = hyp_pfn_to_phys(pfn);
> -       u64 virt = (u64)__hyp_va(phys);
>         u64 size = PAGE_SIZE;
>         int ret;
>
> @@ -1066,10 +1075,9 @@ int __pkvm_host_unshare_hyp(u64 pfn)
>         ret = __hyp_check_page_state_range(phys, size, PKVM_PAGE_SHARED_BORROWED);
>         if (ret)
>                 goto unlock;
> -       if (hyp_page_count((void *)virt)) {
> -               ret = -EBUSY;
> +       ret = __hyp_check_page_count_range(phys, size);
> +       if (ret)
>                 goto unlock;
> -       }
>
>         __hyp_set_page_state_range(phys, size, PKVM_NOPAGE);
>         WARN_ON(__host_set_page_state_range(phys, size, PKVM_PAGE_OWNED));
> @@ -1132,6 +1140,10 @@ int __pkvm_hyp_donate_host(u64 pfn, u64 nr_pages)
>         if (ret)
>                 goto unlock;
>
> +       ret = __hyp_check_page_count_range(phys, size);
> +       if (ret)
> +               goto unlock;
> +
>         __hyp_set_page_state_range(phys, size, PKVM_NOPAGE);
>         WARN_ON(kvm_pgtable_hyp_unmap(&pkvm_pgtable, virt, size) != size);
>         WARN_ON(host_stage2_set_owner_locked(phys, size, PKVM_ID_HOST));
> --
> 2.54.0.746.g67dd491aae-goog
>



More information about the linux-arm-kernel mailing list