Re: [PATCH v4 03/11] perf/cxl: Fix the counter overflow delta fixup

[email protected] Wed, 05 Aug 2026 16:07:47 +0000
Newsgroups org.kernel.vger.linux-perf-users
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Unvalidated `counter_width` from the CXL PMU capability register causes undefined behavior in `GENMASK_ULL`.
--

--- Patch [3]: [PATCH v4 03/11] perf/cxl: Fix the counter overflow delta fixup ---
commit 6424601c16fd758ca929ead4bf2082b98255eee8
Author: Dave Jiang <[email protected]>

perf/cxl: Fix the counter overflow delta fixup

This commit fixes the counter overflow delta fixup by conditioning the fixup
on new_cnt >= prev_cnt instead of relying on the overflow status alone. It
also uses mask + 1 for the period to avoid undefined behavior with a 64-bit
counter width shift.

Closes: https://sashiko.dev/#/patchset/[email protected]?part=1

> --- a/drivers/perf/cxl_pmu.c
> +++ b/drivers/perf/cxl_pmu.c

[ ... ]

> @@ -697,12 +697,16 @@ static void __cxl_pmu_read(struct perf_event *event, bool overflow)
>  	} while (local64_cmpxchg(&hwc->prev_count, prev_cnt, new_cnt) != prev_cnt);
>  
>  	/*
> -	 * If we know an overflow occur then take that into account.
> -	 * Note counter is not reset as that would lose events
> +	 * The mask discards the bit that says the counter wrapped, so a delta of
> +	 * one whole period reads back as 0 - the same as no events at all. Only
> +	 * the overflow status separates them, and new_cnt >= prev_cnt is that
> +	 * case, so add the period back. mask + 1 is 2^counter_width, which comes
> +	 * out as 0 for a 64-bit counter and avoids an undefined 1 << 64.
>  	 */
> -	delta = (new_cnt - prev_cnt) & GENMASK_ULL(info->counter_width - 1, 0);
> -	if (overflow && delta < GENMASK_ULL(info->counter_width - 1, 0))
> -		delta += (1UL << info->counter_width);
> +	mask = GENMASK_ULL(info->counter_width - 1, 0);

[Severity: High]
This isn't a bug introduced by this patch, but could this macro expansion
result in undefined behavior if the hardware provides an invalid counter
width?

The counter_width is extracted directly from a hardware capability register
during initialization:

drivers/perf/cxl_pmu.c:cxl_pmu_parse_caps() {
    ...
    info->counter_width = FIELD_GET(CXL_PMU_CAP_COUNTER_WIDTH_MSK, val);
    ...
}

If a faulty or malicious CXL device provides a counter_width of 0 or greater
than 64, the GENMASK_ULL() macro here in __cxl_pmu_read() will evaluate with
a negative or out-of-bounds shift amount. Since GENMASK_ULL(h, l) produces
undefined behavior when h < l or h >= 64, this could trigger a kernel splat
under UBSAN and potentially lead to a panic.

Should we validate the capability register bounds when parsing it to protect
against untrusted MMIO input?

> +	delta = (new_cnt - prev_cnt) & mask;
> +	if (overflow && new_cnt >= prev_cnt)
> +		delta += mask + 1;
>  
>  	local64_add(delta, &event->count);
>  }

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=3