Commit c3bf8a14 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
Loading
Loading
Loading
Loading
+13 −0
Original line number Original line Diff line number Diff line
@@ -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)
+3 −2
Original line number Original line Diff line number Diff line
@@ -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++;
+2 −0
Original line number Original line Diff line number Diff line
@@ -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;
};
};
+16 −0
Original line number Original line Diff line number Diff line
@@ -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,
	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;
+9 −8
Original line number Original line Diff line number Diff line
@@ -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)
		.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)


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)
	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)
/* 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)
	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)
	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