summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSami Tolvanen <samitolvanen@google.com>2020-06-01 12:20:04 -0700
committerSami Tolvanen <samitolvanen@google.com>2020-06-02 17:37:03 +0000
commitc0ff3cd9d7d5e2f51c0b691128800b0b0cf7da2c (patch)
tree3f1bc723cf7e3c3b73f242492b9150e470617ed5
parent7b8513eb008b7ed331af838edc3344d172a94ac0 (diff)
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 <samitolvanen@google.com>
-rw-r--r--kernel/scs.c39
1 files changed, 17 insertions, 22 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)
+static void scs_check_usage(struct task_struct *tsk)
{
+ static unsigned long highest;
+
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++;
+ unsigned long prev, curr = highest, used = 0;
- 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);
+ for (; p < end; ++p) {
+ if (!READ_ONCE_NOCHECK(*p))
+ break;
+ used += sizeof(*p);
+ }
- if (used <= highest)
- return;
+ while (used > curr) {
+ prev = cmpxchg_relaxed(&highest, curr, used);
- spin_lock(&lock);
+ if (prev == curr) {
+ pr_info("%s (%d): highest shadow stack usage: %lu bytes\n",
+ tsk->comm, task_pid_nr(tsk), used);
+ break;
+ }
- if (used > highest) {
- pr_info("%s (%d): highest shadow stack usage: %lu bytes\n",
- tsk->comm, task_pid_nr(tsk), used);
- highest = used;
+ curr = prev;
}
-
- spin_unlock(&lock);
}
#else
static inline void scs_check_usage(struct task_struct *tsk)