Re: [PATCH v4 15/48] KVM: arm64: gic-v5: Add resident/non-resident hyp calls

Sascha Bischoff <[email protected]> Fri, 31 Jul 2026 13:16:11 +0000
Newsgroups dev.linux.lists.sashiko-reviews,dev.linux.lists.kvmarm,org.kernel.vger.kvm
Message-ID <[email protected]>
On Fri, 2026-07-24 at 11:26 +0000, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential
> issue(s) to consider:
> - [Critical] The __vgic_v5_make_resident and
> __vgic_v5_make_non_resident hypercalls write unvalidated host-
> supplied data directly to the sensitive ICH_CONTEXTR_EL2 system
> register, breaking pKVM isolation.
> - [Medium] EL2 double-fetches the system register value from host
> memory to check for residency faults, enabling a TOCTOU race.
> --
> 
> --- Patch [15]: [PATCH v4 15/48] KVM: arm64: gic-v5: Add
> resident/non-resident hyp calls ---
> commit 1b185bf2c8c83d76bc583dab060f0d8f605b0939
> Author: Sascha Bischoff <[email protected]>
> 
> KVM: arm64: gic-v5: Add resident/non-resident hyp calls
> 
> This patch introduces GICv5 VPE residency management by adding
> hypercalls
> to make a VPE resident or non-resident via ICH_CONTEXTR_EL2. It also
> updates vgic_v5_load() and vgic_v5_put() to use these hypercalls,
> ensuring
> the VPE is considered resident during the load-to-put interval.
> 
> > diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> 
> [ ... ]
> 
> > @@ -691,6 +691,20 @@ static void
> > handle___tracing_write_event(struct kvm_cpu_context *host_ctxt)
> >  	trace_selftest(id);
> >  }
> >  
> > +static void handle___vgic_v5_make_resident(struct kvm_cpu_context
> > *host_ctxt)
> > +{
> > +	DECLARE_REG(struct vgic_v5_cpu_if *, cpu_if, host_ctxt,
> > 1);
> > +
> > +	__vgic_v5_make_resident(kern_hyp_va(cpu_if));
> 
> [Severity: Critical]
> Does this hypercall act on a raw, unvalidated host memory pointer
> passed in
> a register?
> 
> Because the host can pass an arbitrary pointer to
> handle___vgic_v5_make_resident(), EL2 should copy the necessary
> fields to
> EL2 private memory and validate them before acting on the data to
> prevent
> isolation bypasses.

As previously discussed, we don't support pKVM at the moment for GICv5.
This is fine for now.

> 
> > +}
> > +
> > +static void handle___vgic_v5_make_non_resident(struct
> > kvm_cpu_context *host_ctxt)
> > +{
> 
> [ ... ]
> 
> > diff --git a/arch/arm64/kvm/hyp/vgic-v5-sr.c
> > b/arch/arm64/kvm/hyp/vgic-v5-sr.c
> > --- a/arch/arm64/kvm/hyp/vgic-v5-sr.c
> > +++ b/arch/arm64/kvm/hyp/vgic-v5-sr.c
> > @@ -7,6 +7,32 @@
> >  
> >  #include <asm/kvm_hyp.h>
> >  
> > +void __vgic_v5_make_resident(struct vgic_v5_cpu_if *cpu_if)
> > +{
> > +	write_sysreg_s(cpu_if->vgic_contextr,
> > SYS_ICH_CONTEXTR_EL2);
> 
> [Severity: Critical]
> Does this code write unvalidated host-supplied data directly to the
> sensitive ICH_CONTEXTR_EL2 system register?
> 
> Under the pKVM threat model, cpu_if points to untrusted host memory
> post
> deprivilege. By blindly reading vgic_contextr from the host and
> writing it
> to the hardware register, a malicious host could potentially supply
> an
> arbitrary VMID and VPEID belonging to a protected VM. This could
> trick the
> Interrupt Routing System into routing a protected VM's interrupts to
> the
> host's physical CPU.
> 
> Should EL2 derive and validate the residency state from EL2-private
> data
> instead of trusting the raw hypercall parameters in
> __vgic_v5_make_resident()?

As I stated above, no. We're not currently supporting pKVM.

> 
> > +	isb();
> > +
> > +	/* Catch any faults */
> > +	cpu_if->vgic_contextr =
> > read_sysreg_s(SYS_ICH_CONTEXTR_EL2);
> > +	if (!!FIELD_GET(ICH_CONTEXTR_EL2_F, cpu_if-
> > >vgic_contextr))
> 
> [Severity: Medium]
> Can this sequence cause a Time-of-Check to Time-of-Use race?
> 
> The code writes the system register value to cpu_if->vgic_contextr in
> host-shared memory, and then immediately evaluates it back from host
> memory
> using FIELD_GET(). A concurrent thread on the host could overwrite
> this
> memory location between the write and the check.
> 
> If the hardware reports a residency fault (F=1), could the host
> overwrite
> the memory with F=0 to trick EL2 into ignoring the fault? Reading the
> system register into a local EL2-private variable for validation
> before
> writing it out to host memory might avoid this issue.

We should never be in the situation where this happens. The only times
where the state of cpu_if->vgic_contextr is changed is as part of
vgic_v5_load() or vgic_v5_put().

> 
> > +		return;
> > +
> > +	cpu_if->gicv5_vpe.resident = true;
> > +}
> > +
> > +void __vgic_v5_make_non_resident(struct vgic_v5_cpu_if *cpu_if)
> > +{
> > +	/*
> > +	 * Make as non-resident before actually making non-
> > resident. Avoids race
> > +	 * with doorbell arriving.
> > +	 */
> > +	cpu_if->gicv5_vpe.resident = false;
> > +	dsb(st);
> > +
> > +	write_sysreg_s(cpu_if->vgic_contextr,
> > SYS_ICH_CONTEXTR_EL2);
> 
> [Severity: Critical]
> Similarly to __vgic_v5_make_resident(), does
> __vgic_v5_make_non_resident()
> write host-controlled memory to the system register instead of
> securely
> writing a hardcoded 0 from EL2-private state?

No. See above.

> 
> > +	isb();
> > +}
> 

Thanks,
Sascha