[PATCH v1 0/4] KVM: arm64: Fix unguarded GICv5 CPU interface accesses

Fuad Tabba posted 4 patches 1 month, 3 weeks ago
There is a newer version of this series
arch/arm64/kvm/hyp/nvhe/hyp-main.c |  6 ++++++
arch/arm64/kvm/hyp/nvhe/pkvm.c     | 16 ++++++++++++++--
arch/arm64/kvm/hyp/nvhe/switch.c   |  4 ++--
arch/arm64/kvm/vgic/vgic.c         | 12 ++++++++----
4 files changed, 30 insertions(+), 8 deletions(-)
[PATCH v1 0/4] KVM: arm64: Fix unguarded GICv5 CPU interface accesses
Posted by Fuad Tabba 1 month, 3 weeks ago
Hi folks,

This series stops KVM reaching GICv5 CPU interface registers on hardware
that does not implement them, in three places with no guard.

Under pKVM the first two are reachable from an untrusted host. EL2
copies vgic_model out of the host's struct kvm without validating it,
and the nVHE world switch dispatches on that field with no cpucap
guard, so a host writing KVM_DEV_TYPE_ARM_VGIC_V5 steers EL2 into
ICC_ICSR_EL1 and the ICH_PPI_* registers. Separately, __vgic_v5_save_apr
and __vgic_v5_restore_vmcr_apr sit in the hypercall band the
de-privileged host may still call, and pKVM never registers a GICv5
vgic, so neither has a valid caller in protected mode. Without
FEAT_GCIE those registers are UNDEFINED at EL2, so either path panics
the hypervisor. Both need a compromised host kernel rather than host
userspace, so this is hardening and not a guest-reachable hole.

I had said these paths were unreachable under pKVM because
vgic_v5_probe() skips GICv5 registration in protected mode [1]. That was
wrong. The skip is host-side only, and does not constrain what a
malicious host can call.

The third one is not pKVM. can_access_vgic_from_kernel() excludes only
the GICv3 system register interface, so on a native GICv5 system
without FEAT_GCIE_LEGACY the kernel reaches EL2-only registers from EL1
under nVHE, and the world switch does the same work at EL2 anyway.

The last patch drops the VGICv3 reference from two nVHE world switch
comments that cover GICv5 too. No functional change.

Tested on QEMU. I also checked the first one with a local host patch
that hands EL2 a GICv5 model: it panics at __vgic_v5_restore_state
before the series and boots cleanly after.

Based on Linux 7.2-rc6 (075b74841bd00). It also applies cleanly to
kvmarm/next and kvmarm/fixes.

I really should stop looking at the GIC, but I won't be able to anytime
soon I'm afraid...

Cheers,
/fuad

[1] https://lore.kernel.org/all/CA%2BEHjTyGULmVCgyoya3bXG4gRj0OYFE1gnJLhNE6kvCrZFtXyQ@mail.gmail.com/

Fuad Tabba (4):
  KVM: arm64: Validate the host-provided vgic model in pKVM
  KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM
  KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1
  KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch

 arch/arm64/kvm/hyp/nvhe/hyp-main.c |  6 ++++++
 arch/arm64/kvm/hyp/nvhe/pkvm.c     | 16 ++++++++++++++--
 arch/arm64/kvm/hyp/nvhe/switch.c   |  4 ++--
 arch/arm64/kvm/vgic/vgic.c         | 12 ++++++++----
 4 files changed, 30 insertions(+), 8 deletions(-)


base-commit: 075b74841bd0065a3bda3440873c747938e69b68
-- 
2.39.5
Re: [PATCH v1 0/4] KVM: arm64: Fix unguarded GICv5 CPU interface accesses
Posted by Sascha Bischoff 1 month, 3 weeks ago
Hi Fuad,
On Thu, 2026-08-06 at 11:02 +0100, Fuad Tabba wrote:
> Hi folks,
> 
> This series stops KVM reaching GICv5 CPU interface registers on
> hardware
> that does not implement them, in three places with no guard.

Thank you for fixing my mess!

I'd naively assumed that if we don't allow a vGICv5 to be initialised,
then we'd not be going down these paths. Obviously, that doesn't quite
fit with the pKVM model.

> Under pKVM the first two are reachable from an untrusted host. EL2
> copies vgic_model out of the host's struct kvm without validating it,
> and the nVHE world switch dispatches on that field with no cpucap
> guard, so a host writing KVM_DEV_TYPE_ARM_VGIC_V5 steers EL2 into
> ICC_ICSR_EL1 and the ICH_PPI_* registers. Separately,
> __vgic_v5_save_apr
> and __vgic_v5_restore_vmcr_apr sit in the hypercall band the
> de-privileged host may still call, and pKVM never registers a GICv5
> vgic, so neither has a valid caller in protected mode. Without
> FEAT_GCIE those registers are UNDEFINED at EL2, so either path panics
> the hypervisor. Both need a compromised host kernel rather than host
> userspace, so this is hardening and not a guest-reachable hole.
> 
> I had said these paths were unreachable under pKVM because
> vgic_v5_probe() skips GICv5 registration in protected mode [1]. That
> was
> wrong. The skip is host-side only, and does not constrain what a
> malicious host can call.

Yeah, this is precisely what I'd gotten wrong in my mental model. I'll
try and bear this in mind going forward.

> 
> The third one is not pKVM. can_access_vgic_from_kernel() excludes
> only
> the GICv3 system register interface, so on a native GICv5 system
> without FEAT_GCIE_LEGACY the kernel reaches EL2-only registers from
> EL1
> under nVHE, and the world switch does the same work at EL2 anyway.
> 
> The last patch drops the VGICv3 reference from two nVHE world switch
> comments that cover GICv5 too. No functional change.
> 
> Tested on QEMU. I also checked the first one with a local host patch
> that hands EL2 a GICv5 model: it panics at __vgic_v5_restore_state
> before the series and boots cleanly after.
> 
> Based on Linux 7.2-rc6 (075b74841bd00). It also applies cleanly to
> kvmarm/next and kvmarm/fixes.
> 
> I really should stop looking at the GIC, but I won't be able to
> anytime
> soon I'm afraid...

You and me both!

These three look good to me:

  KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM
  KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1
  KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch

Hence, for those three:
Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>

I've left a question on your first patch.

Thanks,
Sascha

> 
> Cheers,
> /fuad
> 
> [1]
> https://lore.kernel.org/all/CA%2BEHjTyGULmVCgyoya3bXG4gRj0OYFE1gnJLhNE6kvCrZFtXyQ@mail.gmail.com/
> 
> Fuad Tabba (4):
>   KVM: arm64: Validate the host-provided vgic model in pKVM
>   KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM
>   KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1
>   KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch
> 
>  arch/arm64/kvm/hyp/nvhe/hyp-main.c |  6 ++++++
>  arch/arm64/kvm/hyp/nvhe/pkvm.c     | 16 ++++++++++++++--
>  arch/arm64/kvm/hyp/nvhe/switch.c   |  4 ++--
>  arch/arm64/kvm/vgic/vgic.c         | 12 ++++++++----
>  4 files changed, 30 insertions(+), 8 deletions(-)
> 
> 
> base-commit: 075b74841bd0065a3bda3440873c747938e69b68