@@ -1074,7 +1074,7 @@ int sbi_pmu_ctr_get_info(uint32_t cidx, unsigned long *ctr_info)
int sbi_pmu_event_get_info(unsigned long shmem_phys_lo, unsigned long shmem_phys_hi,
unsigned long num_events, unsigned long flags)
{
- unsigned long shmem_size = num_events * sizeof(struct sbi_pmu_event_info);
+ unsigned long shmem_size;
int i, j, event_type;
struct sbi_pmu_event_info *einfo;
struct sbi_pmu_hart_state *phs = pmu_thishart_state_ptr();
@@ -1089,6 +1089,14 @@ int sbi_pmu_event_get_info(unsigned long shmem_phys_lo, unsigned long shmem_phys
if (!num_events || (shmem_phys_lo & 0xF))
return SBI_ERR_INVALID_PARAM;
+ if (!shmem_phys_lo)
+ return SBI_ERR_INVALID_ADDRESS;
+
+ if (num_events > ((unsigned long)-1) / sizeof(struct sbi_pmu_event_info))
+ return SBI_ERR_INVALID_PARAM;
+
+ shmem_size = num_events * sizeof(struct sbi_pmu_event_info);
+
/*
* On RV32, the M-mode can only access the first 4GB of
* the physical address space because M-mode does not have
sbi_pmu_event_get_info() computes the shared memory size as num_events * sizeof(struct sbi_pmu_event_info) before num_events is validated. The product can wrap, in which case the domain check runs against a truncated size while the loop below still iterates over the original count, that is, past the region that was checked. A shmem_phys_lo of zero is also accepted, which leaves the loop writing at address 0. Check num_events against the largest value that cannot wrap, and reject a zero address, both before the multiplication. Fixes: e4345842168b ("lib: sbi_pmu: Implement SBI PMU event info function") Signed-off-by: liutong <liutong@iscas.ac.cn> --- Previously sent as [PATCH v2 4/6]. Changes in v3: - Rebased onto current master - Commit message reworded; the code is unchanged from v2 - Split into this series lib/sbi/sbi_pmu.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)