* [PATCH] RISC-V: KVM: Fix PMU event info array size overflow
@ 2026-07-18 15:36 ` Guidong Han
0 siblings, 0 replies; 4+ messages in thread
From: Guidong Han @ 2026-07-18 15:36 UTC (permalink / raw)
To: Anup Patel, Atish Patra
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm,
kvm-riscv, linux-riscv, linux-kernel, Guidong Han
SBI PMU EVENT_GET_INFO stores guest-controlled
num_events * sizeof(*einfo) in an int. On RV64, num_events = 0x10000001
makes 0x100000010 truncate to 16. KVM then allocates one entry but loops
over the original num_events, causing out-of-bounds reads and writes. A
nested guest triggered:
BUG: KASAN: slab-out-of-bounds in kvm_riscv_vcpu_pmu_event_info+0xa4/0x142
Read of size 4 at addr ff600000074d46b0 by task init/1
Call Trace:
[<ffffffff8006471c>] kvm_riscv_vcpu_pmu_event_info+0xa4/0x142
[<ffffffff800690c0>] kvm_sbi_ext_pmu_handler+0xca/0x268
[<ffffffff8006779e>] kvm_riscv_vcpu_sbi_ecall+0xec/0x1e6
[<ffffffff8006008c>] kvm_riscv_vcpu_exit+0x48c/0x540
[<ffffffff8005ea0a>] kvm_arch_vcpu_ioctl_run+0x37e/0xc80
Allocated by task 1:
__kmalloc_noprof+0x19e/0x4b0
kvm_riscv_vcpu_pmu_event_info+0x72/0x142
kvm_sbi_ext_pmu_handler+0xca/0x268
kvm_riscv_vcpu_sbi_ecall+0xec/0x1e6
kvm_riscv_vcpu_exit+0x48c/0x540
kvm_arch_vcpu_ioctl_run+0x37e/0xc80
The buggy address is located 0 bytes to the right of
allocated 16-byte region [ff600000074d46a0, ff600000074d46b0)
Store the shared-memory size in size_t and reject multiplication overflow.
Reject sizes beyond KMALLOC_MAX_SIZE to avoid triggering WARN_ON_ONCE_GFP()
for an impossible allocation order. Use an unsigned long loop index to
match num_events.
Fixes: e309fd113b9f ("RISC-V: KVM: Implement get event info function")
Cc: stable@vger.kernel.org
Signed-off-by: Guidong Han <2045gemini@gmail.com>
---
arch/riscv/kvm/vcpu_pmu.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c
index bb46dcbfb24d..8b489fc3051f 100644
--- a/arch/riscv/kvm/vcpu_pmu.c
+++ b/arch/riscv/kvm/vcpu_pmu.c
@@ -12,7 +12,9 @@
#include <linux/err.h>
#include <linux/kvm_host.h>
#include <linux/nospec.h>
+#include <linux/overflow.h>
#include <linux/perf/riscv_pmu.h>
+#include <linux/slab.h>
#include <asm/csr.h>
#include <asm/kvm_isa.h>
#include <asm/kvm_vcpu_sbi.h>
@@ -479,16 +481,21 @@ 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;
gpa_t shmem;
u32 eidx, etype;
u64 econfig;
int ret;
- if (flags != 0 || (saddr_low & (SZ_16 - 1) || num_events == 0)) {
+ if (flags != 0 || (saddr_low & (SZ_16 - 1)) || num_events == 0 ||
+ check_mul_overflow(num_events, sizeof(*einfo), &shmem_size)) {
ret = SBI_ERR_INVALID_PARAM;
goto out;
}
+ if (shmem_size > KMALLOC_MAX_SIZE) {
+ ret = SBI_ERR_FAILURE;
+ goto out;
+ }
shmem = saddr_low;
if (saddr_high != 0) {
@@ -512,7 +519,7 @@ int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low
goto free_mem;
}
- for (int i = 0; i < num_events; i++) {
+ for (unsigned long i = 0; i < num_events; i++) {
eidx = einfo[i].event_idx;
etype = kvm_pmu_get_perf_event_type(eidx);
econfig = kvm_pmu_get_perf_event_config(eidx, einfo[i].event_data);
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH] RISC-V: KVM: Fix PMU event info array size overflow
@ 2026-07-18 15:36 ` Guidong Han
0 siblings, 0 replies; 4+ messages in thread
From: Guidong Han @ 2026-07-18 15:36 UTC (permalink / raw)
To: Anup Patel, Atish Patra
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm,
kvm-riscv, linux-riscv, linux-kernel, Guidong Han
SBI PMU EVENT_GET_INFO stores guest-controlled
num_events * sizeof(*einfo) in an int. On RV64, num_events = 0x10000001
makes 0x100000010 truncate to 16. KVM then allocates one entry but loops
over the original num_events, causing out-of-bounds reads and writes. A
nested guest triggered:
BUG: KASAN: slab-out-of-bounds in kvm_riscv_vcpu_pmu_event_info+0xa4/0x142
Read of size 4 at addr ff600000074d46b0 by task init/1
Call Trace:
[<ffffffff8006471c>] kvm_riscv_vcpu_pmu_event_info+0xa4/0x142
[<ffffffff800690c0>] kvm_sbi_ext_pmu_handler+0xca/0x268
[<ffffffff8006779e>] kvm_riscv_vcpu_sbi_ecall+0xec/0x1e6
[<ffffffff8006008c>] kvm_riscv_vcpu_exit+0x48c/0x540
[<ffffffff8005ea0a>] kvm_arch_vcpu_ioctl_run+0x37e/0xc80
Allocated by task 1:
__kmalloc_noprof+0x19e/0x4b0
kvm_riscv_vcpu_pmu_event_info+0x72/0x142
kvm_sbi_ext_pmu_handler+0xca/0x268
kvm_riscv_vcpu_sbi_ecall+0xec/0x1e6
kvm_riscv_vcpu_exit+0x48c/0x540
kvm_arch_vcpu_ioctl_run+0x37e/0xc80
The buggy address is located 0 bytes to the right of
allocated 16-byte region [ff600000074d46a0, ff600000074d46b0)
Store the shared-memory size in size_t and reject multiplication overflow.
Reject sizes beyond KMALLOC_MAX_SIZE to avoid triggering WARN_ON_ONCE_GFP()
for an impossible allocation order. Use an unsigned long loop index to
match num_events.
Fixes: e309fd113b9f ("RISC-V: KVM: Implement get event info function")
Cc: stable@vger.kernel.org
Signed-off-by: Guidong Han <2045gemini@gmail.com>
---
arch/riscv/kvm/vcpu_pmu.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c
index bb46dcbfb24d..8b489fc3051f 100644
--- a/arch/riscv/kvm/vcpu_pmu.c
+++ b/arch/riscv/kvm/vcpu_pmu.c
@@ -12,7 +12,9 @@
#include <linux/err.h>
#include <linux/kvm_host.h>
#include <linux/nospec.h>
+#include <linux/overflow.h>
#include <linux/perf/riscv_pmu.h>
+#include <linux/slab.h>
#include <asm/csr.h>
#include <asm/kvm_isa.h>
#include <asm/kvm_vcpu_sbi.h>
@@ -479,16 +481,21 @@ 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;
gpa_t shmem;
u32 eidx, etype;
u64 econfig;
int ret;
- if (flags != 0 || (saddr_low & (SZ_16 - 1) || num_events == 0)) {
+ if (flags != 0 || (saddr_low & (SZ_16 - 1)) || num_events == 0 ||
+ check_mul_overflow(num_events, sizeof(*einfo), &shmem_size)) {
ret = SBI_ERR_INVALID_PARAM;
goto out;
}
+ if (shmem_size > KMALLOC_MAX_SIZE) {
+ ret = SBI_ERR_FAILURE;
+ goto out;
+ }
shmem = saddr_low;
if (saddr_high != 0) {
@@ -512,7 +519,7 @@ int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low
goto free_mem;
}
- for (int i = 0; i < num_events; i++) {
+ for (unsigned long i = 0; i < num_events; i++) {
eidx = einfo[i].event_idx;
etype = kvm_pmu_get_perf_event_type(eidx);
econfig = kvm_pmu_get_perf_event_config(eidx, einfo[i].event_data);
--
2.43.0
--
kvm-riscv mailing list
kvm-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kvm-riscv
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH] RISC-V: KVM: Fix PMU event info array size overflow
@ 2026-07-18 15:36 ` Guidong Han
0 siblings, 0 replies; 4+ messages in thread
From: Guidong Han @ 2026-07-18 15:36 UTC (permalink / raw)
To: Anup Patel, Atish Patra
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, kvm,
kvm-riscv, linux-riscv, linux-kernel, Guidong Han
SBI PMU EVENT_GET_INFO stores guest-controlled
num_events * sizeof(*einfo) in an int. On RV64, num_events = 0x10000001
makes 0x100000010 truncate to 16. KVM then allocates one entry but loops
over the original num_events, causing out-of-bounds reads and writes. A
nested guest triggered:
BUG: KASAN: slab-out-of-bounds in kvm_riscv_vcpu_pmu_event_info+0xa4/0x142
Read of size 4 at addr ff600000074d46b0 by task init/1
Call Trace:
[<ffffffff8006471c>] kvm_riscv_vcpu_pmu_event_info+0xa4/0x142
[<ffffffff800690c0>] kvm_sbi_ext_pmu_handler+0xca/0x268
[<ffffffff8006779e>] kvm_riscv_vcpu_sbi_ecall+0xec/0x1e6
[<ffffffff8006008c>] kvm_riscv_vcpu_exit+0x48c/0x540
[<ffffffff8005ea0a>] kvm_arch_vcpu_ioctl_run+0x37e/0xc80
Allocated by task 1:
__kmalloc_noprof+0x19e/0x4b0
kvm_riscv_vcpu_pmu_event_info+0x72/0x142
kvm_sbi_ext_pmu_handler+0xca/0x268
kvm_riscv_vcpu_sbi_ecall+0xec/0x1e6
kvm_riscv_vcpu_exit+0x48c/0x540
kvm_arch_vcpu_ioctl_run+0x37e/0xc80
The buggy address is located 0 bytes to the right of
allocated 16-byte region [ff600000074d46a0, ff600000074d46b0)
Store the shared-memory size in size_t and reject multiplication overflow.
Reject sizes beyond KMALLOC_MAX_SIZE to avoid triggering WARN_ON_ONCE_GFP()
for an impossible allocation order. Use an unsigned long loop index to
match num_events.
Fixes: e309fd113b9f ("RISC-V: KVM: Implement get event info function")
Cc: stable@vger.kernel.org
Signed-off-by: Guidong Han <2045gemini@gmail.com>
---
arch/riscv/kvm/vcpu_pmu.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c
index bb46dcbfb24d..8b489fc3051f 100644
--- a/arch/riscv/kvm/vcpu_pmu.c
+++ b/arch/riscv/kvm/vcpu_pmu.c
@@ -12,7 +12,9 @@
#include <linux/err.h>
#include <linux/kvm_host.h>
#include <linux/nospec.h>
+#include <linux/overflow.h>
#include <linux/perf/riscv_pmu.h>
+#include <linux/slab.h>
#include <asm/csr.h>
#include <asm/kvm_isa.h>
#include <asm/kvm_vcpu_sbi.h>
@@ -479,16 +481,21 @@ 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;
gpa_t shmem;
u32 eidx, etype;
u64 econfig;
int ret;
- if (flags != 0 || (saddr_low & (SZ_16 - 1) || num_events == 0)) {
+ if (flags != 0 || (saddr_low & (SZ_16 - 1)) || num_events == 0 ||
+ check_mul_overflow(num_events, sizeof(*einfo), &shmem_size)) {
ret = SBI_ERR_INVALID_PARAM;
goto out;
}
+ if (shmem_size > KMALLOC_MAX_SIZE) {
+ ret = SBI_ERR_FAILURE;
+ goto out;
+ }
shmem = saddr_low;
if (saddr_high != 0) {
@@ -512,7 +519,7 @@ int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low
goto free_mem;
}
- for (int i = 0; i < num_events; i++) {
+ for (unsigned long i = 0; i < num_events; i++) {
eidx = einfo[i].event_idx;
etype = kvm_pmu_get_perf_event_type(eidx);
econfig = kvm_pmu_get_perf_event_config(eidx, einfo[i].event_data);
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH] RISC-V: KVM: Fix PMU event info array size overflow
2026-07-18 15:36 ` Guidong Han
(?)
(?)
@ 2026-07-18 15:49 ` sashiko-bot
-1 siblings, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-07-18 15:49 UTC (permalink / raw)
To: Guidong Han; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Guest-controlled large allocation lacks __GFP_NOWARN and __GFP_ACCOUNT, allowing host log spam and memcg limit bypass.
--
--- Patch [1]: [PATCH] RISC-V: KVM: Fix PMU event info array size overflow ---
commit f0a5b0643b60a1981804276ca1f91780cd681469
Author: Guidong Han <2045gemini@gmail.com>
RISC-V: KVM: Fix PMU event info array size overflow
The patch prevents an integer overflow when calculating shmem_size from
guest-controlled num_events in the SBI PMU EVENT_GET_INFO handler. It
introduces check_mul_overflow and rejects sizes beyond KMALLOC_MAX_SIZE.
> diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c
> index bb46dcbfb24da..8b489fc3051f4 100644
> --- a/arch/riscv/kvm/vcpu_pmu.c
> +++ b/arch/riscv/kvm/vcpu_pmu.c
[ ... ]
> @@ -479,16 +481,21 @@ 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;
> gpa_t shmem;
> u32 eidx, etype;
> u64 econfig;
> int ret;
>
> - if (flags != 0 || (saddr_low & (SZ_16 - 1) || num_events == 0)) {
> + if (flags != 0 || (saddr_low & (SZ_16 - 1)) || num_events == 0 ||
> + check_mul_overflow(num_events, sizeof(*einfo), &shmem_size)) {
> ret = SBI_ERR_INVALID_PARAM;
> goto out;
> }
> + if (shmem_size > KMALLOC_MAX_SIZE) {
> + ret = SBI_ERR_FAILURE;
> + goto out;
> + }
[Severity: High]
This is a pre-existing issue, but is it safe to allow a guest-controlled
allocation up to KMALLOC_MAX_SIZE using kzalloc() without __GFP_ACCOUNT
and __GFP_NOWARN?
Later in kvm_riscv_vcpu_pmu_event_info(), the code does:
einfo = kzalloc(shmem_size, GFP_KERNEL);
Since the allocation uses GFP_KERNEL without __GFP_ACCOUNT, this memory is
not charged to the guest's memory cgroup. Could an untrusted guest coordinate
concurrent SBI_EXT_PMU_EVENT_GET_INFO hypercalls across multiple vCPUs to
temporarily hoard host memory, potentially causing a host OOM?
Additionally, without __GFP_NOWARN, won't allocation failures for these
high-order pages on a fragmented system generate rate-limited page
allocation failure stack traces, causing host log spam?
Since these allocations can be large and are guest-driven, would it be better
to use kvcalloc() with GFP_KERNEL_ACCOUNT | __GFP_NOWARN so it falls back to
vmalloc() if physical memory is fragmented?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260718153620.829378-1-2045gemini@gmail.com?part=1
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-07-18 15:49 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-18 15:36 [PATCH] RISC-V: KVM: Fix PMU event info array size overflow Guidong Han
2026-07-18 15:36 ` Guidong Han
2026-07-18 15:36 ` Guidong Han
2026-07-18 15:49 ` sashiko-bot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.