* [PATCH 1/2] perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter()
@ 2026-04-14 2:14 Dapeng Mi
2026-04-14 2:14 ` [PATCH 2/2] perf/x86/intel: Fix kernel address leakages in LBR stack Dapeng Mi
2026-04-29 20:58 ` [PATCH 1/2] perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter() Chen, Zide
0 siblings, 2 replies; 6+ messages in thread
From: Dapeng Mi @ 2026-04-14 2:14 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin,
Andi Kleen, Eranian Stephane
Cc: linux-kernel, linux-perf-users, Dapeng Mi, Zide Chen,
Falcon Thomas, Xudong Hao, Dapeng Mi, stable
In intel_pmu_lbr_filter(), the 'type' variable is bitwise ORed with
'to_plm' (which contains X86_BR_USER and/or X86_BR_KERNEL bits). Because
of this, 'type' can never equal X86_BR_NONE (0) after the assignment.
As a result, the subsequent check 'if (type == X86_BR_NONE)' is dead code
and the entries with X86_BR_NONE type would not be skipped eventually.
Correct this by masking out the X86_BR_KERNEL and X86_BR_USER bits
before performing the X86_BR_NONE comparison.
Cc: stable@vger.kernel.org
Fixes: 47125db27e47 ("perf/x86/intel/lbr: Support Architectural LBR")
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
---
arch/x86/events/intel/lbr.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c
index 72f2adcda7c6..16977e4c6f8a 100644
--- a/arch/x86/events/intel/lbr.c
+++ b/arch/x86/events/intel/lbr.c
@@ -1245,7 +1245,7 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc)
}
/* if type does not correspond, then discard */
- if (type == X86_BR_NONE || (br_sel & type) != type) {
+ if ((type & ~X86_BR_PLM) == X86_BR_NONE || (br_sel & type) != type) {
cpuc->lbr_entries[i].from = 0;
compress = true;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/2] perf/x86/intel: Fix kernel address leakages in LBR stack 2026-04-14 2:14 [PATCH 1/2] perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter() Dapeng Mi @ 2026-04-14 2:14 ` Dapeng Mi 2026-04-29 20:57 ` Chen, Zide 2026-04-29 20:58 ` [PATCH 1/2] perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter() Chen, Zide 1 sibling, 1 reply; 6+ messages in thread From: Dapeng Mi @ 2026-04-14 2:14 UTC (permalink / raw) To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin, Andi Kleen, Eranian Stephane Cc: linux-kernel, linux-perf-users, Dapeng Mi, Zide Chen, Falcon Thomas, Xudong Hao, Dapeng Mi, stable Prior to the arch-LBR which supports CPL filtering, the kernel address could be leaked to user space even PERF_SAMPLE_BRANCH_USER is required. e.g., run below command on Intel Tigerlake platform, ``` $./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 SYSRET/ERET branch calls are found the in the LBR stack, whose "from" addresses are obviously kernel address. Currently intel_pmu_lbr_filter() only filters out the LBR entries whose "to" address is a kernel address but doesn't check the "from" address. To fix the issue, extend the software filtering to both "from" and "to" addresses. Cc: stable@vger.kernel.org Reported-by: Ian Rogers <irogers@google.com> Fixes: 47125db27e47 ("perf/x86/intel/lbr: Support Architectural LBR") Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com> --- arch/x86/events/intel/lbr.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index 16977e4c6f8a..deef81c16571 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 */ @@ -1244,8 +1244,15 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc) type |= X86_BR_NO_TX; } - /* if type does not correspond, then discard */ - if ((type & ~X86_BR_PLM) == X86_BR_NONE || (br_sel & type) != type) { + from_plm = kernel_ip(from) ? X86_BR_KERNEL : X86_BR_USER; + /* + * If type does not correspond, then discard. + * Especially filter out the entries whose from or to address + * is a kernel address while only X86_BR_USER is set. This prevents + * kernel address from being leaked into a user-space-only LBR stack. + */ + if ((type & ~X86_BR_PLM) == X86_BR_NONE || (br_sel & type) != type || + (!(br_sel & X86_BR_KERNEL) && (from_plm & X86_BR_KERNEL))) { cpuc->lbr_entries[i].from = 0; compress = true; } -- 2.34.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] perf/x86/intel: Fix kernel address leakages in LBR stack 2026-04-14 2:14 ` [PATCH 2/2] perf/x86/intel: Fix kernel address leakages in LBR stack Dapeng Mi @ 2026-04-29 20:57 ` Chen, Zide 2026-04-30 1:22 ` Mi, Dapeng 0 siblings, 1 reply; 6+ messages in thread From: Chen, Zide @ 2026-04-29 20:57 UTC (permalink / raw) To: Dapeng Mi, Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin, Andi Kleen, Eranian Stephane Cc: linux-kernel, linux-perf-users, Dapeng Mi, Falcon Thomas, Xudong Hao, stable On 4/13/2026 7:14 PM, Dapeng Mi wrote: > Prior to the arch-LBR which supports CPL filtering, the kernel address > could be leaked to user space even PERF_SAMPLE_BRANCH_USER is required. This sounds correct to catch these branches, since only the target CPL counts. The software filtering is implemented to match the HW behavior: Legacy LBR. CPL_EQ_0: When set, do not capture branches ending in ring 0 CPL_NEQ_0: When set, do not capture branches ending in ring >0 Arch LBR: For operations which change the CPL, the operation is recorded in LBRs only if the CPL at the end of the operation is enabled for LBR recording. In cases where the CPL transitions from a value that is filtered out to a value that is enabled for LBR recording, the FROM_IP address for the recorded CPL transition branch or event will be 0FFFFFFFFFFFFFFFFH. > > e.g., run below command on Intel Tigerlake platform, > > ``` > $./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/- > ``` Thus, filtering with USR=1, it's correct that ERET/SYSRET show up in the above command running on TG because the target CPL is 3. However, the from address should be hidden with 0xFFFFFFFFFFFFFFFF. Instead, this appears a bug on platforms with CPL filtering (SPR, etc.) that filters out these branches. This is because for ERET/SYSRET, the br_type is 8 (OTHER_BRANCH), so even on arch LBR, it gets the type from branch_type() which incorrectly translates type 8 to 0 (X86_BR_NONE). Therefore, something needs to be done in get_branch_type() to handle OTHER_BRANCH. > The SYSRET/ERET branch calls are found the in the LBR stack, whose "from" > addresses are obviously kernel address. > > Currently intel_pmu_lbr_filter() only filters out the LBR entries whose > "to" address is a kernel address but doesn't check the "from" address. > > To fix the issue, extend the software filtering to both "from" and "to" > addresses. > > Cc: stable@vger.kernel.org > Reported-by: Ian Rogers <irogers@google.com> > Fixes: 47125db27e47 ("perf/x86/intel/lbr: Support Architectural LBR") > Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com> > --- > arch/x86/events/intel/lbr.c | 13 ++++++++++--- > 1 file changed, 10 insertions(+), 3 deletions(-) > > diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c > index 16977e4c6f8a..deef81c16571 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 */ > @@ -1244,8 +1244,15 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc) > type |= X86_BR_NO_TX; > } > > - /* if type does not correspond, then discard */ > - if ((type & ~X86_BR_PLM) == X86_BR_NONE || (br_sel & type) != type) { > + from_plm = kernel_ip(from) ? X86_BR_KERNEL : X86_BR_USER; > + /* > + * If type does not correspond, then discard. > + * Especially filter out the entries whose from or to address > + * is a kernel address while only X86_BR_USER is set. This prevents > + * kernel address from being leaked into a user-space-only LBR stack. > + */ > + if ((type & ~X86_BR_PLM) == X86_BR_NONE || (br_sel & type) != type || > + (!(br_sel & X86_BR_KERNEL) && (from_plm & X86_BR_KERNEL))) { > cpuc->lbr_entries[i].from = 0; > compress = true; > } ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/2] perf/x86/intel: Fix kernel address leakages in LBR stack 2026-04-29 20:57 ` Chen, Zide @ 2026-04-30 1:22 ` Mi, Dapeng 0 siblings, 0 replies; 6+ messages in thread From: Mi, Dapeng @ 2026-04-30 1:22 UTC (permalink / raw) To: Chen, Zide, Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin, Andi Kleen, Eranian Stephane Cc: linux-kernel, linux-perf-users, Dapeng Mi, Falcon Thomas, Xudong Hao, stable On 4/30/2026 4:57 AM, Chen, Zide wrote: > > On 4/13/2026 7:14 PM, Dapeng Mi wrote: >> Prior to the arch-LBR which supports CPL filtering, the kernel address >> could be leaked to user space even PERF_SAMPLE_BRANCH_USER is required. > This sounds correct to catch these branches, since only the target CPL > counts. The software filtering is implemented to match the HW behavior: > > Legacy LBR. > CPL_EQ_0: When set, do not capture branches ending in ring 0 > CPL_NEQ_0: When set, do not capture branches ending in ring >0 > > Arch LBR: > For operations which change the CPL, the operation is recorded in LBRs > only if the CPL at the end of the operation is enabled for LBR > recording. In cases where the CPL transitions from a value that is > filtered out to a value that is enabled for LBR > recording, the FROM_IP address for the recorded CPL transition branch or > event will be 0FFFFFFFFFFFFFFFFH. Yes, this is exactly what HW does. > >> e.g., run below command on Intel Tigerlake platform, >> >> ``` >> $./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/- >> ``` > Thus, filtering with USR=1, it's correct that ERET/SYSRET show up in the > above command running on TG because the target CPL is 3. However, the > from address should be hidden with 0xFFFFFFFFFFFFFFFF. Hmm, in theory forcing the "from" IP to 0xFFFFFFFFFFFFFFFF seems a better idea, don't lose SYSRET/ERET trace and no kernel address leakage as well. It works for legacy LBR, but arch-LBR HW already forces the "from" IP to 0xFFFFFFFFFFFFFFFF , SW has no way to figure out the real branch type, so the branch type has to be converted X86_BR_NONE which leads to this entry is dropped. Beside, I'm not sure if this would break current test case. @Ian, how's your idea on this? > > Instead, this appears a bug on platforms with CPL filtering (SPR, etc.) > that filters out these branches. This is because for ERET/SYSRET, the > br_type is 8 (OTHER_BRANCH), so even on arch LBR, it gets the type from > branch_type() which incorrectly translates type 8 to 0 (X86_BR_NONE). As above explained, this doesn't work for arch-LBR. Thanks. > > Therefore, something needs to be done in get_branch_type() to handle > OTHER_BRANCH. > >> The SYSRET/ERET branch calls are found the in the LBR stack, whose "from" >> addresses are obviously kernel address. >> >> Currently intel_pmu_lbr_filter() only filters out the LBR entries whose >> "to" address is a kernel address but doesn't check the "from" address. >> >> To fix the issue, extend the software filtering to both "from" and "to" >> addresses. >> >> Cc: stable@vger.kernel.org >> Reported-by: Ian Rogers <irogers@google.com> >> Fixes: 47125db27e47 ("perf/x86/intel/lbr: Support Architectural LBR") >> Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com> >> --- >> arch/x86/events/intel/lbr.c | 13 ++++++++++--- >> 1 file changed, 10 insertions(+), 3 deletions(-) >> >> diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c >> index 16977e4c6f8a..deef81c16571 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 */ >> @@ -1244,8 +1244,15 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc) >> type |= X86_BR_NO_TX; >> } >> >> - /* if type does not correspond, then discard */ >> - if ((type & ~X86_BR_PLM) == X86_BR_NONE || (br_sel & type) != type) { >> + from_plm = kernel_ip(from) ? X86_BR_KERNEL : X86_BR_USER; >> + /* >> + * If type does not correspond, then discard. >> + * Especially filter out the entries whose from or to address >> + * is a kernel address while only X86_BR_USER is set. This prevents >> + * kernel address from being leaked into a user-space-only LBR stack. >> + */ >> + if ((type & ~X86_BR_PLM) == X86_BR_NONE || (br_sel & type) != type || >> + (!(br_sel & X86_BR_KERNEL) && (from_plm & X86_BR_KERNEL))) { >> cpuc->lbr_entries[i].from = 0; >> compress = true; >> } ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter() 2026-04-14 2:14 [PATCH 1/2] perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter() Dapeng Mi 2026-04-14 2:14 ` [PATCH 2/2] perf/x86/intel: Fix kernel address leakages in LBR stack Dapeng Mi @ 2026-04-29 20:58 ` Chen, Zide 2026-04-30 0:42 ` Mi, Dapeng 1 sibling, 1 reply; 6+ messages in thread From: Chen, Zide @ 2026-04-29 20:58 UTC (permalink / raw) To: Dapeng Mi, Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin, Andi Kleen, Eranian Stephane Cc: linux-kernel, linux-perf-users, Dapeng Mi, Falcon Thomas, Xudong Hao, stable On 4/13/2026 7:14 PM, Dapeng Mi wrote: > In intel_pmu_lbr_filter(), the 'type' variable is bitwise ORed with > 'to_plm' (which contains X86_BR_USER and/or X86_BR_KERNEL bits). Because > of this, 'type' can never equal X86_BR_NONE (0) after the assignment. Nit: In legacy LBR case, it could if get_branch_type() returns X86_BR_NONE. > > As a result, the subsequent check 'if (type == X86_BR_NONE)' is dead code > and the entries with X86_BR_NONE type would not be skipped eventually. > > Correct this by masking out the X86_BR_KERNEL and X86_BR_USER bits > before performing the X86_BR_NONE comparison. > > Cc: stable@vger.kernel.org > Fixes: 47125db27e47 ("perf/x86/intel/lbr: Support Architectural LBR") > Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com> > --- > arch/x86/events/intel/lbr.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c > index 72f2adcda7c6..16977e4c6f8a 100644 > --- a/arch/x86/events/intel/lbr.c > +++ b/arch/x86/events/intel/lbr.c > @@ -1245,7 +1245,7 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc) > } > > /* if type does not correspond, then discard */ > - if (type == X86_BR_NONE || (br_sel & type) != type) { > + if ((type & ~X86_BR_PLM) == X86_BR_NONE || (br_sel & type) != type) { > cpuc->lbr_entries[i].from = 0; > compress = true; > } ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/2] perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter() 2026-04-29 20:58 ` [PATCH 1/2] perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter() Chen, Zide @ 2026-04-30 0:42 ` Mi, Dapeng 0 siblings, 0 replies; 6+ messages in thread From: Mi, Dapeng @ 2026-04-30 0:42 UTC (permalink / raw) To: Chen, Zide, Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim, Ian Rogers, Adrian Hunter, Alexander Shishkin, Andi Kleen, Eranian Stephane Cc: linux-kernel, linux-perf-users, Dapeng Mi, Falcon Thomas, Xudong Hao, stable On 4/30/2026 4:58 AM, Chen, Zide wrote: > > On 4/13/2026 7:14 PM, Dapeng Mi wrote: >> In intel_pmu_lbr_filter(), the 'type' variable is bitwise ORed with >> 'to_plm' (which contains X86_BR_USER and/or X86_BR_KERNEL bits). Because >> of this, 'type' can never equal X86_BR_NONE (0) after the assignment. > Nit: In legacy LBR case, it could if get_branch_type() returns X86_BR_NONE. Yeah, it's correct and need to change the description slightly. Thanks. > >> As a result, the subsequent check 'if (type == X86_BR_NONE)' is dead code >> and the entries with X86_BR_NONE type would not be skipped eventually. >> >> Correct this by masking out the X86_BR_KERNEL and X86_BR_USER bits >> before performing the X86_BR_NONE comparison. >> >> Cc: stable@vger.kernel.org >> Fixes: 47125db27e47 ("perf/x86/intel/lbr: Support Architectural LBR") >> Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com> >> --- >> arch/x86/events/intel/lbr.c | 2 +- >> 1 file changed, 1 insertion(+), 1 deletion(-) >> >> diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c >> index 72f2adcda7c6..16977e4c6f8a 100644 >> --- a/arch/x86/events/intel/lbr.c >> +++ b/arch/x86/events/intel/lbr.c >> @@ -1245,7 +1245,7 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc) >> } >> >> /* if type does not correspond, then discard */ >> - if (type == X86_BR_NONE || (br_sel & type) != type) { >> + if ((type & ~X86_BR_PLM) == X86_BR_NONE || (br_sel & type) != type) { >> cpuc->lbr_entries[i].from = 0; >> compress = true; >> } ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-04-30 1:22 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-04-14 2:14 [PATCH 1/2] perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter() Dapeng Mi 2026-04-14 2:14 ` [PATCH 2/2] perf/x86/intel: Fix kernel address leakages in LBR stack Dapeng Mi 2026-04-29 20:57 ` Chen, Zide 2026-04-30 1:22 ` Mi, Dapeng 2026-04-29 20:58 ` [PATCH 1/2] perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter() Chen, Zide 2026-04-30 0:42 ` Mi, Dapeng
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox