Re: [Patch v2 5/9] perf/x86/intel: Drop LBR entries whose privilege level mismatches br_sel
From: Peter Zijlstra
Date: Tue Jun 09 2026 - 11:09:24 EST
On Tue, Jun 09, 2026 at 01:02:18PM +0800, Dapeng Mi wrote:
> Before Arch LBR gained CPL filtering support, a user-only branch stack
> could still contain kernel addresses. As a result, kernel branch records
> may be exposed to user space even when PERF_SAMPLE_BRANCH_USER is
> requested.
>
> For example, on Intel Tiger Lake, the following command can still report
> SYSRET/ERET entries with kernel-space from addresses:
>
> ```
> $./perf record -e cycles:p -o - --branch-filter any,save_type,u -- \
> ./perf bench syscall basic --loop 1000 | \
> ./perf script -i - --fields brstack|tr ' ' '\n'| \
> grep -E '0x[89a-f][0-9a-f]{15}'
>
> Total time: 0.000 [sec]
>
> 0.219000 usecs/op
> 4,566,210 ops/sec
> [ perf record: Woken up 1 times to write data ]
> [ perf record: Captured and wrote 0.551 MB - ]
> 0xffffffff93c001c8/0x7f12a2b1d647/P/-/-/16959/SYSRET/-
> 0xffffffff93c001c8/0x7f12a2b1d5c2/P/-/-/17535/SYSRET/-
> 0xffffffff93c01928/0x7f12a2861000/P/-/-/6719/ERET/-
> 0xffffffff93c01928/0x7f12a297a000/P/-/-/8575/ERET/-
> ```
>
> The problem is that intel_pmu_lbr_filter() does not fully validate the
> privilege level of sampled entries. It filters some mismatches based on
> the branch type and the to address, but it does not reject entries whose
> from address violates the requested branch privilege filter.
>
> Fix this by extending software filtering to validate both from and to
> addresses against br_sel. Any LBR entry whose privilege level does not
> match the requested user/kernel filter is dropped. This prevents kernel
> addresses from appearing in user-only branch stacks, and likewise drops
> user entries from kernel-only stacks.
>
> Cc: stable@xxxxxxxxxxxxxxx
> Reported-by: Ian Rogers <irogers@xxxxxxxxxx>
> Fixes: 47125db27e47 ("perf/x86/intel/lbr: Support Architectural LBR")
> Signed-off-by: Dapeng Mi <dapeng1.mi@xxxxxxxxxxxxxxx>
> ---
> arch/x86/events/intel/lbr.c | 14 +++++++++++---
> 1 file changed, 11 insertions(+), 3 deletions(-)
>
> diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c
> index d4c0ed85e1fb..807ce903c972 100644
> --- a/arch/x86/events/intel/lbr.c
> +++ b/arch/x86/events/intel/lbr.c
> @@ -1212,7 +1212,7 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc)
> {
> u64 from, to;
> int br_sel = cpuc->br_sel;
> - int i, j, type, to_plm;
> + int i, j, type, to_plm, from_plm;
> bool compress = false;
>
> /* if sampling all branches, then nothing to filter */
If there, might as well order those variables in reverse xmas.