Commit c3bf8a14 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'perf_urgent_for_v5.17_rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf fixes from Borislav Petkov:

 - Intel/PT: filters could crash the kernel

 - Intel: default disable the PMU for SMM, some new-ish EFI firmware has
   started using CPL3 and the PMU CPL filters don't discriminate against
   SMM, meaning that CPL3 (userspace only) events now also count EFI/SMM
   cycles.

 - Fixup for perf_event_attr::sig_data

* tag 'perf_urgent_for_v5.17_rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf/x86/intel/pt: Fix crash with stop filters in single-range mode
  perf: uapi: Document perf_event_attr::sig_data truncation on 32 bit architectures
  selftests/perf_events: Test modification of perf_event_attr::sig_data
  perf: Copy perf_event_attr::sig_data on modification
  x86/perf: Default set FREEZE_ON_SMI for all
parents aeabe1e0 1d909345
...@@ -4703,6 +4703,19 @@ static __initconst const struct x86_pmu intel_pmu = { ...@@ -4703,6 +4703,19 @@ static __initconst const struct x86_pmu intel_pmu = {
.lbr_read = intel_pmu_lbr_read_64, .lbr_read = intel_pmu_lbr_read_64,
.lbr_save = intel_pmu_lbr_save, .lbr_save = intel_pmu_lbr_save,
.lbr_restore = intel_pmu_lbr_restore, .lbr_restore = intel_pmu_lbr_restore,
/*
* SMM has access to all 4 rings and while traditionally SMM code only
* ran in CPL0, 2021-era firmware is starting to make use of CPL3 in SMM.
*
* Since the EVENTSEL.{USR,OS} CPL filtering makes no distinction
* between SMM or not, this results in what should be pure userspace
* counters including SMM data.
*
* This is a clear privilege issue, therefore globally disable
* counting SMM by default.
*/
.attr_freeze_on_smi = 1,
}; };
static __init void intel_clovertown_quirk(void) static __init void intel_clovertown_quirk(void)
......
...@@ -897,8 +897,9 @@ static void pt_handle_status(struct pt *pt) ...@@ -897,8 +897,9 @@ static void pt_handle_status(struct pt *pt)
* means we are already losing data; need to let the decoder * means we are already losing data; need to let the decoder
* know. * know.
*/ */
if (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries) || if (!buf->single &&
buf->output_off == pt_buffer_region_size(buf)) { (!intel_pt_validate_hw_cap(PT_CAP_topa_multiple_entries) ||
buf->output_off == pt_buffer_region_size(buf))) {
perf_aux_output_flag(&pt->handle, perf_aux_output_flag(&pt->handle,
PERF_AUX_FLAG_TRUNCATED); PERF_AUX_FLAG_TRUNCATED);
advance++; advance++;
......
...@@ -465,6 +465,8 @@ struct perf_event_attr { ...@@ -465,6 +465,8 @@ struct perf_event_attr {
/* /*
* User provided data if sigtrap=1, passed back to user via * User provided data if sigtrap=1, passed back to user via
* siginfo_t::si_perf_data, e.g. to permit user to identify the event. * siginfo_t::si_perf_data, e.g. to permit user to identify the event.
* Note, siginfo_t::si_perf_data is long-sized, and sig_data will be
* truncated accordingly on 32 bit architectures.
*/ */
__u64 sig_data; __u64 sig_data;
}; };
......
...@@ -3238,6 +3238,15 @@ static int perf_event_modify_breakpoint(struct perf_event *bp, ...@@ -3238,6 +3238,15 @@ static int perf_event_modify_breakpoint(struct perf_event *bp,
return err; return err;
} }
/*
* Copy event-type-independent attributes that may be modified.
*/
static void perf_event_modify_copy_attr(struct perf_event_attr *to,
const struct perf_event_attr *from)
{
to->sig_data = from->sig_data;
}
static int perf_event_modify_attr(struct perf_event *event, static int perf_event_modify_attr(struct perf_event *event,
struct perf_event_attr *attr) struct perf_event_attr *attr)
{ {
...@@ -3260,10 +3269,17 @@ static int perf_event_modify_attr(struct perf_event *event, ...@@ -3260,10 +3269,17 @@ static int perf_event_modify_attr(struct perf_event *event,
WARN_ON_ONCE(event->ctx->parent_ctx); WARN_ON_ONCE(event->ctx->parent_ctx);
mutex_lock(&event->child_mutex); mutex_lock(&event->child_mutex);
/*
* Event-type-independent attributes must be copied before event-type
* modification, which will validate that final attributes match the
* source attributes after all relevant attributes have been copied.
*/
perf_event_modify_copy_attr(&event->attr, attr);
err = func(event, attr); err = func(event, attr);
if (err) if (err)
goto out; goto out;
list_for_each_entry(child, &event->child_list, child_list) { list_for_each_entry(child, &event->child_list, child_list) {
perf_event_modify_copy_attr(&child->attr, attr);
err = func(child, attr); err = func(child, attr);
if (err) if (err)
goto out; goto out;
......
...@@ -44,9 +44,10 @@ static struct { ...@@ -44,9 +44,10 @@ static struct {
} ctx; } ctx;
/* Unique value to check si_perf_data is correctly set from perf_event_attr::sig_data. */ /* Unique value to check si_perf_data is correctly set from perf_event_attr::sig_data. */
#define TEST_SIG_DATA(addr) (~(unsigned long)(addr)) #define TEST_SIG_DATA(addr, id) (~(unsigned long)(addr) + id)
static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr) static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr,
unsigned long id)
{ {
struct perf_event_attr attr = { struct perf_event_attr attr = {
.type = PERF_TYPE_BREAKPOINT, .type = PERF_TYPE_BREAKPOINT,
...@@ -60,7 +61,7 @@ static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr) ...@@ -60,7 +61,7 @@ static struct perf_event_attr make_event_attr(bool enabled, volatile void *addr)
.inherit_thread = 1, /* ... but only cloned with CLONE_THREAD. */ .inherit_thread = 1, /* ... but only cloned with CLONE_THREAD. */
.remove_on_exec = 1, /* Required by sigtrap. */ .remove_on_exec = 1, /* Required by sigtrap. */
.sigtrap = 1, /* Request synchronous SIGTRAP on event. */ .sigtrap = 1, /* Request synchronous SIGTRAP on event. */
.sig_data = TEST_SIG_DATA(addr), .sig_data = TEST_SIG_DATA(addr, id),
}; };
return attr; return attr;
} }
...@@ -110,7 +111,7 @@ FIXTURE(sigtrap_threads) ...@@ -110,7 +111,7 @@ FIXTURE(sigtrap_threads)
FIXTURE_SETUP(sigtrap_threads) FIXTURE_SETUP(sigtrap_threads)
{ {
struct perf_event_attr attr = make_event_attr(false, &ctx.iterate_on); struct perf_event_attr attr = make_event_attr(false, &ctx.iterate_on, 0);
struct sigaction action = {}; struct sigaction action = {};
int i; int i;
...@@ -165,7 +166,7 @@ TEST_F(sigtrap_threads, enable_event) ...@@ -165,7 +166,7 @@ TEST_F(sigtrap_threads, enable_event)
EXPECT_EQ(ctx.tids_want_signal, 0); EXPECT_EQ(ctx.tids_want_signal, 0);
EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on); EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT); EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on)); EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
/* Check enabled for parent. */ /* Check enabled for parent. */
ctx.iterate_on = 0; ctx.iterate_on = 0;
...@@ -175,7 +176,7 @@ TEST_F(sigtrap_threads, enable_event) ...@@ -175,7 +176,7 @@ TEST_F(sigtrap_threads, enable_event)
/* Test that modification propagates to all inherited events. */ /* Test that modification propagates to all inherited events. */
TEST_F(sigtrap_threads, modify_and_enable_event) TEST_F(sigtrap_threads, modify_and_enable_event)
{ {
struct perf_event_attr new_attr = make_event_attr(true, &ctx.iterate_on); struct perf_event_attr new_attr = make_event_attr(true, &ctx.iterate_on, 42);
EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr), 0); EXPECT_EQ(ioctl(self->fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &new_attr), 0);
run_test_threads(_metadata, self); run_test_threads(_metadata, self);
...@@ -184,7 +185,7 @@ TEST_F(sigtrap_threads, modify_and_enable_event) ...@@ -184,7 +185,7 @@ TEST_F(sigtrap_threads, modify_and_enable_event)
EXPECT_EQ(ctx.tids_want_signal, 0); EXPECT_EQ(ctx.tids_want_signal, 0);
EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on); EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT); EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on)); EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 42));
/* Check enabled for parent. */ /* Check enabled for parent. */
ctx.iterate_on = 0; ctx.iterate_on = 0;
...@@ -204,7 +205,7 @@ TEST_F(sigtrap_threads, signal_stress) ...@@ -204,7 +205,7 @@ TEST_F(sigtrap_threads, signal_stress)
EXPECT_EQ(ctx.tids_want_signal, 0); EXPECT_EQ(ctx.tids_want_signal, 0);
EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on); EXPECT_EQ(ctx.first_siginfo.si_addr, &ctx.iterate_on);
EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT); EXPECT_EQ(ctx.first_siginfo.si_perf_type, PERF_TYPE_BREAKPOINT);
EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on)); EXPECT_EQ(ctx.first_siginfo.si_perf_data, TEST_SIG_DATA(&ctx.iterate_on, 0));
} }
TEST_HARNESS_MAIN TEST_HARNESS_MAIN
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment