|
|
@@ -4452,12 +4452,20 @@ static void _free_event(struct perf_event *event)
|
|
|
if (event->destroy)
|
|
|
event->destroy(event);
|
|
|
|
|
|
- if (event->ctx)
|
|
|
- put_ctx(event->ctx);
|
|
|
-
|
|
|
+ /*
|
|
|
+ * Must be after ->destroy(), due to uprobe_perf_close() using
|
|
|
+ * hw.target.
|
|
|
+ */
|
|
|
if (event->hw.target)
|
|
|
put_task_struct(event->hw.target);
|
|
|
|
|
|
+ /*
|
|
|
+ * perf_event_free_task() relies on put_ctx() being 'last', in particular
|
|
|
+ * all task references must be cleaned up.
|
|
|
+ */
|
|
|
+ if (event->ctx)
|
|
|
+ put_ctx(event->ctx);
|
|
|
+
|
|
|
exclusive_event_destroy(event);
|
|
|
module_put(event->pmu->module);
|
|
|
|
|
|
@@ -4637,8 +4645,17 @@ again:
|
|
|
mutex_unlock(&event->child_mutex);
|
|
|
|
|
|
list_for_each_entry_safe(child, tmp, &free_list, child_list) {
|
|
|
+ void *var = &child->ctx->refcount;
|
|
|
+
|
|
|
list_del(&child->child_list);
|
|
|
free_event(child);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Wake any perf_event_free_task() waiting for this event to be
|
|
|
+ * freed.
|
|
|
+ */
|
|
|
+ smp_mb(); /* pairs with wait_var_event() */
|
|
|
+ wake_up_var(var);
|
|
|
}
|
|
|
|
|
|
no_ctx:
|
|
|
@@ -11220,11 +11237,11 @@ static void perf_free_event(struct perf_event *event,
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Free an unexposed, unused context as created by inheritance by
|
|
|
- * perf_event_init_task below, used by fork() in case of fail.
|
|
|
+ * Free a context as created by inheritance by perf_event_init_task() below,
|
|
|
+ * used by fork() in case of fail.
|
|
|
*
|
|
|
- * Not all locks are strictly required, but take them anyway to be nice and
|
|
|
- * help out with the lockdep assertions.
|
|
|
+ * Even though the task has never lived, the context and events have been
|
|
|
+ * exposed through the child_list, so we must take care tearing it all down.
|
|
|
*/
|
|
|
void perf_event_free_task(struct task_struct *task)
|
|
|
{
|
|
|
@@ -11254,7 +11271,23 @@ void perf_event_free_task(struct task_struct *task)
|
|
|
perf_free_event(event, ctx);
|
|
|
|
|
|
mutex_unlock(&ctx->mutex);
|
|
|
- put_ctx(ctx);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * perf_event_release_kernel() could've stolen some of our
|
|
|
+ * child events and still have them on its free_list. In that
|
|
|
+ * case we must wait for these events to have been freed (in
|
|
|
+ * particular all their references to this task must've been
|
|
|
+ * dropped).
|
|
|
+ *
|
|
|
+ * Without this copy_process() will unconditionally free this
|
|
|
+ * task (irrespective of its reference count) and
|
|
|
+ * _free_event()'s put_task_struct(event->hw.target) will be a
|
|
|
+ * use-after-free.
|
|
|
+ *
|
|
|
+ * Wait for all events to drop their context reference.
|
|
|
+ */
|
|
|
+ wait_var_event(&ctx->refcount, atomic_read(&ctx->refcount) == 1);
|
|
|
+ put_ctx(ctx); /* must be last */
|
|
|
}
|
|
|
}
|
|
|
|