public inbox for linux-perf-users@vger.kernel.org
 help / color / mirror / Atom feed
* [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-14  2:53 ` [PATCH 1/2] perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter() sashiko-bot
  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-14  3:16   ` sashiko-bot
  2026-04-14  2:53 ` [PATCH 1/2] perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter() sashiko-bot
  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 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-14  2:53 ` sashiko-bot
  2026-04-14  3:00   ` Mi, Dapeng
  1 sibling, 1 reply; 6+ messages in thread
From: sashiko-bot @ 2026-04-14  2:53 UTC (permalink / raw)
  To: Dapeng Mi; +Cc: linux-perf-users

Sashiko AI review found 1 potential issue(s):
- [Medium] Meaningful code and commit message mismatch due to a false premise
--

commit 98c2839085a2b609f94d9f3f338217d29525fd08
Author: Dapeng Mi <dapeng1.mi@linux.intel.com>

perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter()

This commit modifies the branch filter logic to mask out privilege level
bits before checking if a branch type is X86_BR_NONE.

> 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.

Is this description entirely accurate? 

Looking at intel_pmu_lbr_filter(), the bitwise OR with to_plm only happens
in the X86_FEATURE_ARCH_LBR path:

intel_pmu_lbr_filter() {
    ...
    if (static_cpu_has(X86_FEATURE_ARCH_LBR) &&
        type <= ARCH_LBR_BR_TYPE_KNOWN_MAX) {
        to_plm = kernel_ip(to) ? X86_BR_KERNEL : X86_BR_USER;
        type = arch_lbr_br_type_map[type] | to_plm;
    } else
        type = branch_type(from, to, cpuc->lbr_entries[i].abort);
    ...
}

In the software fallback path, type is assigned the result of branch_type().
If branch_type() cannot decode the branch and returns X86_BR_NONE (0),
wouldn't type evaluate to exactly X86_BR_NONE without any to_plm bits set?

> diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c
> index 72f2adcda7c68..16977e4c6f8a5 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) {

While masking out ~X86_BR_PLM doesn't appear to break the software fallback
behavior since (0 & ~X86_BR_PLM) == 0, the original check for X86_BR_NONE
appears to have been functional and necessary for that path.

Could the commit message be updated to clarify that the check was not actually
dead code for the software fallback path?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260414021440.928068-1-dapeng1.mi@linux.intel.com?part=1

^ 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:53 ` [PATCH 1/2] perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter() sashiko-bot
@ 2026-04-14  3:00   ` Mi, Dapeng
  0 siblings, 0 replies; 6+ messages in thread
From: Mi, Dapeng @ 2026-04-14  3:00 UTC (permalink / raw)
  To: sashiko; +Cc: linux-perf-users


On 4/14/2026 10:53 AM, sashiko-bot@kernel.org wrote:
> Sashiko AI review found 1 potential issue(s):
> - [Medium] Meaningful code and commit message mismatch due to a false premise
> --
>
> commit 98c2839085a2b609f94d9f3f338217d29525fd08
> Author: Dapeng Mi <dapeng1.mi@linux.intel.com>
>
> perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter()
>
> This commit modifies the branch filter logic to mask out privilege level
> bits before checking if a branch type is X86_BR_NONE.
>
>> 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.
> Is this description entirely accurate? 
>
> Looking at intel_pmu_lbr_filter(), the bitwise OR with to_plm only happens
> in the X86_FEATURE_ARCH_LBR path:
>
> intel_pmu_lbr_filter() {
>     ...
>     if (static_cpu_has(X86_FEATURE_ARCH_LBR) &&
>         type <= ARCH_LBR_BR_TYPE_KNOWN_MAX) {
>         to_plm = kernel_ip(to) ? X86_BR_KERNEL : X86_BR_USER;
>         type = arch_lbr_br_type_map[type] | to_plm;
>     } else
>         type = branch_type(from, to, cpuc->lbr_entries[i].abort);
>     ...
> }
>
> In the software fallback path, type is assigned the result of branch_type().
> If branch_type() cannot decode the branch and returns X86_BR_NONE (0),
> wouldn't type evaluate to exactly X86_BR_NONE without any to_plm bits set?

No, the branch_type() would bitwise ored the to_plm at last as below code
shows.

```

/*
     * branch priv level determined by target as
     * is done by HW when LBR_SELECT is implemented
     */
    if (ret != X86_BR_NONE)
        ret |= to_plm;

```

Thanks.


>
>> diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c
>> index 72f2adcda7c68..16977e4c6f8a5 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) {
> While masking out ~X86_BR_PLM doesn't appear to break the software fallback
> behavior since (0 & ~X86_BR_PLM) == 0, the original check for X86_BR_NONE
> appears to have been functional and necessary for that path.
>
> Could the commit message be updated to clarify that the check was not actually
> dead code for the software fallback path?
>

^ 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-14  2:14 ` [PATCH 2/2] perf/x86/intel: Fix kernel address leakages in LBR stack Dapeng Mi
@ 2026-04-14  3:16   ` sashiko-bot
  2026-04-14  5:41     ` Mi, Dapeng
  0 siblings, 1 reply; 6+ messages in thread
From: sashiko-bot @ 2026-04-14  3:16 UTC (permalink / raw)
  To: Dapeng Mi; +Cc: linux-perf-users

Sashiko AI review found 1 potential issue(s):
- [High] The patch addresses kernel address leakage in Intel's LBR software filter but overlooks identical vulnerabilities in AMD's LBR and BRS software filters.
--

commit 8dbb741871f5824e6032a6a5fa35f5db78494ff9
Author: Dapeng Mi <dapeng1.mi@linux.intel.com>

perf/x86/intel: Fix kernel address leakages in LBR stack

This commit fixes a kernel address leakage in the Intel LBR stack by extending
the software filtering to check both the source and destination addresses.
Prior to this change, kernel-to-user branches like SYSRET could leak kernel
addresses to user space even when PERF_SAMPLE_BRANCH_USER was requested.

> diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c
> index 16977e4c6f8a5..deef81c16571a 100644
> --- a/arch/x86/events/intel/lbr.c
> +++ b/arch/x86/events/intel/lbr.c
[ ... ]
> @@ -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;
>  		}

