Re: [patch V2 2/8] exec: Cleanup POSIX timers right after de_thread()
From: Frederic Weisbecker
Date: Mon Sep 07 2026 - 18:13:36 EST
Le Sat, Sep 05, 2026 at 08:59:06PM +0200, Thomas Gleixner a écrit :
> From: Hyunwoo Kim <imv4bel@xxxxxxxxx>
>
> 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. 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.
>
> In short:
>
> the non-leader thread B the parent
>
> timer_create(CLOCK_THREAD_CPUTIME_ID)
> timer_settime()
> arm_timer() // the node is queued on B
> execve()
> de_thread(B)
> exchange_tids(B, leader) // B's PID now belongs to the leader
> release_task(leader)
> __exit_signal(leader)
> posix_cpu_timers_exit(leader) // cleans leader's queue, not B's
> __unhash_process(leader) // that PID has no task anymore
> exec_mmap()
> mmap_read_lock_killable(old_mm)
> kill(B, SIGKILL)
> // -EINTR
> get_signal()
> do_exit()
> exit_itimers()
> posix_timer_delete()
> posix_cpu_timer_del()
> posix_timer_unhash_and_free() // freed while still queued
> wait4()
> release_task(B)
> posix_cpu_timers_exit(B)
> cleanup_timerqueue()
> timerqueue_del() // use-after-free
>
> Move the POSIX timer cleanup right after de_thread() before any of the
> later failure conditions brings the task into do_exit().
>
> [ tglx: Move the cleanup right after de_thread() ]
>
> Fixes: 55e8c8eb2c7b ("posix-cpu-timers: Store a reference to a pid not a task")
> Signed-off-by: Hyunwoo Kim <imv4bel@xxxxxxxxx>
> Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxx>
> Cc: stable@xxxxxxxxxxxxxxx
> Link: https://patch.msgid.link/ao7Q8miiuLAPVnWv@v4bel
Reviewed-by: Frederic Weisbecker <frederic@xxxxxxxxxx>