kvm_riscv_vcpu_pmu_event_info() implements the SBI PMU EVENT_GET_INFO call. It sizes the temporary shared-memory buffer that mirrors the guest's event-info array with: int shmem_size = num_events * sizeof(*einfo); num_events comes directly from the guest (SBI argument a2) and is only rejected when it is zero; there is no upper bound. sizeof(*einfo) is 16, so the multiplication is evaluated as size_t but the result is then truncated when it is stored into the 32-bit int shmem_size. A guest can pass, for example, num_events = 0x10000001. The real size is 0x100000010 bytes, but shmem_size truncates to 16. kzalloc() then allocates room for a single entry while the following loop still runs the full 64-bit num_events times: for (int i = 0; i < num_events; i++) { ... einfo[i].output = (ret > 0) ? 1 : 0; } This is a guest-triggerable heap out-of-bounds read and write that extends far past the allocation. Compute the size with size_mul() into a size_t so the value used for the allocation always matches the loop bound. For an oversized num_events the multiplication saturates to SIZE_MAX, kzalloc() fails and the call returns SBI_ERR_FAILURE before the loop runs; well-formed requests behave exactly as before. Signed-off-by: Naveed Khan --- diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c index bb46dcbfb2..ff940fa74b 100644 --- a/arch/riscv/kvm/vcpu_pmu.c +++ b/arch/riscv/kvm/vcpu_pmu.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -479,7 +480,7 @@ int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low unsigned long flags, struct kvm_vcpu_sbi_return *retdata) { struct riscv_pmu_event_info *einfo = NULL; - int shmem_size = num_events * sizeof(*einfo); + size_t shmem_size = size_mul(num_events, sizeof(*einfo)); gpa_t shmem; u32 eidx, etype; u64 econfig; -- 2.50.1 (Apple Git-155)