This patch successfully addresses the kernel address leakage in Intel's LBR
software filter, but does it leave AMD platforms exposed to the same KASLR
bypass?

Looking at arch/x86/events/amd/lbr.c, amd_pmu_lbr_filter() appears to classify
branch privilege levels based exclusively on the destination address via
branch_type_fused(). Does this mean it classifies kernel-to-user branches as
user-space and leaks the source kernel address?

Similarly in arch/x86/events/amd/brs.c, amd_brs_drain() filters branches
using amd_brs_match_plm() which explicitly checks only kernel_ip(to). Would
this also blindly accept the branch and log the source kernel address?

Should equivalent privilege level checks for the source address be added to
the AMD routines to fully resolve the issue across platforms?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260414021440.928068-1-dapeng1.mi@linux.intel.com?part=2

^ 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-14  3:16   ` sashiko-bot
@ 2026-04-14  5:41     ` Mi, Dapeng
  0 siblings, 0 replies; 6+ messages in thread
From: Mi, Dapeng @ 2026-04-14  5:41 UTC (permalink / raw)
  To: sashiko; +Cc: linux-perf-users


On 4/14/2026 11:16 AM, sashiko-bot@kernel.org wrote:
> Sashiko AI review found 1 potential issue(s):
> - [High] The patch addresses kernel address leakage in Intel's LBR software filter but overlooks identical vulnerabilities in AMD's LBR and BRS software filters.
> --
>
> commit 8dbb741871f5824e6032a6a5fa35f5db78494ff9
> Author: Dapeng Mi <dapeng1.mi@linux.intel.com>
>
> perf/x86/intel: Fix kernel address leakages in LBR stack
>
> This commit fixes a kernel address leakage in the Intel LBR stack by extending
> the software filtering to check both the source and destination addresses.
> Prior to this change, kernel-to-user branches like SYSRET could leak kernel
> addresses to user space even when PERF_SAMPLE_BRANCH_USER was requested.
>
>> diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c
>> index 16977e4c6f8a5..deef81c16571a 100644
>> --- a/arch/x86/events/intel/lbr.c
>> +++ b/arch/x86/events/intel/lbr.c
> [ ... ]
>> @@ -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;
>>  		}
> This patch successfully addresses the kernel address leakage in Intel's LBR
> software filter, but does it leave AMD platforms exposed to the same KASLR
> bypass?
>
> Looking at arch/x86/events/amd/lbr.c, amd_pmu_lbr_filter() appears to classify
> branch privilege levels based exclusively on the destination address via
> branch_type_fused(). Does this mean it classifies kernel-to-user branches as
> user-space and leaks the source kernel address?
>
> Similarly in arch/x86/events/amd/brs.c, amd_brs_drain() filters branches
> using amd_brs_match_plm() which explicitly checks only kernel_ip(to). Would
> this also blindly accept the branch and log the source kernel address?
>
> Should equivalent privilege level checks for the source address be added to
> the AMD routines to fully resolve the issue across platforms?

AMD guys have known the issue, suppose they would post the fix in a
separate patch. Thanks.


>

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-04-14  5:41 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-14  3:16   ` sashiko-bot
2026-04-14  5:41     ` Mi, Dapeng
2026-04-14  2:53 ` [PATCH 1/2] perf/x86/intel: Fix redundant branch type check in intel_pmu_lbr_filter() sashiko-bot
2026-04-14  3:00   ` Mi, Dapeng

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox