[PATCH] futex: Temporarily set the task state to running for pivot pending

Edward Adam Davis posted 1 patch 1 month, 1 week ago
kernel/futex/core.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
[PATCH] futex: Temporarily set the task state to running for pivot pending
Posted by Edward Adam Davis 1 month, 1 week ago
There is a report of futex_pivot_pending() locking a mutex while not
TASK_RUNNING, which is due to wait_var_event(mm, futex_pivot_pending(mm))
calls __wait_var_event(), which sets the current task state to 2 before
the condition function `futex_pivot_pending()` executes, which triggers
the warning in [1].

Temporarily set the current task state to 0 within futex_pivot_pending()
to allow `mmph->lock` to complete its lifecycle normally.

[1]
do not call blocking ops when !TASK_RUNNING; state=2 set at [<000000003d62a0c3>] prepare_to_wait_event+0x2e4/0x3ac kernel/sched/wait.c:-1
WARNING: kernel/sched/core.c:9124 at __might_sleep+0xc0/0xdc kernel/sched/core.c:9120, CPU#0: syz.0.17/4920
Call trace:
 class_mutex_constructor include/linux/mutex.h:253 [inline]
 futex_pivot_pending+0x30/0xa4 kernel/futex/core.c:1789
 futex_hash_allocate+0x73c/0xc20 kernel/futex/core.c:1872
 futex_hash_prctl+0xd0/0x324 kernel/futex/core.c:2027

Fixes: 8e7ff730dd96 ("futex: Fix race in futex_pivot_pending() during private hash resize")
Reported-by: syzbot+9c28ada89c468ad30713@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9c28ada89c468ad30713
Tested-by: syzbot+9c28ada89c468ad30713@syzkaller.appspotmail.com
Signed-off-by: Edward Adam Davis <eadavis@qq.com>
---
 kernel/futex/core.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/kernel/futex/core.c b/kernel/futex/core.c
index 128c5752f225..a0b17d2f41da 100644
--- a/kernel/futex/core.c
+++ b/kernel/futex/core.c
@@ -1785,14 +1785,24 @@ static bool futex_pivot_pending(struct mm_struct *mm)
 {
 	struct futex_mm_phash *mmph = &mm->futex.phash;
 	struct futex_private_hash *fph;
+	unsigned int state;
+	bool ret;
+
+	state = current->__state;
+	__set_current_state(TASK_RUNNING);
+	scoped_guard(mutex, &mmph->lock) {
+		if (!mmph->hash_new) {
+			ret = true;
+			goto out;
+		}
 
-	guard(mutex)(&mmph->lock);
-
-	if (!mmph->hash_new)
-		return true;
+		fph = rcu_dereference_raw(mmph->hash);
+		ret = futex_ref_is_dead(fph);
+	}
+out:
+	__set_current_state(state);
+	return ret;
 
-	fph = rcu_dereference_raw(mmph->hash);
-	return futex_ref_is_dead(fph);
 }
 
 static bool futex_hash_less(struct futex_private_hash *a,
-- 
2.43.0