Re: [Patch v5 11/18] perf/x86/intel: Use a dedicated LBR stack for BPF snapshotting
From: Peter Zijlstra
Date: Thu Oct 29 2026 - 06:41:30 EST
On Thu, Oct 29, 2026 at 12:39:07PM +0800, Dapeng Mi wrote:
> BPF LBR snapshotting currently reuses the default LBR stack
> (cpuc->lbr_stack) when storing sampled data. This is unsafe when the
> BPF helper runs in PMI context via bpf_overflow_handler(): it can
> overwrite the cached LBR state for active PEBS LBR events, causing
> incorrect LBR data to be reported to userspace. When the PEBS and BPF
> stacks have different depths, this can also lead to out-of-bounds reads
> when the LBR stack is later exported.
>
> Use a dedicated LBR stack for BPF snapshotting so the BPF path no
> longer clobbers the shared LBR state used by other perf events.
>
> Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
> Fixes: 425507fa5f32 ("perf/x86/intel/lbr: Optimize v4 LBR unfreezing")
> Signed-off-by: Dapeng Mi <dapeng1.mi@xxxxxxxxxxxxxxx>
AMD has the same problem, no?
> ---
> arch/x86/events/intel/core.c | 16 +++++++++++-----
> 1 file changed, 11 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
> index 5eda551cc9f2..482a148916bf 100644
> --- a/arch/x86/events/intel/core.c
> +++ b/arch/x86/events/intel/core.c
> @@ -2819,18 +2819,24 @@ static void intel_pmu_enable_all(int added)
> __intel_pmu_enable_all(false);
> }
>
> +struct lbr_snapshot {
> + struct perf_branch_stack stack;
> + struct perf_branch_entry entries[MAX_LBR_ENTRIES];
> + u64 counters[MAX_LBR_ENTRIES];
> +};
> +static DEFINE_PER_CPU(struct lbr_snapshot, lbr_snapshot);
> +
> static noinline int
> __intel_pmu_snapshot_branch_stack(struct perf_branch_entry *entries,
> unsigned int cnt, unsigned long flags,
> int pmu_enabled, int lbr_enabled)
> {
> - struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
> + struct lbr_snapshot *bpf = this_cpu_ptr(&lbr_snapshot);
>
> - intel_pmu_lbr_read(&cpuc->lbr_stack,
> - cpuc->lbr_entries, cpuc->lbr_counters);
> - cnt = min_t(unsigned int, cnt, cpuc->lbr_stack.nr);
> + intel_pmu_lbr_read(&bpf->stack, bpf->entries, bpf->counters);
> + cnt = min_t(unsigned int, cnt, bpf->stack.nr);
>
> - memcpy(entries, cpuc->lbr_entries,
> + memcpy(entries, bpf->entries,
> sizeof(struct perf_branch_entry) * cnt);
>
> /*
> --
> 2.34.1
>