summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2017-01-13 17:02:48 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2017-01-13 17:02:47 -0800
commit1896b200f9db69446d25a2aace5658df7c775219 (patch)
tree3432d355094f101d595aff55b7e78bc42f3c09d5 /kernel
parentbcea61c8582e309ce28d9223fd7b790b598e38a8 (diff)
parent7ee4109d7ec74f5ed2ae10330f9d0b69b0eeb1c2 (diff)
Merge "perf: protect group_leader from races that cause ctx double-free"
Diffstat (limited to 'kernel')
-rw-r--r--kernel/events/core.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 446dbad75e60..00beacd233fd 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -8066,6 +8066,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
if (!group_leader)
group_leader = event;
+ mutex_init(&event->group_leader_mutex);
mutex_init(&event->child_mutex);
INIT_LIST_HEAD(&event->child_list);
@@ -8505,6 +8506,16 @@ SYSCALL_DEFINE5(perf_event_open,
group_leader = NULL;
}
+ /*
+ * Take the group_leader's group_leader_mutex before observing
+ * anything in the group leader that leads to changes in ctx,
+ * many of which may be changing on another thread.
+ * In particular, we want to take this lock before deciding
+ * whether we need to move_group.
+ */
+ if (group_leader)
+ mutex_lock(&group_leader->group_leader_mutex);
+
if (pid != -1 && !(flags & PERF_FLAG_PID_CGROUP)) {
task = find_lively_task_by_vpid(pid);
if (IS_ERR(task)) {
@@ -8766,6 +8777,8 @@ SYSCALL_DEFINE5(perf_event_open,
if (move_group)
mutex_unlock(&gctx->mutex);
mutex_unlock(&ctx->mutex);
+ if (group_leader)
+ mutex_unlock(&group_leader->group_leader_mutex);
if (task) {
mutex_unlock(&task->signal->cred_guard_mutex);
@@ -8815,6 +8828,8 @@ err_task:
if (task)
put_task_struct(task);
err_group_fd:
+ if (group_leader)
+ mutex_unlock(&group_leader->group_leader_mutex);
fdput(group);
err_fd:
put_unused_fd(event_fd);