[PATCH v2 1/2] RISC-V: KVM: Validate AIA MMIO address ranges
Anup Patel
anup at brainfault.org
Thu Nov 12 21:36:45 PST 2026
On Sun, Sep 20, 2026 at 6:39 PM Pengpeng Hou <hppiscas at 163.com> wrote:
>
> The AIA address setters check alignment but not the complete fixed-size
> APLIC and IMSIC MMIO regions. A range can therefore wrap when its end is
> formed or extend beyond the selected guest physical address space before
> it is registered on the KVM MMIO bus.
>
> Check the complete range in both setters. Return -EINVAL for alignment
> or arithmetic overflow and -E2BIG for a range beyond the selected GPA
> limit, following the arm64 VGIC address-validation convention.
>
> Recheck only the APLIC range during initialization: userspace can set
> its address and then change KVM_CAP_VM_GPA_BITS while the VM still has
> no vCPUs or memory slots. An IMSIC address, in contrast, can only be set
> for an existing vCPU, which already prevents subsequent GPA-width
> changes. No additional pass over the vCPUs is needed.
>
> Keep the existing required-address checks and IMSIC cleanup path.
>
> The issue was found by our static-analysis tool.
>
> Fixes: 89d01306e34d ("RISC-V: KVM: Implement device interface for AIA irqchip")
> Assisted-by: gpt 5
> Signed-off-by: Pengpeng Hou <hppiscas at 163.com>
> ---
> Changes since v1: https://lore.kernel.org/r/38f87205419f328693bc6ab25ae78f021c2dd003.1786512671.git.pengpeng@iscas.ac.cn/
> - Keep the original APLIC and per-vCPU IMSIC required-address checks.
> - Drop the separate pass over all vCPUs during initialization.
> - Recheck only APLIC, whose address can be configured before GPA width
> becomes immutable; IMSIC setters already require an existing vCPU.
>
> arch/riscv/kvm/aia_device.c | 42 +++++++++++++++++++++++++++++++++----
> 1 file changed, 38 insertions(+), 4 deletions(-)
>
> diff --git a/arch/riscv/kvm/aia_device.c b/arch/riscv/kvm/aia_device.c
> index efc7c0b..4490015 100644
> --- a/arch/riscv/kvm/aia_device.c
> +++ b/arch/riscv/kvm/aia_device.c
> @@ -10,7 +10,9 @@
> #include <linux/bits.h>
> #include <linux/irqchip/riscv-imsic.h>
> #include <linux/kvm_host.h>
> +#include <linux/overflow.h>
> #include <linux/uaccess.h>
> +#include <asm/kvm_gstage.h>
> #include <asm/kvm_isa.h>
>
> static int aia_create(struct kvm_device *dev, u32 type)
> @@ -142,17 +144,37 @@ static int aia_config(struct kvm *kvm, unsigned long type,
> return 0;
> }
>
> +static int aia_check_addr_range(struct kvm *kvm, u64 addr, u64 alignment,
> + u64 size)
> +{
> + u64 end;
> +
> + if (!IS_ALIGNED(addr, alignment))
> + return -EINVAL;
> +
> + if (check_add_overflow(addr, size, &end))
> + return -EINVAL;
> +
> + if (end > kvm_riscv_gstage_gpa_size(kvm->arch.pgd_levels))
> + return -E2BIG;
> +
> + return 0;
> +}
> +
> static int aia_aplic_addr(struct kvm *kvm, u64 *addr, bool write)
> {
> struct kvm_aia *aia = &kvm->arch.aia;
> + int ret;
>
> if (write) {
> /* Writes can only be done before irqchip is initialized */
> if (kvm_riscv_aia_initialized(kvm))
> return -EBUSY;
>
> - if (*addr & (KVM_DEV_RISCV_APLIC_ALIGN - 1))
> - return -EINVAL;
> + ret = aia_check_addr_range(kvm, *addr, KVM_DEV_RISCV_APLIC_ALIGN,
> + KVM_DEV_RISCV_APLIC_SIZE);
> + if (ret)
> + return ret;
>
> aia->aplic_addr = *addr;
> } else
> @@ -166,6 +188,7 @@ static int aia_imsic_addr(struct kvm *kvm, u64 *addr,
> {
> struct kvm_vcpu *vcpu;
> struct kvm_vcpu_aia *vcpu_aia;
> + int ret;
>
> vcpu = kvm_get_vcpu(kvm, vcpu_idx);
> if (!vcpu)
> @@ -177,8 +200,10 @@ static int aia_imsic_addr(struct kvm *kvm, u64 *addr,
> if (kvm_riscv_aia_initialized(kvm))
> return -EBUSY;
>
> - if (*addr & (KVM_DEV_RISCV_IMSIC_ALIGN - 1))
> - return -EINVAL;
> + ret = aia_check_addr_range(kvm, *addr, KVM_DEV_RISCV_IMSIC_ALIGN,
> + KVM_DEV_RISCV_IMSIC_SIZE);
> + if (ret)
> + return ret;
> }
>
> mutex_lock(&vcpu->mutex);
> @@ -248,6 +273,15 @@ static int aia_init(struct kvm *kvm)
> if (aia->nr_sources && aia->aplic_addr == KVM_RISCV_AIA_UNDEF_ADDR)
> return -EINVAL;
>
> + /* The GPA width may change after setting APLIC's address on an empty VM. */
> + if (aia->nr_sources) {
> + ret = aia_check_addr_range(kvm, aia->aplic_addr,
> + KVM_DEV_RISCV_APLIC_ALIGN,
> + KVM_DEV_RISCV_APLIC_SIZE);
> + if (ret)
> + return ret;
> + }
> +
We should also check IMSIC addresses one more time in aia_init(). I will
take care of it at the time of merging.
> /* Group index bits must not overlap guest and HART index bits. */
> if (aia->nr_group_bits &&
> aia->nr_group_shift < (IMSIC_MMIO_PAGE_SHIFT +
>
LGTM.
Reviewed-by: Anup Patel <anup at brainfault.org>
Queued this patch as a fix for Linux-7.4-rcX
Thanks,
Anup
More information about the linux-riscv
mailing list