summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-11-27 11:53:41 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2022-11-27 11:53:41 -0800
commit5afcab22179e4b4668e2df4759cfd71f09d2b503 (patch)
tree8700f30eab50601714db69cd627e7a34384acaae
parentbf82d38c91f857083f2d1b9770fa3df55db2ca3b (diff)
parent030a976efae83f7b6593afb11a8254d42f9290fe (diff)
Merge tag 'perf_urgent_for_v6.1_rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf fixes from Borislav Petkov: "Two more fixes to the perf sigtrap handling: - output the address in the sample only when it has been requested - handle the case where user-only events can hit in kernel and thus upset the sigtrap sanity checking" * tag 'perf_urgent_for_v6.1_rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: perf: Consider OS filter fail perf: Fixup SIGTRAP and sample_flags interaction
-rw-r--r--kernel/events/core.c27
1 files changed, 25 insertions, 2 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 884871427a94..9d15d2d96119 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -9273,6 +9273,19 @@ int perf_event_account_interrupt(struct perf_event *event)
return __perf_event_account_interrupt(event, 1);
}
+static inline bool sample_is_allowed(struct perf_event *event, struct pt_regs *regs)
+{
+ /*
+ * Due to interrupt latency (AKA "skid"), we may enter the
+ * kernel before taking an overflow, even if the PMU is only
+ * counting user events.
+ */
+ if (event->attr.exclude_kernel && !user_mode(regs))
+ return false;
+
+ return true;
+}
+
/*
* Generic event overflow handling, sampling.
*/
@@ -9306,6 +9319,13 @@ static int __perf_event_overflow(struct perf_event *event,
}
if (event->attr.sigtrap) {
+ /*
+ * The desired behaviour of sigtrap vs invalid samples is a bit
+ * tricky; on the one hand, one should not loose the SIGTRAP if
+ * it is the first event, on the other hand, we should also not
+ * trigger the WARN or override the data address.
+ */
+ bool valid_sample = sample_is_allowed(event, regs);
unsigned int pending_id = 1;
if (regs)
@@ -9313,7 +9333,7 @@ static int __perf_event_overflow(struct perf_event *event,
if (!event->pending_sigtrap) {
event->pending_sigtrap = pending_id;
local_inc(&event->ctx->nr_pending);
- } else if (event->attr.exclude_kernel) {
+ } else if (event->attr.exclude_kernel && valid_sample) {
/*
* Should not be able to return to user space without
* consuming pending_sigtrap; with exceptions:
@@ -9328,7 +9348,10 @@ static int __perf_event_overflow(struct perf_event *event,
*/
WARN_ON_ONCE(event->pending_sigtrap != pending_id);
}
- event->pending_addr = data->addr;
+
+ event->pending_addr = 0;
+ if (valid_sample && (data->sample_flags & PERF_SAMPLE_ADDR))
+ event->pending_addr = data->addr;
irq_work_queue(&event->pending_irq);
}