Pull perf events fixes from Ingo Molnar: - Fix lock ordering bug found by lockdep in perf_event_wakeup() - Fix uncore counter enumeration on Granite Rapids and Sierra Forest - Fix perf_mmap() refcount bug found by Syzkaller - Fix __perf_event_overflow() vs perf_remove_from_context() race * tag 'perf-urgent-2026-03-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: perf: Fix __perf_event_overflow() vs perf_remove_from_context() race perf/core: Fix refcount bug and potential UAF in perf_mmap perf/x86/intel/uncore: Add per-scheduler IMC CAS count events perf/core: Fix invalid wait context in ctx_sched_in()
Unified · Split
| @@ -6497,6 +6497,32 @@ static struct intel_uncore_type gnr_uncore_ubox = { · 6496 unmodified lines | ||
| 6497 | 6497 | .attr_update = uncore_alias_groups, |
| 6498 | 6498 | }; |
| 6499 | 6499 | |
| 6500 | +static struct uncore_event_desc gnr_uncore_imc_events[] = { | |
| 6501 | + INTEL_UNCORE_EVENT_DESC(clockticks, "event=0x01,umask=0x00"), | |
| 6502 | + INTEL_UNCORE_EVENT_DESC(cas_count_read_sch0, "event=0x05,umask=0xcf"), | |
| 6503 | + INTEL_UNCORE_EVENT_DESC(cas_count_read_sch0.scale, "6.103515625e-5"), | |
| 6504 | + INTEL_UNCORE_EVENT_DESC(cas_count_read_sch0.unit, "MiB"), | |
| 6505 | + INTEL_UNCORE_EVENT_DESC(cas_count_read_sch1, "event=0x06,umask=0xcf"), | |
| 6506 | + INTEL_UNCORE_EVENT_DESC(cas_count_read_sch1.scale, "6.103515625e-5"), | |
| 6507 | + INTEL_UNCORE_EVENT_DESC(cas_count_read_sch1.unit, "MiB"), | |
| 6508 | + INTEL_UNCORE_EVENT_DESC(cas_count_write_sch0, "event=0x05,umask=0xf0"), | |
| 6509 | + INTEL_UNCORE_EVENT_DESC(cas_count_write_sch0.scale, "6.103515625e-5"), | |
| 6510 | + INTEL_UNCORE_EVENT_DESC(cas_count_write_sch0.unit, "MiB"), | |
| 6511 | + INTEL_UNCORE_EVENT_DESC(cas_count_write_sch1, "event=0x06,umask=0xf0"), | |
| 6512 | + INTEL_UNCORE_EVENT_DESC(cas_count_write_sch1.scale, "6.103515625e-5"), | |
| 6513 | + INTEL_UNCORE_EVENT_DESC(cas_count_write_sch1.unit, "MiB"), | |
| 6514 | + { /* end: all zeroes */ }, | |
| 6515 | +}; | |
| 6516 | + | |
| 6517 | +static struct intel_uncore_type gnr_uncore_imc = { | |
| 6518 | + SPR_UNCORE_MMIO_COMMON_FORMAT(), | |
| 6519 | + .name = "imc", | |
| 6520 | + .fixed_ctr_bits = 48, | |
| 6521 | + .fixed_ctr = SNR_IMC_MMIO_PMON_FIXED_CTR, | |
| 6522 | + .fixed_ctl = SNR_IMC_MMIO_PMON_FIXED_CTL, | |
| 6523 | + .event_descs = gnr_uncore_imc_events, | |
| 6524 | +}; | |
| 6525 | + | |
| 6500 | 6526 | static struct intel_uncore_type gnr_uncore_pciex8 = { |
| 6501 | 6527 | SPR_UNCORE_PCI_COMMON_FORMAT(), |
| 6502 | 6528 | .name = "pciex8", |
| @@ -6544,7 +6570,7 @@ static struct intel_uncore_type *gnr_uncores[UNCORE_GNR_NUM_UNCORE_TYPES] = { · 41 unmodified lines | ||
| 6544 | 6570 | NULL, |
| 6545 | 6571 | &spr_uncore_pcu, |
| 6546 | 6572 | &gnr_uncore_ubox, |
| 6547 | − &spr_uncore_imc, | |
| 6573 | + &gnr_uncore_imc, | |
| 6548 | 6574 | NULL, |
| 6549 | 6575 | &gnr_uncore_upi, |
| 6550 | 6576 | NULL, |
| @@ -4138,7 +4138,8 @@ static int merge_sched_in(struct perf_event *event, void *data) · 4137 unmodified lines | ||
| 4138 | 4138 | if (*perf_event_fasync(event)) |
| 4139 | 4139 | event->pending_kill = POLL_ERR; |
| 4140 | 4140 | |
| 4141 | − perf_event_wakeup(event); | |
| 4141 | + event->pending_wakeup = 1; | |
| 4142 | + irq_work_queue(&event->pending_irq); | |
| 4142 | 4143 | } else { |
| 4143 | 4144 | struct perf_cpu_pmu_context *cpc = this_cpc(event->pmu_ctx->pmu); |
| 4144 | 4145 | |
| @@ -7464,28 +7465,28 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) · 3319 unmodified lines | ||
| 7464 | 7465 | ret = perf_mmap_aux(vma, event, nr_pages); |
| 7465 | 7466 | if (ret) |
| 7466 | 7467 | return ret; |
| 7467 | − } | |
| 7468 | 7468 | |
| 7469 | − /* | |
| 7470 | − * Since pinned accounting is per vm we cannot allow fork() to copy our | |
| 7471 | − * vma. | |
| 7472 | − */ | |
| 7473 | − vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP); | |
| 7474 | − vma->vm_ops = &perf_mmap_vmops; | |
| 7469 | + /* | |
| 7470 | + * Since pinned accounting is per vm we cannot allow fork() to copy our | |
| 7471 | + * vma. | |
| 7472 | + */ | |
| 7473 | + vm_flags_set(vma, VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP); | |
| 7474 | + vma->vm_ops = &perf_mmap_vmops; | |
| 7475 | 7475 | |
| 7476 | − mapped = get_mapped(event, event_mapped); | |
| 7477 | − if (mapped) | |
| 7478 | − mapped(event, vma->vm_mm); | |
| 7476 | + mapped = get_mapped(event, event_mapped); | |
| 7477 | + if (mapped) | |
| 7478 | + mapped(event, vma->vm_mm); | |
| 7479 | 7479 | |
| 7480 | − /* | |
| 7481 | − * Try to map it into the page table. On fail, invoke | |
| 7482 | − * perf_mmap_close() to undo the above, as the callsite expects | |
| 7483 | − * full cleanup in this case and therefore does not invoke | |
| 7484 | − * vmops::close(). | |
| 7485 | − */ | |
| 7486 | − ret = map_range(event->rb, vma); | |
| 7487 | − if (ret) | |
| 7488 | − perf_mmap_close(vma); | |
| 7480 | + /* | |
| 7481 | + * Try to map it into the page table. On fail, invoke | |
| 7482 | + * perf_mmap_close() to undo the above, as the callsite expects | |
| 7483 | + * full cleanup in this case and therefore does not invoke | |
| 7484 | + * vmops::close(). | |
| 7485 | + */ | |
| 7486 | + ret = map_range(event->rb, vma); | |
| 7487 | + if (ret) | |
| 7488 | + perf_mmap_close(vma); | |
| 7489 | + } | |
| 7489 | 7490 | |
| 7490 | 7491 | return ret; |
| 7491 | 7492 | } |
| @@ -10776,6 +10777,13 @@ int perf_event_overflow(struct perf_event *event, · 3284 unmodified lines | ||
| 10776 | 10777 | struct perf_sample_data *data, |
| 10777 | 10778 | struct pt_regs *regs) |
| 10778 | 10779 | { |
| 10780 | + /* | |
| 10781 | + * Entry point from hardware PMI, interrupts should be disabled here. | |
| 10782 | + * This serializes us against perf_event_remove_from_context() in | |
| 10783 | + * things like perf_event_release_kernel(). | |
| 10784 | + */ | |
| 10785 | + lockdep_assert_irqs_disabled(); | |
| 10786 | + | |
| 10779 | 10787 | return __perf_event_overflow(event, 1, data, regs); |
| 10780 | 10788 | } |
| 10781 | 10789 | |
| @@ -10852,6 +10860,19 @@ static void perf_swevent_event(struct perf_event *event, u64 nr, · 70 unmodified lines | ||
| 10852 | 10860 | { |
| 10853 | 10861 | struct hw_perf_event *hwc = &event->hw; |
| 10854 | 10862 | |
| 10863 | + /* | |
| 10864 | + * This is: | |
| 10865 | + * - software preempt | |
| 10866 | + * - tracepoint preempt | |
| 10867 | + * - tp_target_task irq (ctx->lock) | |
| 10868 | + * - uprobes preempt/irq | |
| 10869 | + * - kprobes preempt/irq | |
| 10870 | + * - hw_breakpoint irq | |
| 10871 | + * | |
| 10872 | + * Any of these are sufficient to hold off RCU and thus ensure @event | |
| 10873 | + * exists. | |
| 10874 | + */ | |
| 10875 | + lockdep_assert_preemption_disabled(); | |
| 10855 | 10876 | local64_add(nr, &event->count); |
| 10856 | 10877 | |
| 10857 | 10878 | if (!regs) |
| @@ -10860,6 +10881,16 @@ static void perf_swevent_event(struct perf_event *event, u64 nr, · 2 unmodified lines | ||
| 10860 | 10881 | if (!is_sampling_event(event)) |
| 10861 | 10882 | return; |
| 10862 | 10883 | |
| 10884 | + /* | |
| 10885 | + * Serialize against event_function_call() IPIs like normal overflow | |
| 10886 | + * event handling. Specifically, must not allow | |
| 10887 | + * perf_event_release_kernel() -> perf_remove_from_context() to make | |
| 10888 | + * progress and 'release' the event from under us. | |
| 10889 | + */ | |
| 10890 | + guard(irqsave)(); | |
| 10891 | + if (event->state != PERF_EVENT_STATE_ACTIVE) | |
| 10892 | + return; | |
| 10893 | + | |
| 10863 | 10894 | if ((event->attr.sample_type & PERF_SAMPLE_PERIOD) && !event->attr.freq) { |
| 10864 | 10895 | data->period = nr; |
| 10865 | 10896 | return perf_swevent_overflow(event, 1, data, regs); |
| @@ -11358,6 +11389,11 @@ void perf_tp_event(u16 event_type, u64 count, void *record, int entry_size, · 492 unmodified lines | ||
| 11358 | 11389 | struct perf_sample_data data; |
| 11359 | 11390 | struct perf_event *event; |
| 11360 | 11391 | |
| 11392 | + /* | |
| 11393 | + * Per being a tracepoint, this runs with preemption disabled. | |
| 11394 | + */ | |
| 11395 | + lockdep_assert_preemption_disabled(); | |
| 11396 | + | |
| 11361 | 11397 | struct perf_raw_record raw = { |
| 11362 | 11398 | .frag = { |
| 11363 | 11399 | .size = entry_size, |
| @@ -11690,6 +11726,11 @@ void perf_bp_event(struct perf_event *bp, void *data) · 326 unmodified lines | ||
| 11690 | 11726 | struct perf_sample_data sample; |
| 11691 | 11727 | struct pt_regs *regs = data; |
| 11692 | 11728 | |
| 11729 | + /* | |
| 11730 | + * Exception context, will have interrupts disabled. | |
| 11731 | + */ | |
| 11732 | + lockdep_assert_irqs_disabled(); | |
| 11733 | + | |
| 11693 | 11734 | perf_sample_data_init(&sample, bp->attr.bp_addr, 0); |
| 11694 | 11735 | |
| 11695 | 11736 | if (!bp->hw.state && !perf_exclude_event(bp, regs)) |
| @@ -12154,7 +12195,7 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer) · 458 unmodified lines | ||
| 12154 | 12195 | |
| 12155 | 12196 | if (regs && !perf_exclude_event(event, regs)) { |
| 12156 | 12197 | if (!(event->attr.exclude_idle && is_idle_task(current))) |
| 12157 | − if (__perf_event_overflow(event, 1, &data, regs)) | |
| 12198 | + if (perf_event_overflow(event, &data, regs)) | |
| 12158 | 12199 | ret = HRTIMER_NORESTART; |
| 12159 | 12200 | } |
| 12160 | 12201 | |