Re: [PATCH v5 12/49] KVM: arm64: gic-v5: Keep GICv5 vCPU limit model-specific

[email protected] Fri, 07 Aug 2026 13:30:49 +0000
Newsgroups dev.linux.lists.kvmarm,org.kernel.vger.kvm
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] kvm_vgic_create() fails to validate that previously created VCPUs have IDs within the newly selected VGIC model's limits (for GICv2 and GICv3), leading to undefined behavior in GICv2 SGI routing.
--

--- Patch [12]: [PATCH v5 12/49] KVM: arm64: gic-v5: Keep GICv5 vCPU limit model-specific ---
commit 42bacf6540695fc12a35eee006d5382303176971
Author: Sascha Bischoff <[email protected]>

KVM: arm64: gic-v5: Keep GICv5 vCPU limit model-specific

This patch separates the IRS-derived vCPU limit for GICv5 from the generic
KVM maximum limit. It adds validation to reject GICv5 device creation if
existing VCPU IDs exceed the GICv5 model-specific limit.

> diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
> index 079a57c2b18f6..8e1e844ed6e93 100644
> --- a/arch/arm64/kvm/vgic/vgic-init.c
> +++ b/arch/arm64/kvm/vgic/vgic-init.c

[ ... ]

> @@ -129,13 +129,34 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
>  	}
>  	ret = 0;
>  
> -	if (type == KVM_DEV_TYPE_ARM_VGIC_V2)
> +	switch (type) {
> +	case KVM_DEV_TYPE_ARM_VGIC_V2:
>  		kvm->max_vcpus = VGIC_V2_MAX_CPUS;
> -	else if (type == KVM_DEV_TYPE_ARM_VGIC_V3)
> +		break;
> +	case KVM_DEV_TYPE_ARM_VGIC_V3:
>  		kvm->max_vcpus = VGIC_V3_MAX_CPUS;
> -	else if (type == KVM_DEV_TYPE_ARM_VGIC_V5)
> -		kvm->max_vcpus = min(VGIC_V5_MAX_CPUS,
> -				     kvm_vgic_global_state.max_gic_vcpus);
> +		break;
> +	case KVM_DEV_TYPE_ARM_VGIC_V5:
> +		kvm->max_vcpus = kvm_vgic_global_state.max_gicv5_vcpus;
> +
> +		/*
> +		 * We use the userspace-allocated vcpu_id as the index into the
> +		 * GICv5 VPE table. This ensures that userspace's view and the
> +		 * guest's view of IAFFIDs remains consistent - GICv5's virtual
> +		 * IAFFID is the VPE ID in that VM's VPET.
> +		 *
> +		 * Reject vGICv5 creation if we have already got any vCPUs that
> +		 * we cannot back with a GICv5 VPE in the VPET.
> +		 */
> +		kvm_for_each_vcpu(i, vcpu, kvm) {
> +			if (vcpu->vcpu_id >= kvm->max_vcpus) {
> +				ret = -E2BIG;
> +				goto out_unlock;
> +			}
> +		}
> +
> +		break;
> +	}

[Severity: High]
This is a pre-existing issue, but does restricting this validation loop to 
only GICv5 leave the older models vulnerable to an out-of-bounds vcpu_id?

If userspace creates a VCPU with a large ID (for example, 500) before creating 
the VGIC device, it succeeds because the pre-VGIC limit defaults to the 
maximum supported by the system. If userspace then selects a GICv2 device, 
kvm_vgic_create() drops max_vcpus to 8. 

Because the vcpu_id check above is inside the GICv5 switch block, we skip 
validating the existing VCPUs against the new GICv2 limit.

When configuring private IRQs later during initialization, 
vgic_setup_private_irq() does this:

arch/arm64/kvm/vgic/vgic-init.c:vgic_setup_private_irq() {
    ...
    irq->targets = BIT(vcpu->vcpu_id);
    ...
}

Evaluating BIT(500) shifts a 64-bit integer by 500, which results in undefined
behavior in the kernel. A similar shift happens for SGI routing in 
vgic_mmio_write_sgir().

Should this validation loop be moved outside the switch statement so it runs 
for all VGIC models and prevents these out-of-bounds shifts across the board?

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=12