summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-14351/0001-perf-core-Fix-race-in-the-perf_mmap_close-function.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-14351/0001-perf-core-Fix-race-in-the-perf_mmap_close-function.patch')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-14351/0001-perf-core-Fix-race-in-the-perf_mmap_close-function.patch98
1 files changed, 98 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-14351/0001-perf-core-Fix-race-in-the-perf_mmap_close-function.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-14351/0001-perf-core-Fix-race-in-the-perf_mmap_close-function.patch
new file mode 100644
index 000000000..c5114ac32
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/CVE-2020-14351/0001-perf-core-Fix-race-in-the-perf_mmap_close-function.patch
@@ -0,0 +1,98 @@
+From 4ef4d084d9e38fbf31d40ff0a91bd621720421d9 Mon Sep 17 00:00:00 2001
+From: Jiri Olsa <jolsa@redhat.com>
+Date: Wed, 16 Sep 2020 13:53:11 +0200
+Subject: [PATCH] perf/core: Fix race in the perf_mmap_close() function
+
+There's a possible race in perf_mmap_close() when checking ring buffer's
+mmap_count refcount value. The problem is that the mmap_count check is
+not atomic because we call atomic_dec() and atomic_read() separately.
+
+ perf_mmap_close:
+ ...
+ atomic_dec(&rb->mmap_count);
+ ...
+ if (atomic_read(&rb->mmap_count))
+ goto out_put;
+
+ <ring buffer detach>
+ free_uid
+
+out_put:
+ ring_buffer_put(rb); /* could be last */
+
+The race can happen when we have two (or more) events sharing same ring
+buffer and they go through atomic_dec() and then they both see 0 as refcount
+value later in atomic_read(). Then both will go on and execute code which
+is meant to be run just once.
+
+The code that detaches ring buffer is probably fine to be executed more
+than once, but the problem is in calling free_uid(), which will later on
+demonstrate in related crashes and refcount warnings, like:
+
+ refcount_t: addition on 0; use-after-free.
+ ...
+ RIP: 0010:refcount_warn_saturate+0x6d/0xf
+ ...
+ Call Trace:
+ prepare_creds+0x190/0x1e0
+ copy_creds+0x35/0x172
+ copy_process+0x471/0x1a80
+ _do_fork+0x83/0x3a0
+ __do_sys_wait4+0x83/0x90
+ __do_sys_clone+0x85/0xa0
+ do_syscall_64+0x5b/0x1e0
+ entry_SYSCALL_64_after_hwframe+0x44/0xa9
+
+Using atomic decrease and check instead of separated calls.
+
+Tested-by: Michael Petlan <mpetlan@redhat.com>
+Signed-off-by: Jiri Olsa <jolsa@kernel.org>
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Acked-by: Namhyung Kim <namhyung@kernel.org>
+Acked-by: Wade Mealing <wmealing@redhat.com>
+Fixes: 9bb5d40cd93c ("perf: Fix mmap() accounting hole");
+Link: https://lore.kernel.org/r/20200916115311.GE2301783@krava
+---
+ kernel/events/core.c | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 956d5ab46db9..1d5f2806c65e 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -5587,11 +5587,11 @@ static void perf_pmu_output_stop(struct perf_event *event);
+ static void perf_mmap_close(struct vm_area_struct *vma)
+ {
+ struct perf_event *event = vma->vm_file->private_data;
+-
+ struct ring_buffer *rb = ring_buffer_get(event);
+ struct user_struct *mmap_user = rb->mmap_user;
+ int mmap_locked = rb->mmap_locked;
+ unsigned long size = perf_data_size(rb);
++ bool detach_rest = false;
+
+ if (event->pmu->event_unmapped)
+ event->pmu->event_unmapped(event, vma->vm_mm);
+@@ -5622,7 +5622,8 @@ static void perf_mmap_close(struct vm_area_struct *vma)
+ mutex_unlock(&event->mmap_mutex);
+ }
+
+- atomic_dec(&rb->mmap_count);
++ if (atomic_dec_and_test(&rb->mmap_count))
++ detach_rest = true;
+
+ if (!atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex))
+ goto out_put;
+@@ -5631,7 +5632,7 @@ static void perf_mmap_close(struct vm_area_struct *vma)
+ mutex_unlock(&event->mmap_mutex);
+
+ /* If there's still other mmap()s of this buffer, we're done. */
+- if (atomic_read(&rb->mmap_count))
++ if (!detach_rest)
+ goto out_put;
+
+ /*
+--
+2.17.1
+