FAILED: patch "[PATCH] futex/pi: Plug private futex exec() race" failed to apply to 7.1-stable tree
Subsystems (4)
[email protected]
maintainerThe patch below does not apply to the 7.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-7.1.y
git checkout FETCH_HEAD
git cherry-pick -x c5f0bc9fd1cec4a00400cc727fcde03e0fde17cc
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026082416-unopened-rectify-cdc8@gregkh' --subject-prefix 'PATCH 7.1.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From c5f0bc9fd1cec4a00400cc727fcde03e0fde17cc Mon Sep 17 00:00:00 2001
From: Thomas Gleixner <[email protected]>
Date: Fri, 7 Aug 2026 17:07:13 +0200
Subject: [PATCH] futex/pi: Plug private futex exec() race
The check for private futexes whether the waiter's mm, which is stored in the futex_key and copied into the pi_state, is the same as the owner's mm is not sufficient for exec(). exec() has a gap where the mm check fails to give the correct answer:
exec()
...
exec_release_mm()
futex_exec_release()
tsk::futex::exit_state = EXITING;
cleanup_robust_list();
1) tsk::futex::exit_state = OK;
...
old_mm = tsk::mm;2) tsk::mm = ->mm;
Between #1 and #2 the check for the mm is wrong as that mm is about to be swapped out and eventually freed.
Plug this gap by:
1) Setting tsk::futex::exit_state to FUTEX_STATE_DEAD in futex_exec_release()
2) Setting tsk::futex::exit_state to FUTEX_STATE_OK after the mm has been switched.
From a futex point of view the task is dead after it finished the robust list cleanup up to the point where it sets the state to OK again.
fs/exec.c +5 -2
@@ -30,6 +30,7 @@#include <linux/mm.h> #include <linux/stat.h> #include <linux/fcntl.h> +#include <linux/futex.h> #include <linux/swap.h> #include <linux/string.h> #include <linux/init.h>
@@ -854,6 +855,7 @@ static int exec_mmap(struct linux_binprm *bprm)/* Notify parent that we're no longer interested in the old VM */ tsk = current; old_mm = current->mm; +/* Clean up futexes and release the mm */ exec_mm_release (tsk, old_mm); ret =down_write_killable (&tsk->signal->exec_update_lock);
@@ -902,9 +904,10 @@ static int exec_mmap(struct linux_binprm *bprm)BUG_ON (active_mm != old_mm);/* Defer teardown to setup_new_exec(), outside the exec locks. */ bprm->old_mm = old_mm; -return 0 ; + }else { +mmdrop_lazy_tlb (active_mm); } -mmdrop_lazy_tlb (active_mm); +futex_exec_done (tsk);return 0 ; }
include/linux/futex.h +2 -0
@@ -73,6 +73,7 @@ static inline void futex_init_task(struct task_struct *tsk)void futex_exit_recursive (struct task_struct *tsk);void futex_exit_release (struct task_struct *tsk);void futex_exec_release (struct task_struct *tsk); +void futex_exec_done (struct task_struct *tsk);long do_futex (u32 __user *uaddr,int op,u32 val,ktime_t *timeout,u32 __user *uaddr2,u32 val2,u32 val3);
@@ -91,6 +92,7 @@ static inline void futex_init_task(struct task_struct *tsk) { }static inline void futex_exit_recursive (struct task_struct *tsk) { }static inline void futex_exit_release (struct task_struct *tsk) { }static inline void futex_exec_release (struct task_struct *tsk) { } +static inline void futex_exec_done (struct task_struct *tsk) { }static inline long do_futex (u32 __user *uaddr,int op,u32 val,ktime_t *timeout,u32 __user *uaddr2,u32 val2,u32 val3) {
kernel/futex/core.c +41 -21
81 lines not on this page · raw message
kernel/futex/pi.c +16 -6
@@ -200,15 +200,25 @@ void put_pi_state(struct futex_pi_state *pi_state)* * - FUTEX_STATE_OK when the task is alive and waiters can be attached * -* - FUTEX_STATE_EXITING when the task cleans up the robust list and pi +* - FUTEX_STATE_EXITING when the task cleans up the robust list and PI * state. Concurrent waiters cannot attach anymore and have to wait until the -* cleanup is finished to re-evaluate the potential changes of robust list and -* pi state cleanups. +* cleanup is finished to re-evaluate the potential changes caused by the +* robust list and PI state cleanups. * -* - FUTEX_STATE_DEAD when the task has cleaned up the robust list and -* is about to fully exit. +* - FUTEX_STATE_DEAD when the task has cleaned up the robust list. This state +* is set independent of exit() or exec(). In the exit() case the task is +* gone. In the exec() case this ensures that nothing can attach to the task +* after cleaning up the robust list and PI state before it has switched to +* the new mm. From a futex point of view the task is dead until it sets the +* state to FUTEX_STATE_OK again after switching to the new mm. * -* exec() switches back to FUTEX_STATE_OK after the cleanup. +* The valid state transitions for exit(): +* +* FUTEX_STATE_OK -> FUTEX_STATE_EXITING -> FUTEX_STATE_DEAD +* +* The valid state transitions for exec(): +* +* FUTEX_STATE_OK -> FUTEX_STATE_EXITING -> FUTEX_STATE_DEAD -> FUTEX_STATE_OK * * The state has two related locks: *
Sasha Levin
maintainerPATCH 1/1 futex/pi: Plug private futex exec() race
From: Thomas Gleixner <[email protected]>
[ Upstream commit c5f0bc9fd1cec4a00400cc727fcde03e0fde17cc ]
The check for private futexes whether the waiter's mm, which is stored in the futex_key and copied into the pi_state, is the same as the owner's mm is not sufficient for exec(). exec() has a gap where the mm check fails to give the correct answer:
exec()
...
exec_release_mm()
futex_exec_release()
tsk::futex::exit_state = EXITING;
cleanup_robust_list();
1) tsk::futex::exit_state = OK;
...
old_mm = tsk::mm;2) tsk::mm = ->mm;
Between #1 and #2 the check for the mm is wrong as that mm is about to be swapped out and eventually freed.
Plug this gap by:
1) Setting tsk::futex::exit_state to FUTEX_STATE_DEAD in futex_exec_release()
2) Setting tsk::futex::exit_state to FUTEX_STATE_OK after the mm has been switched.
From a futex point of view the task is dead after it finished the robust list cleanup up to the point where it sets the state to OK again.
--- fs/exec.c | 7 ++++-- include/linux/futex.h | 2 ++ kernel/futex/core.c | 54 +++++++++++++++++++++++++++++-------------- 3 files changed, 44 insertions(+), 19 deletions(-)
fs/exec.c +5 -2
@@ -30,6 +30,7 @@#include <linux/mm.h> #include <linux/stat.h> #include <linux/fcntl.h> +#include <linux/futex.h> #include <linux/swap.h> #include <linux/string.h> #include <linux/init.h>
@@ -843,6 +844,7 @@ static int exec_mmap(struct mm_struct *mm)/* Notify parent that we're no longer interested in the old VM */ tsk = current; old_mm = current->mm; +/* Clean up futexes and release the mm */ exec_mm_release (tsk, old_mm); ret =down_write_killable (&tsk->signal->exec_update_lock);
@@ -891,9 +893,10 @@ static int exec_mmap(struct mm_struct *mm)setmax_mm_hiwater_rss (&tsk->signal->maxrss, old_mm);mm_update_next_owner (old_mm);mmput (old_mm); -return 0 ; + }else { +mmdrop_lazy_tlb (active_mm); } -mmdrop_lazy_tlb (active_mm); +futex_exec_done (tsk);return 0 ; }
include/linux/futex.h +2 -0
@@ -77,6 +77,7 @@ static inline void futex_init_task(struct task_struct *tsk)void futex_exit_recursive (struct task_struct *tsk);void futex_exit_release (struct task_struct *tsk);void futex_exec_release (struct task_struct *tsk); +void futex_exec_done (struct task_struct *tsk);long do_futex (u32 __user *uaddr,int op,u32 val,ktime_t *timeout,u32 __user *uaddr2,u32 val2,u32 val3);
@@ -98,6 +99,7 @@ static inline void futex_init_task(struct task_struct *tsk) { }static inline void futex_exit_recursive (struct task_struct *tsk) { }static inline void futex_exit_release (struct task_struct *tsk) { }static inline void futex_exec_release (struct task_struct *tsk) { } +static inline void futex_exec_done (struct task_struct *tsk) { }static inline long do_futex (u32 __user *uaddr,int op,u32 val,ktime_t *timeout,u32 __user *uaddr2,u32 val2,u32 val3)
kernel/futex/core.c +37 -17
80 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg KH
maintainerRe: [PATCH 7.1.y] futex/pi: Plug private futex exec() race
Quoted 3 lines · Sasha Levin
From: Thomas Gleixner <[email protected]>
[ Upstream commit
c5f0bc9fd1cec4a00400cc727fcde03e0fde17cc]
Already queued up :)