[PATCH 5.4 388/453] powerpc/powernv/memtrace: Fix crashing the kernel when enabling concurrently
From: Greg Kroah-Hartman
Date: Mon Dec 28 2020 - 10:28:16 EST
From: David Hildenbrand <david@xxxxxxxxxx>
commit d6718941a2767fb383e105d257d2105fe4f15f0e upstream.
It's very easy to crash the kernel right now by simply trying to
enable memtrace concurrently, hammering on the "enable" interface
loop.sh:
#!/bin/bash
dmesg --console-off
while true; do
echo 0x40000000 > /sys/kernel/debug/powerpc/memtrace/enable
done
[root@localhost ~]# loop.sh &
[root@localhost ~]# loop.sh &
Resulting quickly in a kernel crash. Let's properly protect using a
mutex.
Fixes: 9d5171a8f248 ("powerpc/powernv: Enable removal of memory for in memory tracing")
Cc: stable@xxxxxxxxxxxxxxx# v4.14+
Signed-off-by: David Hildenbrand <david@xxxxxxxxxx>
Reviewed-by: Oscar Salvador <osalvador@xxxxxxx>
Signed-off-by: Michael Ellerman <mpe@xxxxxxxxxxxxxx>
Link: https://lore.kernel.org/r/20201111145322.15793-3-david@xxxxxxxxxx
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
arch/powerpc/platforms/powernv/memtrace.c | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
--- a/arch/powerpc/platforms/powernv/memtrace.c
+++ b/arch/powerpc/platforms/powernv/memtrace.c
@@ -30,6 +30,7 @@ struct memtrace_entry {
char name[16];
};
+static DEFINE_MUTEX(memtrace_mutex);
static u64 memtrace_size;
static struct memtrace_entry *memtrace_array;
@@ -290,6 +291,7 @@ static int memtrace_online(void)
static int memtrace_enable_set(void *data, u64 val)
{
+ int rc = -EAGAIN;
u64 bytes;
/*
@@ -302,25 +304,31 @@ static int memtrace_enable_set(void *dat
return -EINVAL;
}
+ mutex_lock(&memtrace_mutex);
+
/* Re-add/online previously removed/offlined memory */
if (memtrace_size) {
if (memtrace_online())
- return -EAGAIN;
+ goto out_unlock;
}
- if (!val)
- return 0;
+ if (!val) {
+ rc = 0;
+ goto out_unlock;
+ }
/* Offline and remove memory */
if (memtrace_init_regions_runtime(val))
- return -EINVAL;
+ goto out_unlock;
if (memtrace_init_debugfs())
- return -EINVAL;
+ goto out_unlock;
memtrace_size = val;
-
- return 0;
+ rc = 0;
+out_unlock:
+ mutex_unlock(&memtrace_mutex);
+ return rc;
}
static int memtrace_enable_get(void *data, u64 *val)