Re: [PATCH v2 11/11] KVM: arm64: Tag host-VA hypercall parameters __kern

Fuad Tabba <[email protected]> Mon, 3 Aug 2026 14:49:21 +0100
Newsgroups dev.linux.lists.sashiko-reviews,dev.linux.lists.kvmarm
Message-ID <CA+EHjTyH9BcXvROasUDSfyFGSmrBGWpnyPvJMKiGjD0ot7WS8A@mail.gmail.com>
On Mon, 3 Aug 2026 at 14:44, <[email protected]> wrote:
>
> Thank you for your contribution! Sashiko AI review found 2 potential issu=
e(s) to consider:
>
> New issues:
> - [Medium] The `kern_hyp_va_host()` macro strips the `__kern` tag using `=
(__force void *)` and returns a plain pointer, undermining the static analy=
sis guarantees for both misapplied unwraps and subsequent TOCTOU bugs.

https://lore.kernel.org/all/[email protected]/

>
> Pre-existing issues:
> - [Critical] Always-on hypercalls (e.g., `__vgic_v3_save_aprs`, `__kvm_ad=
just_pc`) accept host VAs, translate them via `kern_hyp_va_host()`, and rea=
d/write to them without validating physical page ownership, enabling a Conf=
used Deputy arbitrary memory corruption attack.

We're working on that, coming soon!

/fuad

> --
>
> --- Patch [11]: [PATCH v2 11/11] KVM: arm64: Tag host-VA hypercall parame=
ters __kern ---
> commit 0acf480afb506d5122464f1024574511fad649b3
> Author: Fuad Tabba <[email protected]>
>
> KVM: arm64: Tag host-VA hypercall parameters __kern
>
> The nVHE hypervisor takes host virtual addresses as hypercall arguments
> and translates each with kern_hyp_va() before use. This patch adds a __ke=
rn
> sparse address space for EL2 code to tag host-VA parameters and introduce=
s
> kern_hyp_va_host() to unwrap them.
>
> > diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/=
kvm_mmu.h
> > index 6eae7e7e2a684..57f65257bb56d 100644
> > --- a/arch/arm64/include/asm/kvm_mmu.h
> > +++ b/arch/arm64/include/asm/kvm_mmu.h
> [ ... ]
> > @@ -140,6 +142,14 @@ static __always_inline unsigned long __kern_hyp_va=
(unsigned long v)
> >
> >  #define kern_hyp_va(v)       ((typeof(v))(__kern_hyp_va((unsigned long=
)(v))))
> >
> > +/*
> > + * Translate a __kern-tagged host VA, dropping the tag: the only sanct=
ioned
> > + * unwrap. Translation only, no ownership or bounds validation; the re=
sult
> > + * carries the pointee type stripped of the tag and of any cv-qualifie=
rs.
> > + */
> > +#define kern_hyp_va_host(v)                                          \
> > +     ((TYPEOF_UNQUAL(*(v)) *)__kern_hyp_va((unsigned long)(__force voi=
d *)(v)))
>
> [Severity: Medium]
> Since the __force void * cast unconditionally strips all sparse address s=
pace
> information, does this suppress warnings if the macro is accidentally app=
lied
> to an untagged EL2 private-VA-range pointer?
>
> Additionally, because the returned pointer has no address space tag, does=
n't
> this prevent sparse from warning if a developer directly double-fetches o=
r acts
> on the translated untrusted host memory instead of copying it first?
>
> For example, in __pkvm_init_vm(), host_kvm is passed as a plain pointer a=
nd
> loses its sparse static analysis protection despite still aliasing untrus=
ted
> memory.
>
> [ ... ]
> > diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nv=
he/hyp-main.c
> > index 6986ce55fd9ef..f8ea1661b3166 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> [ ... ]
> > @@ -500,15 +500,15 @@ DEFINE_KVM_HOST_HCALL0_VOID(__vgic_v3_init_lrs)
> >  }
> >
> >  DEFINE_KVM_HOST_HCALL_VOID(__vgic_v3_save_aprs,
> > -     struct vgic_v3_cpu_if *, cpu_if)
> > +     struct vgic_v3_cpu_if __kern *, cpu_if)
> >  {
> > -     __vgic_v3_save_aprs(kern_hyp_va(cpu_if));
> > +     __vgic_v3_save_aprs(kern_hyp_va_host(cpu_if));
> >  }
>
> [Severity: Critical]
> This is a pre-existing issue, but by retaining the lack of bounds validat=
ion
> through kern_hyp_va_host(), can the host EL1 trigger an arbitrary memory
> corruption in the hypervisor?
>
> Since kern_hyp_va_host() explicitly performs no ownership or bounds valid=
ation,
> it appears the host kernel could provide a forged pointer that translates=
 to a
> physical page owned by EL2.
>
> The hypervisor then passes this pointer directly to __vgic_v3_save_aprs()
> after unvalidated translation:
>
> arch/arm64/kvm/hyp/vgic-v3-sr.c:__vgic_v3_save_aprs() {
>     ...
>     cpu_if->vgic_ap0r[3] =3D __vgic_v3_read_ap0rn(3);
>     ...
> }
>
> which directly writes to the untrusted pointer, potentially allowing the =
host
> to corrupt EL2 private memory and bypass isolation.
>
> [ ... ]
>
> --
> Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260803124220.33=
[email protected]?part=3D11