From: "Mi, Dapeng" <dapeng1.mi@linux.intel.com>
To: sashiko-reviews@lists.linux.dev
Cc: linux-perf-users@vger.kernel.org, bpf@vger.kernel.org
Subject: Re: [Patch v4 1/5] perf/x86: Disable LBR if x86_pmu.lbr_nr exceeds MAX_LBR_ENTRIES
Date: Wed, 21 Oct 2026 14:16:05 +0800 [thread overview]
Message-ID: <e8e0c5e0-46c7-4f34-abff-5f24ceba12f7@linux.intel.com> (raw)
In-Reply-To: <sashiko-outbox-179814@kernel.org>
On 10/21/2026 1:42 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] perf/x86: init_hw_perf_events() disables LBR too late after vendor PMU init
> --
>
> commit c6c1bbb1f4feb929dd247ddd507177ce58d871e1
> Author: Dapeng Mi <dapeng1.mi@linux.intel.com>
>
> perf/x86: Disable LBR if x86_pmu.lbr_nr exceeds MAX_LBR_ENTRIES
>
> This commit disables last branch record support in init_hw_perf_events()
> if x86_pmu.lbr_nr exceeds MAX_LBR_ENTRIES to prevent out-of-bounds
> accesses in the cached branch stack handling path.
>
>> diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c
>> index 4df792b139e05..002a04c149c29 100644
>> --- a/arch/x86/events/core.c
>> +++ b/arch/x86/events/core.c
>> @@ -2645,6 +2645,12 @@ static int __init init_hw_perf_events(void)
>> if (!x86_pmu.config_mask)
>> x86_pmu.config_mask = X86_RAW_EVENT_MASK;
>>
>> + if (x86_pmu.lbr_nr > MAX_LBR_ENTRIES) {
>> + pr_warn("LBR entries %d exceeds max %d, disable LBR.\n",
>> + x86_pmu.lbr_nr, MAX_LBR_ENTRIES);
>> + x86_pmu.lbr_nr = 0;
>> + }
>> +
>> perf_events_lapic_init();
>> register_nmi_handler(NMI_LOCAL, perf_event_nmi_handler, 0, "PMI");
> [Severity: Medium]
> Does zeroing x86_pmu.lbr_nr here in init_hw_perf_events() happen too late,
> after intel_pmu_init() and amd_pmu_init() have already configured hardware
> and driver state using the unvalidated x86_pmu.lbr_nr value?
>
> In arch/x86/events/intel/lbr.c:intel_pmu_arch_lbr_init(), if lbr_nr exceeds
> MAX_LBR_ENTRIES, initialization proceeds instead of taking the clear_arch_lbr
> path:
>
> lbr_nr = fls(eax.split.lbr_depth_mask) * 8;
> if (!lbr_nr)
> goto clear_arch_lbr;
>
> /* Apply the max depth of Arch LBR */
> if (wrmsrq_safe(MSR_ARCH_LBR_DEPTH, lbr_nr))
> goto clear_arch_lbr;
> ...
> x86_pmu.lbr_counters = ecx.split.lbr_counters;
> x86_pmu.lbr_nr = lbr_nr;
>
> if (!!x86_pmu.lbr_counters)
> x86_pmu.flags |= PMU_FL_BR_CNTR | PMU_FL_DYN_CONSTRAINT;
>
> Because clear_arch_lbr is skipped, X86_FEATURE_ARCH_LBR remains enabled,
> MSR_ARCH_LBR_DEPTH is written, pmu->task_ctx_cache is allocated via
> create_lbr_kmem_cache(), and x86_pmu.lbr_ctl_map and static branches are
> configured.
>
> Subsequently, arch/x86/events/intel/lbr.c:reserve_lbr_buffers() checks the
> feature bit and task_ctx_cache rather than x86_pmu.lbr_nr:
>
> if (!cpu_feature_enabled(X86_FEATURE_ARCH_LBR))
> return;
>
> for_each_possible_cpu(cpu) {
> cpuc = per_cpu_ptr(&cpu_hw_events, cpu);
> kmem_cache = x86_get_pmu(cpu)->task_ctx_cache;
> if (!kmem_cache || cpuc->lbr_xsave)
> continue;
>
> cpuc->lbr_xsave = kmem_cache_alloc_node(kmem_cache,
> GFP_KERNEL | __GFP_ZERO,
> cpu_to_node(cpu));
> }
>
> Wouldn't this still allocate per-cpu cpuc->lbr_xsave buffers on hardware
> reservation even after x86_pmu.lbr_nr is set to 0?
>
> Similarly, in arch/x86/events/intel/core.c:lbr_is_visible(), leaving
> PMU_FL_BR_CNTR set in x86_pmu.flags keeps branch_counter_nr and
> branch_counter_width visible in sysfs when x86_pmu.lbr_nr is 0:
>
> /* branches */
> if (i == 0)
> return x86_pmu.lbr_nr ? attr->mode : 0;
>
> return (x86_pmu.flags & PMU_FL_BR_CNTR) ? attr->mode : 0;
>
> In addition, both arch/x86/events/intel/core.c:intel_pmu_init() and
> arch/x86/events/amd/core.c:amd_core_pmu_init() check x86_pmu.lbr_nr before
> init_hw_perf_events() clears it:
>
> if (x86_pmu.lbr_nr) {
> intel_pmu_lbr_init();
>
> pr_cont("%d-deep LBR, ", x86_pmu.lbr_nr);
>
> /* only support branch_stack snapshot for perfmon >= v2 */
> if (x86_pmu.disable_all == intel_pmu_disable_all) {
> if (boot_cpu_has(X86_FEATURE_ARCH_LBR)) {
> static_call_update(perf_snapshot_branch_stack,
> intel_pmu_snapshot_arch_branch_stack);
> } else {
> static_call_update(perf_snapshot_branch_stack,
> intel_pmu_snapshot_branch_stack);
> }
> }
> }
>
> And in amd_core_pmu_init():
>
> if (!amd_pmu_lbr_init()) {
> /* LBR requires flushing on context switch */
> x86_pmu.sched_task = amd_pmu_lbr_sched_task;
> static_call_update(amd_pmu_branch_hw_config, amd_pmu_lbr_hw_config);
> static_call_update(amd_pmu_branch_reset, amd_pmu_lbr_reset);
> static_call_update(amd_pmu_branch_add, amd_pmu_lbr_add);
> static_call_update(amd_pmu_branch_del, amd_pmu_lbr_del);
>
> /* Only support branch_stack snapshot on perfmon v2 */
> if (x86_pmu.handle_irq == amd_pmu_v2_handle_irq)
> static_call_update(perf_snapshot_branch_stack, amd_pmu_v2_snapshot_branch_stack);
> } else if (!amd_brs_init()) {
>
> If bpf_get_branch_snapshot() is later called when x86_pmu.lbr_nr is 0, won't
> the registered perf_snapshot_branch_stack callback still run, manipulate
> branch and global control registers, and unconditionally call
> intel_pmu_enable_all(0) or amd_pmu_v2_enable_all(0)?
>
> Should the MAX_LBR_ENTRIES check be performed before or during the
> vendor-specific initialization routines (such as intel_pmu_lbr_init(),
> intel_pmu_arch_lbr_init(), and amd_pmu_lbr_init()) so that None of the
> hardware state, slab caches, flags, or static calls are enabled when
> lbr_nr is out of range?
The change is good enough. The branch sampling perf event creation is
guarded with x86_pmu.lbr_nr regardless of on Intel or AMD platforms. If
x86_pmu.lbr_nr is 0, then no events with branch sampling can be created
successfully, and if no active LBR event is present, the LBR hardware is
not really enabled.
Since it's a common validation for all x86 vendor platforms, it should be
placed into the x86 common PMU initialization path.
Thanks.
>
next prev parent reply other threads:[~2026-10-21 6:16 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-21 5:07 [Patch v4 0/5] perf/x86: Limit branch snapshots to valid entries Dapeng Mi
2026-10-21 5:07 ` [Patch v4 1/5] perf/x86: Disable LBR if x86_pmu.lbr_nr exceeds MAX_LBR_ENTRIES Dapeng Mi
2026-10-21 5:42 ` sashiko-bot
2026-10-21 6:16 ` Mi, Dapeng [this message]
2026-10-21 5:07 ` [Patch v4 2/5] perf/x86/amd/lbr: Limit branch snapshots to valid entries Dapeng Mi
2026-10-21 5:31 ` sashiko-bot
2026-10-21 5:07 ` [Patch v4 3/5] perf/x86/intel/lbr: Reset the cached LBR stack in intel_pmu_lbr_reset() Dapeng Mi
2026-10-21 5:44 ` sashiko-bot
2026-10-21 5:07 ` [Patch v4 4/5] perf/x86/intel/lbr: Limit branch snapshots to valid entries Dapeng Mi
2026-10-21 5:37 ` sashiko-bot
2026-10-21 5:07 ` [Patch v4 5/5] pef/x86/intel: Always snapshot live hardware LBR state for BPF path Dapeng Mi
2026-10-21 6:05 ` sashiko-bot
2026-10-21 6:53 ` Mi, Dapeng
2026-10-22 6:19 ` Mi, Dapeng
2026-10-21 6:59 ` Mi, Dapeng
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e8e0c5e0-46c7-4f34-abff-5f24ceba12f7@linux.intel.com \
--to=dapeng1.mi@linux.intel.com \
--cc=bpf@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.