summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorMarco Elver <elver@google.com>2021-05-27 12:47:11 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2021-06-16 11:34:53 +0200
commit668bd53c549e1d6de8873c9037de98f042240b1e (patch)
treec8f6aecf48db7319908388b159a6dbffa5eae55a /kernel
parent4e0d9280b6b13556f9f39dba0854cc670151653f (diff)
perf: Fix data race between pin_count increment/decrement
commit 6c605f8371159432ec61cbb1488dcf7ad24ad19a upstream. KCSAN reports a data race between increment and decrement of pin_count: write to 0xffff888237c2d4e0 of 4 bytes by task 15740 on cpu 1: find_get_context kernel/events/core.c:4617 __do_sys_perf_event_open kernel/events/core.c:12097 [inline] __se_sys_perf_event_open kernel/events/core.c:11933 ... read to 0xffff888237c2d4e0 of 4 bytes by task 15743 on cpu 0: perf_unpin_context kernel/events/core.c:1525 [inline] __do_sys_perf_event_open kernel/events/core.c:12328 [inline] __se_sys_perf_event_open kernel/events/core.c:11933 ... Because neither read-modify-write here is atomic, this can lead to one of the operations being lost, resulting in an inconsistent pin_count. Fix it by adding the missing locking in the CPU-event case. Fixes: fe4b04fa31a6 ("perf: Cure task_oncpu_function_call() races") Reported-by: syzbot+142c9018f5962db69c7e@syzkaller.appspotmail.com Signed-off-by: Marco Elver <elver@google.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lkml.kernel.org/r/20210527104711.2671610-1-elver@google.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/events/core.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c
index d399748ea86b..ee75563b724f 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -3497,7 +3497,9 @@ find_get_context(struct pmu *pmu, struct task_struct *task,
cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
ctx = &cpuctx->ctx;
get_ctx(ctx);
+ raw_spin_lock_irqsave(&ctx->lock, flags);
++ctx->pin_count;
+ raw_spin_unlock_irqrestore(&ctx->lock, flags);
return ctx;
}