From: Peter Zijlstra <peterz@infradead.org>
To: Vegard Nossum <vegard.nossum@gmail.com>
Cc: David Carrillo-Cisneros <davidcc@google.com>,
Vineet Gupta <Vineet.Gupta1@synopsys.com>,
Kan Liang <kan.liang@intel.com>,
Arnaldo Carvalho de Melo <acme@redhat.com>,
LKML <linux-kernel@vger.kernel.org>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>
Subject: Re: NULL ptr deref in perf/filter_match
Date: Thu, 4 Aug 2016 14:37:24 +0200 [thread overview]
Message-ID: <20160804123724.GN6862@twins.programming.kicks-ass.net> (raw)
In-Reply-To: <CAOMGZ=FhxmTfK64UGh=fKh5mAZkSNO_aa8ye7E1tVLiEGHRVzA@mail.gmail.com>
On Fri, Jul 29, 2016 at 11:41:11PM +0200, Vegard Nossum wrote:
> Digging a bit deeper into this, it seems the event itself is getting
> created by perf_event_open() and it gets added to the pmu_event_list
> through:
>
> perf_event_open()
> - perf_event_alloc()
> - account_event()
> - account_pmu_sb_event()
> - attach_sb_event()
>
> so at this point the event is being attached but its ->ctx is still
> NULL. It seems like ->ctx is set just a bit later in
> perf_event_open(), though.
>
> But before that, __schedule() comes along and creates a stack trace
> similar to the one above:
>
> __schedule()
> - __perf_event_task_sched_out()
> - perf_iterate_sb()
> - perf_iterate_sb_cpu()
> - event_filter_match()
> - perf_cgroup_match()
> - __get_cpu_context()
> - (dereference ctx which is NULL)
>
> So I guess the question is... should the event be attached (= put on
> the list) before ->ctx gets set? Or should the cgroup code check for a
> NULL ->ctx?
Does this fix it? Ordering is a bit of a mess, adding the events to the
list _after_ they've been installed has the risk of missing things I
think, nor does that result in particularly nice code.
Then again, this isn't pretty either.
---
kernel/events/core.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index a19550d80ab1..87d02b8cb87e 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -1716,8 +1716,8 @@ static inline int pmu_filter_match(struct perf_event *event)
static inline int
event_filter_match(struct perf_event *event)
{
- return (event->cpu == -1 || event->cpu == smp_processor_id())
- && perf_cgroup_match(event) && pmu_filter_match(event);
+ return (event->cpu == -1 || event->cpu == smp_processor_id()) &&
+ perf_cgroup_match(event) && pmu_filter_match(event);
}
static void
@@ -1737,8 +1737,8 @@ event_sched_out(struct perf_event *event,
* maintained, otherwise bogus information is return
* via read() for time_enabled, time_running:
*/
- if (event->state == PERF_EVENT_STATE_INACTIVE
- && !event_filter_match(event)) {
+ if (event->state == PERF_EVENT_STATE_INACTIVE &&
+ !event_filter_match(event)) {
delta = tstamp - event->tstamp_stopped;
event->tstamp_running += delta;
event->tstamp_stopped = tstamp;
@@ -2236,10 +2236,15 @@ perf_install_in_context(struct perf_event_context *ctx,
lockdep_assert_held(&ctx->mutex);
- event->ctx = ctx;
if (event->cpu != -1)
event->cpu = cpu;
+ /*
+ * Ensures that if we can observe event->ctx, both the event and ctx
+ * will be 'complete'. See perf_iterate_sb_cpu().
+ */
+ smp_store_release(&event->ctx, ctx);
+
if (!task) {
cpu_function_call(cpu, __perf_install_in_context, event);
return;
@@ -5969,6 +5974,14 @@ static void perf_iterate_sb_cpu(perf_iterate_f output, void *data)
struct perf_event *event;
list_for_each_entry_rcu(event, &pel->list, sb_list) {
+ /*
+ * Skip events that are not fully formed yet; ensure that
+ * if we observe event->ctx, both event and ctx will be
+ * complete enough. See perf_install_in_context().
+ */
+ if (!smp_load_acquire(&event->ctx))
+ continue;
+
if (event->state < PERF_EVENT_STATE_INACTIVE)
continue;
if (!event_filter_match(event))
next prev parent reply other threads:[~2016-08-04 12:37 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-07-27 14:15 NULL ptr deref in perf/filter_match Vegard Nossum
2016-07-29 21:41 ` Vegard Nossum
2016-07-29 22:36 ` Vegard Nossum
2016-08-04 12:37 ` Peter Zijlstra [this message]
2016-08-04 15:17 ` Vegard Nossum
2016-08-04 15:55 ` Vegard Nossum
2016-08-04 16:00 ` Peter Zijlstra
2016-08-08 20:07 ` Vince Weaver
2016-08-09 6:19 ` Vegard Nossum
2016-08-10 17:56 ` [tip:perf/core] perf/core: Fix sideband list-iteration vs. event ordering NULL pointer deference crash tip-bot for Peter Zijlstra
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=20160804123724.GN6862@twins.programming.kicks-ass.net \
--to=peterz@infradead.org \
--cc=Vineet.Gupta1@synopsys.com \
--cc=acme@redhat.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=davidcc@google.com \
--cc=kan.liang@intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=vegard.nossum@gmail.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox