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

Edward Adam Davis <[email protected]>
Newsgroups gmane.linux.kernel
Message-ID <[email protected]>
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: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=9c28ada89c468ad30713
Tested-by: [email protected]
Signed-off-by: Edward Adam Davis <[email protected]>
---
 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.