From c0ff3cd9d7d5e2f51c0b691128800b0b0cf7da2c Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Mon, 1 Jun 2020 12:20:04 -0700 Subject: [PATCH] ANDROID: scs: fix recursive spinlock in scs_check_usage Use cmpxchg instead of a spinlock in scs_check_usage() to avoid deadlocks. Bug: 157781894 Change-Id: I1701ccaf25fdbd34ce4798c6f93e220b1565fb34 Signed-off-by: Sami Tolvanen --- kernel/scs.c | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/kernel/scs.c b/kernel/scs.c index ad74d13f2c0f..c8e53358e20a 100644 --- a/kernel/scs.c +++ b/kernel/scs.c @@ -185,36 +185,31 @@ int scs_prepare(struct task_struct *tsk, int node) } #ifdef CONFIG_DEBUG_STACK_USAGE -static inline unsigned long scs_used(struct task_struct *tsk) -{ - unsigned long *p = __scs_base(tsk); - unsigned long *end = scs_magic(p); - unsigned long s = (unsigned long)p; - - while (p < end && READ_ONCE_NOCHECK(*p)) - p++; - - return (unsigned long)p - s; -} - static void scs_check_usage(struct task_struct *tsk) { - static DEFINE_SPINLOCK(lock); static unsigned long highest; - unsigned long used = scs_used(tsk); - if (used <= highest) - return; + unsigned long *p = __scs_base(tsk); + unsigned long *end = scs_magic(p); + unsigned long prev, curr = highest, used = 0; - spin_lock(&lock); - - if (used > highest) { - pr_info("%s (%d): highest shadow stack usage: %lu bytes\n", - tsk->comm, task_pid_nr(tsk), used); - highest = used; + for (; p < end; ++p) { + if (!READ_ONCE_NOCHECK(*p)) + break; + used += sizeof(*p); } - spin_unlock(&lock); + while (used > curr) { + prev = cmpxchg_relaxed(&highest, curr, used); + + if (prev == curr) { + pr_info("%s (%d): highest shadow stack usage: %lu bytes\n", + tsk->comm, task_pid_nr(tsk), used); + break; + } + + curr = prev; + } } #else static inline void scs_check_usage(struct task_struct *tsk)