* [PATCH 0/2] RISC-V: KVM: Validate AIA MMIO ranges against GPA width
@ 2026-08-12 5:39 Pengpeng Hou
2026-08-12 5:39 ` [PATCH 1/2] RISC-V: KVM: Validate AIA MMIO address ranges Pengpeng Hou
2026-08-12 5:39 ` [PATCH 2/2] RISC-V: KVM: Disallow GPA-width changes after AIA init Pengpeng Hou
0 siblings, 2 replies; 3+ messages in thread
From: Pengpeng Hou @ 2026-08-12 5:39 UTC (permalink / raw)
To: Anup Patel, Atish Patra
Cc: Pengpeng Hou, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Fangyu Yu, Andrew Jones, Nutty Liu, Guo Ren, kvm,
kvm-riscv, linux-riscv, linux-kernel
The AIA device API currently checks only the alignment of userspace-
supplied APLIC and IMSIC base addresses. This can publish a wrapping
fixed-size MMIO interval or one that lies beyond the selected stage-2
guest physical address (GPA) width.
There are two points to close because the GPA width is configurable:
1. Validate every complete range when it is stored and again immediately
before AIA initialization publishes the first MMIO device.
2. Once AIA initialization has published those devices, prevent the GPA
width from being reduced below their addresses.
Both initialization and GPA-width changes are serialized by kvm->lock.
The series was reviewed against the RISC-V KVM queue at
dfdf1374fdeccb5b7e3d35186228e01ec5ea5f01. No build or runtime testing
was performed.
Pengpeng Hou (2):
RISC-V: KVM: Validate AIA MMIO address ranges
RISC-V: KVM: Disallow GPA-width changes after AIA init
arch/riscv/kvm/aia_device.c | 79 +++++++++++++++++++++++++++++++------
arch/riscv/kvm/vm.c | 3 +-
2 files changed, 68 insertions(+), 14 deletions(-)
--
2.50.1 (Apple Git-155)
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 1/2] RISC-V: KVM: Validate AIA MMIO address ranges
2026-08-12 5:39 [PATCH 0/2] RISC-V: KVM: Validate AIA MMIO ranges against GPA width Pengpeng Hou
@ 2026-08-12 5:39 ` Pengpeng Hou
2026-08-12 5:39 ` [PATCH 2/2] RISC-V: KVM: Disallow GPA-width changes after AIA init Pengpeng Hou
1 sibling, 0 replies; 3+ messages in thread
From: Pengpeng Hou @ 2026-08-12 5:39 UTC (permalink / raw)
To: Anup Patel, Atish Patra
Cc: Pengpeng Hou, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Fangyu Yu, Andrew Jones, Nutty Liu, Guo Ren, kvm,
kvm-riscv, linux-riscv, linux-kernel
Userspace supplies the APLIC and per-vCPU IMSIC base addresses through
the AIA device API. The address setters currently reject only
misaligned addresses.
The regions are later registered on KVM's MMIO bus with fixed sizes. An
aligned base near U64_MAX can therefore wrap when the range end is
formed. A lower base can still place the range beyond the selected
guest stage-2 physical address space. kvm_io_bus_cmp() assumes that
registered ranges do not wrap.
Validate the complete interval when an address is stored. Since
KVM_CAP_VM_GPA_BITS can change the selected GPA width before AIA
initialization, validate every address again before registering the
first MMIO device.
Return -EINVAL for misalignment or arithmetic overflow and -E2BIG when
the end exceeds the stage-2 GPA limit, following the arm64 VGIC
address-validation convention.
Fixes: 89d01306e34d ("RISC-V: KVM: Implement device interface for AIA irqchip")
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
arch/riscv/kvm/aia_device.c | 79 +++++++++++++++++++++++++++++++------
1 file changed, 66 insertions(+), 13 deletions(-)
diff --git a/arch/riscv/kvm/aia_device.c b/arch/riscv/kvm/aia_device.c
index efc7c0bcfba9..e969dbdc4b97 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);
@@ -191,6 +216,40 @@ static int aia_imsic_addr(struct kvm *kvm, u64 *addr,
return 0;
}
+static int aia_validate_addr_ranges(struct kvm *kvm)
+{
+ struct kvm_aia *aia = &kvm->arch.aia;
+ struct kvm_vcpu_aia *vaia;
+ struct kvm_vcpu *vcpu;
+ unsigned long idx;
+ int ret;
+
+ if (aia->nr_sources) {
+ if (aia->aplic_addr == KVM_RISCV_AIA_UNDEF_ADDR)
+ return -EINVAL;
+
+ ret = aia_check_addr_range(kvm, aia->aplic_addr,
+ KVM_DEV_RISCV_APLIC_ALIGN,
+ KVM_DEV_RISCV_APLIC_SIZE);
+ if (ret)
+ return ret;
+ }
+
+ kvm_for_each_vcpu(idx, vcpu, kvm) {
+ vaia = &vcpu->arch.aia_context;
+ if (vaia->imsic_addr == KVM_RISCV_AIA_UNDEF_ADDR)
+ return -EINVAL;
+
+ ret = aia_check_addr_range(kvm, vaia->imsic_addr,
+ KVM_DEV_RISCV_IMSIC_ALIGN,
+ KVM_DEV_RISCV_IMSIC_SIZE);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static gpa_t aia_imsic_ppn(struct kvm_aia *aia, gpa_t addr)
{
u32 h, l;
@@ -244,9 +303,9 @@ static int aia_init(struct kvm *kvm)
if (aia->nr_ids < aia->nr_sources)
return -EINVAL;
- /* APLIC base is required for non-zero number of sources */
- if (aia->nr_sources && aia->aplic_addr == KVM_RISCV_AIA_UNDEF_ADDR)
- return -EINVAL;
+ ret = aia_validate_addr_ranges(kvm);
+ if (ret)
+ return ret;
/* Group index bits must not overlap guest and HART index bits. */
if (aia->nr_group_bits &&
@@ -263,12 +322,6 @@ static int aia_init(struct kvm *kvm)
kvm_for_each_vcpu(idx, vcpu, kvm) {
vaia = &vcpu->arch.aia_context;
- /* IMSIC base is required */
- if (vaia->imsic_addr == KVM_RISCV_AIA_UNDEF_ADDR) {
- ret = -EINVAL;
- goto fail_cleanup_imsics;
- }
-
/* All IMSICs should have matching base PPN */
if (base_ppn == KVM_RISCV_AIA_UNDEF_ADDR)
base_ppn = aia_imsic_ppn(aia, vaia->imsic_addr);
--
2.50.1 (Apple Git-155)
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/2] RISC-V: KVM: Disallow GPA-width changes after AIA init
2026-08-12 5:39 [PATCH 0/2] RISC-V: KVM: Validate AIA MMIO ranges against GPA width Pengpeng Hou
2026-08-12 5:39 ` [PATCH 1/2] RISC-V: KVM: Validate AIA MMIO address ranges Pengpeng Hou
@ 2026-08-12 5:39 ` Pengpeng Hou
1 sibling, 0 replies; 3+ messages in thread
From: Pengpeng Hou @ 2026-08-12 5:39 UTC (permalink / raw)
To: Anup Patel, Atish Patra
Cc: Pengpeng Hou, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, Fangyu Yu, Andrew Jones, Nutty Liu, Guo Ren, kvm,
kvm-riscv, linux-riscv, linux-kernel
KVM_ENABLE_CAP(KVM_CAP_VM_GPA_BITS) allows userspace to reduce the
stage-2 GPA width while a VM has no vCPUs or memory slots.
AIA initialization can still complete with an APLIC and no vCPUs or
memory slots. In that state, the APLIC MMIO device has already been
registered, but the existing checks allow userspace to shrink the GPA
width below its address.
Reject GPA-width changes after AIA initialization. Both paths hold
kvm->lock, so the check also closes the race between final AIA address
validation and publication.
Fixes: 7263b4fdb0b2 ("RISC-V: KVM: Reuse KVM_CAP_VM_GPA_BITS to select HGATP.MODE")
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
arch/riscv/kvm/vm.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c
index a9f083feeb76..66edfaa86243 100644
--- a/arch/riscv/kvm/vm.c
+++ b/arch/riscv/kvm/vm.c
@@ -250,7 +250,8 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
mutex_lock(&kvm->lock);
mutex_lock(&kvm->slots_lock);
- if (kvm->created_vcpus || !kvm_are_all_memslots_empty(kvm))
+ if (kvm->created_vcpus || !kvm_are_all_memslots_empty(kvm) ||
+ kvm_riscv_aia_initialized(kvm))
r = -EBUSY;
else
kvm->arch.pgd_levels = new_levels;
--
2.50.1 (Apple Git-155)
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-08-12 5:40 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-12 5:39 [PATCH 0/2] RISC-V: KVM: Validate AIA MMIO ranges against GPA width Pengpeng Hou
2026-08-12 5:39 ` [PATCH 1/2] RISC-V: KVM: Validate AIA MMIO address ranges Pengpeng Hou
2026-08-12 5:39 ` [PATCH 2/2] RISC-V: KVM: Disallow GPA-width changes after AIA init Pengpeng Hou
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox