Re: [PATCH RFC] KVM: pfncache: Check gpc->active before sanity checking GPA and HVA

Aleksandr Nogikh <[email protected]> Wed, 29 Jul 2026 15:21:35 +0200
Newsgroups dev.linux.lists.syzbot
Message-ID <CANp29Y5FVs_k4fjVWxFNUcAkX-xvg3ZJR1eysYttfe1A-qReBQ@mail.gmail.com>
Based off the discussion in
https://lore.kernel.org/all/[email protected]/T/

Moving the `!gpc->active` check into `__kvm_gpc_refresh()` is too late
because `kvm_gpc_refresh()` calls `kvm_gpc_is_valid_len(gpc->gpa,
gpc->uhva, len)` *before* calling `__kvm_gpc_refresh()`.

On an inactive cache (`gpc->gpa =3D=3D INVALID_GPA` and `gpc->uhva =3D=3D
KVM_HVA_ERR_BAD`), `kvm_gpc_is_valid_len()` will still end up running
`offset_in_page(uhva)` on an invalid HVA.

`if (!gpc->active)` needs to be checked at the start of
`kvm_gpc_refresh()` right after acquiring `gpc->refresh_lock`, before
`kvm_gpc_is_valid_len()` is called.

On Wed, Jul 29, 2026 at 3:18=E2=80=AFPM 'syzbot' via
syzkaller-upstream-moderation
<[email protected]> wrote:
>
> When attempting to refresh a gfn_to_pfn_cache (gpc) that has never been
> activated, KVM triggers a sanity-check warning in __kvm_gpc_refresh(). Th=
is
> occurs because an inactive cache naturally has both its GPA and HVA
> initialized to error values, which violates the condition that exactly on=
e
> of them must be valid.
>
> This can be triggered via the KVM_XEN_HVM_EVTCHN_SEND ioctl. If the guest
> has not yet set up the shared info page, the shinfo_cache is inactive.
> Attempting to deliver the event returns -EWOULDBLOCK, prompting KVM to
> attempt a refresh of the cache, leading to the warning:
>
> ------------[ cut here ]------------
> kvm_is_error_gpa(gpa) =3D=3D kvm_is_error_hva(uhva)
> WARNING: arch/x86/kvm/../../../virt/kvm/pfncache.c:267 at
> __kvm_gpc_refresh+0x1510/0x1710 virt/kvm/pfncache.c:267
> ...
> Call Trace:
>  <TASK>
>  kvm_gpc_refresh+0xe1/0x110 virt/kvm/pfncache.c:382
>  kvm_xen_set_evtchn+0x14f/0x220 arch/x86/kvm/xen.c:1945
>  kvm_xen_hvm_evtchn_send+0x120/0x1e0 arch/x86/kvm/xen.c:2036
>  kvm_arch_vm_ioctl+0xfad/0x1a10 arch/x86/kvm/x86.c:7523
>  kvm_vm_ioctl+0x8f7/0xd30 virt/kvm/kvm_main.c:5381
> ...
>
> The warning can also be triggered via vcpu_info_cache if an event is sent
> while the cache is inactive, causing the vCPU to attempt a refresh when
> injecting pending events.
>
> Fix this by moving the check for an inactive cache to the very beginning =
of
> __kvm_gpc_refresh(), before the WARN_ON_ONCE and before acquiring the
> gpc->lock. It is completely safe to check gpc->active before acquiring
> gpc->lock because all modifications to gpc->active are fully serialized b=
y
> gpc->refresh_lock, which is already held and asserted at the start of the
> function. Bailing out early also avoids the overhead of unnecessarily
> acquiring and releasing the lock (which disables and re-enables interrupt=
s)
> for a cache that cannot be refreshed.
>
> Fixes: 721f5b0dda78 ("KVM: pfncache: allow a cache to be activated with a=
 fixed (userspace) HVA")
> Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
> Reported-by: [email protected]
> Closes: https://syzkaller.appspot.com/bug?extid=3Dcde12433b6c56f55d9ed
> Link: https://syzkaller.appspot.com/ai_job?id=3D4e819403-979c-4f19-96ab-2=
8961c06eab0
> To: <[email protected]>
> To: "Paolo Bonzini" <[email protected]>
> To: "Paul Durrant" <[email protected]>
> Cc: <[email protected]>
>
> ---
> diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c
> index 728d2c1b4..fcfd5555b 100644
> --- a/virt/kvm/pfncache.c
> +++ b/virt/kvm/pfncache.c
> @@ -263,19 +263,17 @@ static int __kvm_gpc_refresh(struct gfn_to_pfn_cach=
e *gpc, gpa_t gpa, unsigned l
>         void *old_khva;
>         int ret;
>
> +       lockdep_assert_held(&gpc->refresh_lock);
> +
> +       if (!gpc->active)
> +               return -EINVAL;
> +
>         /* Either gpa or uhva must be valid, but not both */
>         if (WARN_ON_ONCE(kvm_is_error_gpa(gpa) =3D=3D kvm_is_error_hva(uh=
va)))
>                 return -EINVAL;
>
> -       lockdep_assert_held(&gpc->refresh_lock);
> -
>         write_lock_irq(&gpc->lock);
>
> -       if (!gpc->active) {
> -               ret =3D -EINVAL;
> -               goto out_unlock;
> -       }
> -
>         old_pfn =3D gpc->pfn;
>         old_khva =3D (void *)PAGE_ALIGN_DOWN((uintptr_t)gpc->khva);
>         old_uhva =3D PAGE_ALIGN_DOWN(gpc->uhva);
>
>
> base-commit: f5098b6bae761e346ebcd9da7f95622c04733cff
> --
> This is an AI-generated patch subject to moderation.
> Reply with '#syz upstream' to Sign-off the patch as a human author
> and send it to the upstream kernel mailing lists.
> Reply with '#syz reject' to reject it ('#syz unreject' to undo).
>
> See https://goo.gle/syzbot-ai-patches for information about AI-generated =
patches.
> You can comment on the patch as usual, syzbot will try to address
> the comments and send a new version of the patch if necessary.
> syzbot engineers can be reached at [email protected].
>
> --
> You received this message because you are subscribed to the Google Groups=
 "syzkaller-upstream-moderation" group.
> To unsubscribe from this group and stop receiving emails from it, send an=
 email to [email protected].
> To view this discussion visit https://groups.google.com/d/msgid/syzkaller=
-upstream-moderation/a144cc7e-406a-4896-9299-9f425c722100%40mail.kernel.org=
.