Re: [PATCH] posix-cpu-timers: Dequeue per-thread timers before exchange_tids()

Hyunwoo Kim <[email protected]>
Newsgroups org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kvack.linux-mm
Message-ID <an8Dq_XUMobC395V@v4bel>
On Sun, Aug 09, 2026 at 11:06:38AM +0900, Hyunwoo Kim wrote:
> A per-thread CPU timer holds a reference to the PID of the thread it is
> attached to and, while it is armed, its node is queued in that thread's
> posix_cputimers. The task is looked up by that PID.
> 
> When a non-leader thread exec()s, de_thread() changes which task owns
> that PID:
> 
>   de_thread(tsk)
>     exchange_tids(tsk, leader);		// tsk's PID now belongs to leader
>     ...
>     release_task(leader)
>       __exit_signal(leader)
>         posix_cpu_timers_exit(leader);	// cleans leader's queue, not tsk's
>         __unhash_process(leader)	// that PID has no task anymore
> 
> pid_task(timer->it.cpu.pid, PIDTYPE_PID) then returns NULL, but the node
> is still queued on tsk, which is alive. timer_lock_sighand() takes a
> failed lookup to mean that the node is already dequeued, so it has
> nothing to undo.
> 
> begin_new_exec() calls posix_cpu_timers_exit(me) right after
> exec_task_namespaces() and that removes the leftover node, so the state
> normally stays invisible. But bprm->point_of_no_return is set before
> de_thread(), so if unshare_files(), set_mm_exe_file(), exec_mmap() or
> exec_task_namespaces() fails, the task dies before it gets there.
> exit_itimers() then frees the k_itimer while its node is still queued,
> and reaping tsk later erases that freed node from the rbtree.
> 
> Dequeue the per-thread CPU timers of tsk before the PID changes hands, so
> that a failed lookup again implies a dequeued node. Process-wide timers
> are looked up with PIDTYPE_TGID and transfer_pid() moves that link to
> tsk, so they are left alone.
> 
> Fixes: 55e8c8eb2c7b ("posix-cpu-timers: Store a reference to a pid not a task")
> Cc: [email protected]
> Signed-off-by: Hyunwoo Kim <[email protected]>
> ---
>  fs/exec.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/fs/exec.c b/fs/exec.c
> index c7b8f2d6366c44..f80f70e1c26de4 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -1000,6 +1000,18 @@ static int de_thread(struct task_struct *tsk)
>  		 * the former thread group leader:
>  		 */
>  
> +#ifdef CONFIG_POSIX_TIMERS
> +		/*
> +		 * exchange_tids() hands this thread's PID to the old leader,
> +		 * which is reaped right after. The PID lookup in
> +		 * timer_lock_sighand() then fails while the per thread CPU
> +		 * timers are still queued here, so dequeue them first.
> +		 */
> +		spin_lock(lock);
> +		posix_cpu_timers_exit(tsk);
> +		spin_unlock(lock);
> +#endif
> +
>  		/* Become a process group leader with the old leader's pid.
>  		 * The old leader becomes a thread of the this thread group.
>  		 */
> -- 
> 2.43.0
> 

Gentle ping. Any feedback on this patch would be appreciated.


Best regards,
Hyunwoo Kim
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.