* [PATCH] RISC-V: KVM: Fix integer overflow in kvm_pmu_validate_counter_mask()
@ 2026-03-19 3:59 Jiakai Xu
2026-03-19 17:39 ` Atish Patra
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Jiakai Xu @ 2026-03-19 3:59 UTC (permalink / raw)
To: kvm-riscv, kvm, linux-kernel, linux-riscv
Cc: Albert Ou, Alexandre Ghiti, Andrew Jones, Anup Patel, Atish Patra,
Palmer Dabbelt, Paul Walmsley, Jiakai Xu, Jiakai Xu
When a guest initiates an SBI_EXT_PMU_COUNTER_CFG_MATCH call with
ctr_base=0xfffffffffffffffe, ctr_mask=0xeb5f and flags=0x1
(SBI_PMU_CFG_FLAG_SKIP_MATCH), kvm_riscv_vcpu_pmu_ctr_cfg_match()
first invokes kvm_pmu_validate_counter_mask() to verify whether
ctr_base and ctr_mask are valid, by evaluating:
!ctr_mask || (ctr_base + __fls(ctr_mask) >= kvm_pmu_num_counters(kvpmu))
With the above inputs, __fls(0xeb5f) equals 15, and adding 15 to
0xfffffffffffffffe causes an integer overflow, wrapping around to 13.
Since 13 is less than kvm_pmu_num_counters(), the validation wrongly
succeeds.
Thereafter, since flags & SBI_PMU_CFG_FLAG_SKIP_MATCH is satisfied,
the code evaluates:
!test_bit(ctr_base + __ffs(ctr_mask), kvpmu->pmc_in_use)
Here __ffs(0xeb5f) equals 0, so test_bit() receives 0xfffffffffffffffe
as the bit index and attempts to access the corresponding element of
the kvpmu->pmc_in_use, which results in an invalid memory access. This
triggers the following Oops:
Unable to handle kernel paging request at virtual address e3ebffff12abba89
generic_test_bit include/asm-generic/bitops/generic-non-atomic.h:128
kvm_riscv_vcpu_pmu_ctr_cfg_match arch/riscv/kvm/vcpu_pmu.c:758
kvm_sbi_ext_pmu_handler arch/riscv/kvm/vcpu_sbi_pmu.c:49
kvm_riscv_vcpu_sbi_ecall arch/riscv/kvm/vcpu_sbi.c:608
kvm_riscv_vcpu_exit arch/riscv/kvm/vcpu_exit.c:240
The root cause is that kvm_pmu_validate_counter_mask() does not account
for the case where ctr_base itself is out of range, allowing the
subsequent addition to silently overflow and bypass the check.
Fix this by explicitly validating ctr_base against kvm_pmu_num_counters()
before performing the addition.
This bug was found by fuzzing the KVM RISC-V PMU interface.
Fixes: 0cb74b65d2e5e6 ("RISC-V: KVM: Implement perf support without sampling")
Signed-off-by: Jiakai Xu <jiakaiPeanut@gmail.com>
Signed-off-by: Jiakai Xu <xujiakai2025@iscas.ac.cn>
---
arch/riscv/kvm/vcpu_pmu.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c
index e873430e596b2..a098a9b417ad8 100644
--- a/arch/riscv/kvm/vcpu_pmu.c
+++ b/arch/riscv/kvm/vcpu_pmu.c
@@ -266,8 +266,10 @@ static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx,
static int kvm_pmu_validate_counter_mask(struct kvm_pmu *kvpmu, unsigned long ctr_base,
unsigned long ctr_mask)
{
- /* Make sure the we have a valid counter mask requested from the caller */
- if (!ctr_mask || (ctr_base + __fls(ctr_mask) >= kvm_pmu_num_counters(kvpmu)))
+ unsigned long num_ctrs = kvm_pmu_num_counters(kvpmu);
+
+ /* Make sure we have a valid counter mask requested from the caller */
+ if (!ctr_mask || ctr_base >= num_ctrs || (ctr_base + __fls(ctr_mask) >= num_ctrs))
return -EINVAL;
return 0;
--
2.34.1
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH] RISC-V: KVM: Fix integer overflow in kvm_pmu_validate_counter_mask() 2026-03-19 3:59 [PATCH] RISC-V: KVM: Fix integer overflow in kvm_pmu_validate_counter_mask() Jiakai Xu @ 2026-03-19 17:39 ` Atish Patra 2026-03-20 1:02 ` Jiakai Xu 2026-03-23 8:47 ` Nutty.Liu 2026-03-30 8:26 ` Anup Patel 2 siblings, 1 reply; 5+ messages in thread From: Atish Patra @ 2026-03-19 17:39 UTC (permalink / raw) To: Jiakai Xu, kvm-riscv, kvm, linux-kernel, linux-riscv Cc: Albert Ou, Alexandre Ghiti, Andrew Jones, Anup Patel, Palmer Dabbelt, Paul Walmsley, Jiakai Xu On 3/18/26 8:59 PM, Jiakai Xu wrote: > When a guest initiates an SBI_EXT_PMU_COUNTER_CFG_MATCH call with > ctr_base=0xfffffffffffffffe, ctr_mask=0xeb5f and flags=0x1 > (SBI_PMU_CFG_FLAG_SKIP_MATCH), kvm_riscv_vcpu_pmu_ctr_cfg_match() > first invokes kvm_pmu_validate_counter_mask() to verify whether > ctr_base and ctr_mask are valid, by evaluating: > !ctr_mask || (ctr_base + __fls(ctr_mask) >= kvm_pmu_num_counters(kvpmu)) > > With the above inputs, __fls(0xeb5f) equals 15, and adding 15 to > 0xfffffffffffffffe causes an integer overflow, wrapping around to 13. > Since 13 is less than kvm_pmu_num_counters(), the validation wrongly > succeeds. > > Thereafter, since flags & SBI_PMU_CFG_FLAG_SKIP_MATCH is satisfied, > the code evaluates: > !test_bit(ctr_base + __ffs(ctr_mask), kvpmu->pmc_in_use) > > Here __ffs(0xeb5f) equals 0, so test_bit() receives 0xfffffffffffffffe > as the bit index and attempts to access the corresponding element of > the kvpmu->pmc_in_use, which results in an invalid memory access. This > triggers the following Oops: > Unable to handle kernel paging request at virtual address e3ebffff12abba89 > generic_test_bit include/asm-generic/bitops/generic-non-atomic.h:128 > kvm_riscv_vcpu_pmu_ctr_cfg_match arch/riscv/kvm/vcpu_pmu.c:758 > kvm_sbi_ext_pmu_handler arch/riscv/kvm/vcpu_sbi_pmu.c:49 > kvm_riscv_vcpu_sbi_ecall arch/riscv/kvm/vcpu_sbi.c:608 > kvm_riscv_vcpu_exit arch/riscv/kvm/vcpu_exit.c:240 > > The root cause is that kvm_pmu_validate_counter_mask() does not account > for the case where ctr_base itself is out of range, allowing the > subsequent addition to silently overflow and bypass the check. > > Fix this by explicitly validating ctr_base against kvm_pmu_num_counters() > before performing the addition. > > This bug was found by fuzzing the KVM RISC-V PMU interface. Thanks for fuzzing. Do you have a detailed report that you can share ? > Fixes: 0cb74b65d2e5e6 ("RISC-V: KVM: Implement perf support without sampling") > Signed-off-by: Jiakai Xu <jiakaiPeanut@gmail.com> > Signed-off-by: Jiakai Xu <xujiakai2025@iscas.ac.cn> > --- > arch/riscv/kvm/vcpu_pmu.c | 6 ++++-- > 1 file changed, 4 insertions(+), 2 deletions(-) > > diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c > index e873430e596b2..a098a9b417ad8 100644 > --- a/arch/riscv/kvm/vcpu_pmu.c > +++ b/arch/riscv/kvm/vcpu_pmu.c > @@ -266,8 +266,10 @@ static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx, > static int kvm_pmu_validate_counter_mask(struct kvm_pmu *kvpmu, unsigned long ctr_base, > unsigned long ctr_mask) > { > - /* Make sure the we have a valid counter mask requested from the caller */ > - if (!ctr_mask || (ctr_base + __fls(ctr_mask) >= kvm_pmu_num_counters(kvpmu))) > + unsigned long num_ctrs = kvm_pmu_num_counters(kvpmu); > + > + /* Make sure we have a valid counter mask requested from the caller */ > + if (!ctr_mask || ctr_base >= num_ctrs || (ctr_base + __fls(ctr_mask) >= num_ctrs)) > return -EINVAL; > > return 0; Thanks for the fix. Reviewed-by: Atish Patra <atish.patra@linux.dev> _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] RISC-V: KVM: Fix integer overflow in kvm_pmu_validate_counter_mask() 2026-03-19 17:39 ` Atish Patra @ 2026-03-20 1:02 ` Jiakai Xu 0 siblings, 0 replies; 5+ messages in thread From: Jiakai Xu @ 2026-03-20 1:02 UTC (permalink / raw) To: atish.patra Cc: ajones, alex, anup, aou, jiakaiPeanut, kvm-riscv, kvm, linux-kernel, linux-riscv, palmer, pjw, xujiakai2025 > > When a guest initiates an SBI_EXT_PMU_COUNTER_CFG_MATCH call with > > ctr_base=0xfffffffffffffffe, ctr_mask=0xeb5f and flags=0x1 > > (SBI_PMU_CFG_FLAG_SKIP_MATCH), kvm_riscv_vcpu_pmu_ctr_cfg_match() > > first invokes kvm_pmu_validate_counter_mask() to verify whether > > ctr_base and ctr_mask are valid, by evaluating: > > !ctr_mask || (ctr_base + __fls(ctr_mask) >= kvm_pmu_num_counters(kvpmu)) > > > > With the above inputs, __fls(0xeb5f) equals 15, and adding 15 to > > 0xfffffffffffffffe causes an integer overflow, wrapping around to 13. > > Since 13 is less than kvm_pmu_num_counters(), the validation wrongly > > succeeds. > > > > Thereafter, since flags & SBI_PMU_CFG_FLAG_SKIP_MATCH is satisfied, > > the code evaluates: > > !test_bit(ctr_base + __ffs(ctr_mask), kvpmu->pmc_in_use) > > > > Here __ffs(0xeb5f) equals 0, so test_bit() receives 0xfffffffffffffffe > > as the bit index and attempts to access the corresponding element of > > the kvpmu->pmc_in_use, which results in an invalid memory access. This > > triggers the following Oops: > > Unable to handle kernel paging request at virtual address e3ebffff12abba89 > > generic_test_bit include/asm-generic/bitops/generic-non-atomic.h:128 > > kvm_riscv_vcpu_pmu_ctr_cfg_match arch/riscv/kvm/vcpu_pmu.c:758 > > kvm_sbi_ext_pmu_handler arch/riscv/kvm/vcpu_sbi_pmu.c:49 > > kvm_riscv_vcpu_sbi_ecall arch/riscv/kvm/vcpu_sbi.c:608 > > kvm_riscv_vcpu_exit arch/riscv/kvm/vcpu_exit.c:240 > > > > The root cause is that kvm_pmu_validate_counter_mask() does not account > > for the case where ctr_base itself is out of range, allowing the > > subsequent addition to silently overflow and bypass the check. > > > > Fix this by explicitly validating ctr_base against kvm_pmu_num_counters() > > before performing the addition. > > > > This bug was found by fuzzing the KVM RISC-V PMU interface. > > Thanks for fuzzing. Do you have a detailed report that you can share ? Yes, here is the detailed crash report: Unable to handle kernel paging request at virtual address e3ebffff12abba89 Current syz.4.5087 pgtable: 4K pagesize, 57-bit VAs, pgdp=0x0000000130cbc000 [e3ebffff12abba89] pgd=000000005fff6001, p4d=000000005fff5801, pud=000000005fff5401, pmd=000000005b4000e7 Oops [#1] Modules linked in: CPU: 3 UID: 0 PID: 5789 Comm: syz.4.5087 Tainted: G W 7.0.0-rc2-00014-gc61ec3e8cc5d #1 PREEMPT Tainted: [W]=WARN Hardware name: riscv-virtio,qemu (DT) epc : generic_test_bit include/asm-generic/bitops/generic-non-atomic.h:128 [inline] epc : kvm_riscv_vcpu_pmu_ctr_cfg_match+0x31a/0xe12 arch/riscv/kvm/vcpu_pmu.c:758 ra : kvm_riscv_vcpu_pmu_ctr_cfg_match+0x2ee/0xe12 arch/riscv/kvm/vcpu_pmu.c:758 epc : ffffffff8012f320 ra : ffffffff8012f2f4 sp : ff200000067275c0 gp : ffffffff8a382bc0 tp : ff60000095d03500 t0 : ff200000067276e0 t1 : fffffffff3f3f3f3 t2 : 0000000200004520 s0 : ff200000067277c0 s1 : ff20000006727740 a0 : 0000000000000007 a1 : 0000000000000000 a2 : 0000000000080000 a3 : 03ec000012abba89 a4 : fffffffffffffffe a5 : e3ebffff12abba89 a6 : 0000000000000003 a7 : ffe3ffff00ce4ec4 s2 : 1f600000955dd448 s3 : ff600000955dace0 s4 : 0000000000000001 s5 : 0000000000000000 s6 : ff20000006727850 s7 : 0000000000000004 s8 : fffffffffffffffe s9 : 0000000000000000 s10: 1fe4000000ce4ec4 s11: 0000000000000003 t3 : cbdd65f600000000 t4 : 0000000000000000 t5 : 0000000000000000 t6 : 0000000000000000 ssp : 0000000000000000 status: 0000000200000120 badaddr: e3ebffff12abba89 cause: 000000000000000d [<ffffffff8012f320>] generic_test_bit include/asm-generic/bitops/generic-non-atomic.h:128 [inline] [<ffffffff8012f320>] kvm_riscv_vcpu_pmu_ctr_cfg_match+0x31a/0xe12 arch/riscv/kvm/vcpu_pmu.c:758 [<ffffffff80136b12>] kvm_sbi_ext_pmu_handler+0x266/0x630 arch/riscv/kvm/vcpu_sbi_pmu.c:49 [<ffffffff80133636>] kvm_riscv_vcpu_sbi_ecall+0x11c/0x2f8 arch/riscv/kvm/vcpu_sbi.c:608 [<ffffffff80122e50>] kvm_riscv_vcpu_exit+0x7b2/0x9ba arch/riscv/kvm/vcpu_exit.c:240 [<ffffffff8011fa6e>] kvm_arch_vcpu_ioctl_run+0x13c6/0x3600 arch/riscv/kvm/vcpu.c:1008 [<ffffffff800da0ae>] kvm_vcpu_ioctl+0x532/0x13e0 virt/kvm/kvm_main.c:4476 [<ffffffff80d25228>] vfs_ioctl fs/ioctl.c:51 [inline] [<ffffffff80d25228>] __do_sys_ioctl fs/ioctl.c:597 [inline] [<ffffffff80d25228>] __se_sys_ioctl fs/ioctl.c:583 [inline] [<ffffffff80d25228>] __riscv_sys_ioctl+0x180/0x1e4 fs/ioctl.c:583 [<ffffffff80078fc2>] syscall_handler+0x94/0x118 arch/riscv/include/asm/syscall.h:112 [<ffffffff86693a68>] do_trap_ecall_u+0x39e/0x62e arch/riscv/kernel/traps.c:344 [<ffffffff866be63e>] handle_exception+0x15e/0x16a arch/riscv/kernel/entry.S:232 Code: 9793 0036 993e 07b7 e000 17fd 5693 0039 1782 97b6 (c783) 0007 ---[ end trace 0000000000000000 ]--- ---------------- Code disassembly (best guess): 0: 00369793 slli a5,a3,0x3 4: 993e add s2,s2,a5 6: e00007b7 lui a5,0xe0000 a: 17fd addi a5,a5,-1 # 0xffffffffdfffffff c: 00395693 srli a3,s2,0x3 10: 1782 slli a5,a5,0x20 12: 97b6 add a5,a5,a3 * 14: 0007c783 lbu a5,0(a5) <-- trapping instruction <<<<<<<<<<<<<<< tail report >>>>>>>>>>>>>>> SYZFAIL: failed to recv rpc fd=3 want=4 recv=0 n=0 (errno 9: Bad file descriptor) <<<<<<<<<<<<<<< tail report >>>>>>>>>>>>>>> > > > Fixes: 0cb74b65d2e5e6 ("RISC-V: KVM: Implement perf support without sampling") > > Signed-off-by: Jiakai Xu <jiakaiPeanut@gmail.com> > > Signed-off-by: Jiakai Xu <xujiakai2025@iscas.ac.cn> > > --- > > arch/riscv/kvm/vcpu_pmu.c | 6 ++++-- > > 1 file changed, 4 insertions(+), 2 deletions(-) > > > > diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c > > index e873430e596b2..a098a9b417ad8 100644 > > --- a/arch/riscv/kvm/vcpu_pmu.c > > +++ b/arch/riscv/kvm/vcpu_pmu.c > > @@ -266,8 +266,10 @@ static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx, > > static int kvm_pmu_validate_counter_mask(struct kvm_pmu *kvpmu, unsigned long ctr_base, > > unsigned long ctr_mask) > > { > > - /* Make sure the we have a valid counter mask requested from the caller */ > > - if (!ctr_mask || (ctr_base + __fls(ctr_mask) >= kvm_pmu_num_counters(kvpmu))) > > + unsigned long num_ctrs = kvm_pmu_num_counters(kvpmu); > > + > > + /* Make sure we have a valid counter mask requested from the caller */ > > + if (!ctr_mask || ctr_base >= num_ctrs || (ctr_base + __fls(ctr_mask) >= num_ctrs)) > > return -EINVAL; > > > > return 0; > > Thanks for the fix. > > Reviewed-by: Atish Patra <atish.patra@linux.dev> Thanks for the review! Regards, Jiakai _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] RISC-V: KVM: Fix integer overflow in kvm_pmu_validate_counter_mask() 2026-03-19 3:59 [PATCH] RISC-V: KVM: Fix integer overflow in kvm_pmu_validate_counter_mask() Jiakai Xu 2026-03-19 17:39 ` Atish Patra @ 2026-03-23 8:47 ` Nutty.Liu 2026-03-30 8:26 ` Anup Patel 2 siblings, 0 replies; 5+ messages in thread From: Nutty.Liu @ 2026-03-23 8:47 UTC (permalink / raw) To: Jiakai Xu, kvm-riscv, kvm, linux-kernel, linux-riscv Cc: Albert Ou, Alexandre Ghiti, Andrew Jones, Anup Patel, Atish Patra, Palmer Dabbelt, Paul Walmsley, Jiakai Xu On 3/19/2026 11:59 AM, Jiakai Xu wrote: > When a guest initiates an SBI_EXT_PMU_COUNTER_CFG_MATCH call with > ctr_base=0xfffffffffffffffe, ctr_mask=0xeb5f and flags=0x1 > (SBI_PMU_CFG_FLAG_SKIP_MATCH), kvm_riscv_vcpu_pmu_ctr_cfg_match() > first invokes kvm_pmu_validate_counter_mask() to verify whether > ctr_base and ctr_mask are valid, by evaluating: > !ctr_mask || (ctr_base + __fls(ctr_mask) >= kvm_pmu_num_counters(kvpmu)) > > With the above inputs, __fls(0xeb5f) equals 15, and adding 15 to > 0xfffffffffffffffe causes an integer overflow, wrapping around to 13. > Since 13 is less than kvm_pmu_num_counters(), the validation wrongly > succeeds. > > Thereafter, since flags & SBI_PMU_CFG_FLAG_SKIP_MATCH is satisfied, > the code evaluates: > !test_bit(ctr_base + __ffs(ctr_mask), kvpmu->pmc_in_use) > > Here __ffs(0xeb5f) equals 0, so test_bit() receives 0xfffffffffffffffe > as the bit index and attempts to access the corresponding element of > the kvpmu->pmc_in_use, which results in an invalid memory access. This > triggers the following Oops: > Unable to handle kernel paging request at virtual address e3ebffff12abba89 > generic_test_bit include/asm-generic/bitops/generic-non-atomic.h:128 > kvm_riscv_vcpu_pmu_ctr_cfg_match arch/riscv/kvm/vcpu_pmu.c:758 > kvm_sbi_ext_pmu_handler arch/riscv/kvm/vcpu_sbi_pmu.c:49 > kvm_riscv_vcpu_sbi_ecall arch/riscv/kvm/vcpu_sbi.c:608 > kvm_riscv_vcpu_exit arch/riscv/kvm/vcpu_exit.c:240 > > The root cause is that kvm_pmu_validate_counter_mask() does not account > for the case where ctr_base itself is out of range, allowing the > subsequent addition to silently overflow and bypass the check. > > Fix this by explicitly validating ctr_base against kvm_pmu_num_counters() > before performing the addition. > > This bug was found by fuzzing the KVM RISC-V PMU interface. > > Fixes: 0cb74b65d2e5e6 ("RISC-V: KVM: Implement perf support without sampling") > Signed-off-by: Jiakai Xu <jiakaiPeanut@gmail.com> > Signed-off-by: Jiakai Xu <xujiakai2025@iscas.ac.cn> Reviewed-by: Nutty Liu <nutty.liu@hotmail.com> Thanks, Nutty > --- > arch/riscv/kvm/vcpu_pmu.c | 6 ++++-- > 1 file changed, 4 insertions(+), 2 deletions(-) > > diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c > index e873430e596b2..a098a9b417ad8 100644 > --- a/arch/riscv/kvm/vcpu_pmu.c > +++ b/arch/riscv/kvm/vcpu_pmu.c > @@ -266,8 +266,10 @@ static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx, > static int kvm_pmu_validate_counter_mask(struct kvm_pmu *kvpmu, unsigned long ctr_base, > unsigned long ctr_mask) > { > - /* Make sure the we have a valid counter mask requested from the caller */ > - if (!ctr_mask || (ctr_base + __fls(ctr_mask) >= kvm_pmu_num_counters(kvpmu))) > + unsigned long num_ctrs = kvm_pmu_num_counters(kvpmu); > + > + /* Make sure we have a valid counter mask requested from the caller */ > + if (!ctr_mask || ctr_base >= num_ctrs || (ctr_base + __fls(ctr_mask) >= num_ctrs)) > return -EINVAL; > > return 0; _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] RISC-V: KVM: Fix integer overflow in kvm_pmu_validate_counter_mask() 2026-03-19 3:59 [PATCH] RISC-V: KVM: Fix integer overflow in kvm_pmu_validate_counter_mask() Jiakai Xu 2026-03-19 17:39 ` Atish Patra 2026-03-23 8:47 ` Nutty.Liu @ 2026-03-30 8:26 ` Anup Patel 2 siblings, 0 replies; 5+ messages in thread From: Anup Patel @ 2026-03-30 8:26 UTC (permalink / raw) To: Jiakai Xu Cc: kvm-riscv, kvm, linux-kernel, linux-riscv, Albert Ou, Alexandre Ghiti, Andrew Jones, Atish Patra, Palmer Dabbelt, Paul Walmsley, Jiakai Xu On Thu, Mar 19, 2026 at 9:29 AM Jiakai Xu <xujiakai2025@iscas.ac.cn> wrote: > > When a guest initiates an SBI_EXT_PMU_COUNTER_CFG_MATCH call with > ctr_base=0xfffffffffffffffe, ctr_mask=0xeb5f and flags=0x1 > (SBI_PMU_CFG_FLAG_SKIP_MATCH), kvm_riscv_vcpu_pmu_ctr_cfg_match() > first invokes kvm_pmu_validate_counter_mask() to verify whether > ctr_base and ctr_mask are valid, by evaluating: > !ctr_mask || (ctr_base + __fls(ctr_mask) >= kvm_pmu_num_counters(kvpmu)) > > With the above inputs, __fls(0xeb5f) equals 15, and adding 15 to > 0xfffffffffffffffe causes an integer overflow, wrapping around to 13. > Since 13 is less than kvm_pmu_num_counters(), the validation wrongly > succeeds. > > Thereafter, since flags & SBI_PMU_CFG_FLAG_SKIP_MATCH is satisfied, > the code evaluates: > !test_bit(ctr_base + __ffs(ctr_mask), kvpmu->pmc_in_use) > > Here __ffs(0xeb5f) equals 0, so test_bit() receives 0xfffffffffffffffe > as the bit index and attempts to access the corresponding element of > the kvpmu->pmc_in_use, which results in an invalid memory access. This > triggers the following Oops: > Unable to handle kernel paging request at virtual address e3ebffff12abba89 > generic_test_bit include/asm-generic/bitops/generic-non-atomic.h:128 > kvm_riscv_vcpu_pmu_ctr_cfg_match arch/riscv/kvm/vcpu_pmu.c:758 > kvm_sbi_ext_pmu_handler arch/riscv/kvm/vcpu_sbi_pmu.c:49 > kvm_riscv_vcpu_sbi_ecall arch/riscv/kvm/vcpu_sbi.c:608 > kvm_riscv_vcpu_exit arch/riscv/kvm/vcpu_exit.c:240 > > The root cause is that kvm_pmu_validate_counter_mask() does not account > for the case where ctr_base itself is out of range, allowing the > subsequent addition to silently overflow and bypass the check. > > Fix this by explicitly validating ctr_base against kvm_pmu_num_counters() > before performing the addition. > > This bug was found by fuzzing the KVM RISC-V PMU interface. > > Fixes: 0cb74b65d2e5e6 ("RISC-V: KVM: Implement perf support without sampling") > Signed-off-by: Jiakai Xu <jiakaiPeanut@gmail.com> > Signed-off-by: Jiakai Xu <xujiakai2025@iscas.ac.cn> Queued this patch for Linux-7.1 Thanks, Anup > --- > arch/riscv/kvm/vcpu_pmu.c | 6 ++++-- > 1 file changed, 4 insertions(+), 2 deletions(-) > > diff --git a/arch/riscv/kvm/vcpu_pmu.c b/arch/riscv/kvm/vcpu_pmu.c > index e873430e596b2..a098a9b417ad8 100644 > --- a/arch/riscv/kvm/vcpu_pmu.c > +++ b/arch/riscv/kvm/vcpu_pmu.c > @@ -266,8 +266,10 @@ static int pmu_ctr_read(struct kvm_vcpu *vcpu, unsigned long cidx, > static int kvm_pmu_validate_counter_mask(struct kvm_pmu *kvpmu, unsigned long ctr_base, > unsigned long ctr_mask) > { > - /* Make sure the we have a valid counter mask requested from the caller */ > - if (!ctr_mask || (ctr_base + __fls(ctr_mask) >= kvm_pmu_num_counters(kvpmu))) > + unsigned long num_ctrs = kvm_pmu_num_counters(kvpmu); > + > + /* Make sure we have a valid counter mask requested from the caller */ > + if (!ctr_mask || ctr_base >= num_ctrs || (ctr_base + __fls(ctr_mask) >= num_ctrs)) > return -EINVAL; > > return 0; > -- > 2.34.1 > _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-03-30 8:27 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-03-19 3:59 [PATCH] RISC-V: KVM: Fix integer overflow in kvm_pmu_validate_counter_mask() Jiakai Xu 2026-03-19 17:39 ` Atish Patra 2026-03-20 1:02 ` Jiakai Xu 2026-03-23 8:47 ` Nutty.Liu 2026-03-30 8:26 ` Anup Patel
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox