Kernel KVM virtualization development
 help / color / mirror / Atom feed
* [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
  2026-07-30  9:17 ` [PATCH v2] " Guidong Han
  0 siblings, 2 replies; 5+ 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] 5+ messages in thread

* Re: [PATCH] RISC-V: KVM: Fix PMU event info array size overflow
  2026-07-18 15:36 [PATCH] RISC-V: KVM: Fix PMU event info array size overflow Guidong Han
@ 2026-07-18 15:49 ` sashiko-bot
  2026-07-30  9:36   ` Guidong Han
  2026-07-30  9:17 ` [PATCH v2] " Guidong Han
  1 sibling, 1 reply; 5+ 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] 5+ messages in thread

* [PATCH v2] RISC-V: KVM: Fix PMU event info array size overflow
  2026-07-18 15:36 [PATCH] RISC-V: KVM: Fix PMU event info array size overflow Guidong Han
  2026-07-18 15:49 ` sashiko-bot
@ 2026-07-30  9:17 ` Guidong Han
  2026-07-30  9:36   ` sashiko-bot
  1 sibling, 1 reply; 5+ messages in thread
From: Guidong Han @ 2026-07-30  9:17 UTC (permalink / raw)
  To: Anup Patel, Atish Patra
  Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	Naveed Khan, 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.
Allocate the guest-driven array with GFP_KERNEL_ACCOUNT so it is charged
to kmemcg, and use __GFP_NOWARN to suppress allocation failure warnings.
Use kvcalloc() to allow vmalloc fallback and an unsigned long loop index
to match num_events.

Reported-by: Naveed Khan <naveed@digiscrypt.com>
Closes: https://lore.kernel.org/kvm/178345245327.72065.13249716450708539854@digiscrypt.com/
Fixes: e309fd113b9f ("RISC-V: KVM: Implement get event info function")
Cc: stable@vger.kernel.org
Signed-off-by: Guidong Han <2045gemini@gmail.com>
---
Changes in v2:
- Use an accounted, no-warning kvcalloc() allocation and kvfree(), as
  suggested by Sashiko.
- Naveed Khan reported the issue before v1. I missed his report at the
  time, so add Reported-by and Closes tags to credit him.

Link to v1: https://lore.kernel.org/kvm/20260718153620.829378-1-2045gemini@gmail.com/
---
 arch/riscv/kvm/vcpu_pmu.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c
index bb46dcbfb24d..8e1f6abb84e2 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,13 +481,14 @@ 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;
 	}
@@ -500,7 +503,8 @@ int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low
 		}
 	}
 
-	einfo = kzalloc(shmem_size, GFP_KERNEL);
+	einfo = kvcalloc(num_events, sizeof(*einfo),
+			 GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
 	if (!einfo) {
 		ret = SBI_ERR_FAILURE;
 		goto out;
@@ -512,7 +516,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);
@@ -525,7 +529,7 @@ int kvm_riscv_vcpu_pmu_event_info(struct kvm_vcpu *vcpu, unsigned long saddr_low
 		ret = SBI_ERR_INVALID_ADDRESS;
 
 free_mem:
-	kfree(einfo);
+	kvfree(einfo);
 out:
 	retdata->err_val = ret;
 
-- 
2.43.0

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v2] RISC-V: KVM: Fix PMU event info array size overflow
  2026-07-30  9:17 ` [PATCH v2] " Guidong Han
@ 2026-07-30  9:36   ` sashiko-bot
  0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-07-30  9:36 UTC (permalink / raw)
  To: Guidong Han; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Unbounded guest-controlled `num_events` allows arbitrarily large memory allocations via `kvcalloc` and host soft lockups.
--

--- Patch [1]: [PATCH v2] RISC-V: KVM: Fix PMU event info array size overflow ---
commit 500aa03e09c05223e23f66e67acfa12d3e264362
Author: Guidong Han <2045gemini@gmail.com>

RISC-V: KVM: Fix PMU event info array size overflow

This commit fixes a slab out-of-bounds issue by storing the shared memory
size in a size_t and checking for multiplication overflow. It also switches
the allocation to use kvcalloc() with GFP_KERNEL_ACCOUNT and __GFP_NOWARN
to support large guest requests safely.

Link: https://lore.kernel.org/kvm/178345245327.72065.13249716450708539854@digiscrypt.com/
Link: https://lore.kernel.org/kvm/20260718153620.829378-1-2045gemini@gmail.com/

> diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c
> index 2025b664961c8..a7f948410d531 100644
> --- a/arch/riscv/kvm/vcpu_pmu.c
> +++ b/arch/riscv/kvm/vcpu_pmu.c
[ ... ]
> @@ -479,13 +481,14 @@ 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;
[ ... ]
> -	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)) {

[Severity: High]
Is there a missing upper bound check for num_events here?

While check_mul_overflow() prevents integer wrap-around, it still allows a
guest to pass extremely large values for num_events (e.g., hundreds of
millions) since size_t is 64-bit on RV64.

>  		ret = SBI_ERR_INVALID_PARAM;
>  		goto out;
>  	}
[ ... ]
> -	einfo = kzalloc(shmem_size, GFP_KERNEL);
> +	einfo = kvcalloc(num_events, sizeof(*einfo),
> +			 GFP_KERNEL_ACCOUNT | __GFP_NOWARN);

[Severity: High]
Can this unbounded allocation lead to host memory exhaustion?

Because the patch replaces kzalloc() with kvcalloc() without adding a
functional upper limit on num_events, an untrusted guest could force the
host to allocate and zero gigabytes of vmalloc memory. Even with
GFP_KERNEL_ACCOUNT, this could cause severe memory pressure or memcg OOMs.

>  	if (!einfo) {
>  		ret = SBI_ERR_FAILURE;
>  		goto out;
>  	}
[ ... ]
> -	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);

[Severity: High]
If the guest backs the request with valid memory, could this loop cause a
host soft lockup?

This block iterates num_events times synchronously. For very large inputs,
this could execute millions of times without cond_resched(), monopolizing
the host CPU and causing RCU stalls. Should num_events be bounded to a sane
architectural maximum?

>  		econfig = kvm_pmu_get_perf_event_config(eidx, einfo[i].event_data);
>  		ret = riscv_pmu_get_event_info(etype, econfig, NULL);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260730091710.1366757-1-2045gemini@gmail.com?part=1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] RISC-V: KVM: Fix PMU event info array size overflow
  2026-07-18 15:49 ` sashiko-bot
@ 2026-07-30  9:36   ` Guidong Han
  0 siblings, 0 replies; 5+ messages in thread
From: Guidong Han @ 2026-07-30  9:36 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: kvm

On Sat, Jul 18, 2026 at 11:49 PM <sashiko-bot@kernel.org> wrote:
>
> 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.

You're right, this was helpful. Fixed in v2. Thanks!

> --
>
> --- 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] 5+ messages in thread

end of thread, other threads:[~2026-07-30  9:36 UTC | newest]

Thread overview: 5+ 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:49 ` sashiko-bot
2026-07-30  9:36   ` Guidong Han
2026-07-30  9:17 ` [PATCH v2] " Guidong Han
2026-07-30  9:36   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox