Re: [patch V2 1/8] signal: Prevent exec() race
From: Thomas Gleixner
Date: Mon Sep 07 2026 - 18:29:58 EST
On Mon, Sep 07 2026 at 22:15, Frederic Weisbecker wrote:
> Le Mon, Sep 07, 2026 at 05:26:04PM +0200, Thomas Gleixner a écrit :
>> It's not obvious of course and might deserve a comment.
>>
>> exit_signals()
>> lock(sighand)
>> old_leader->flags |= PF_EXITING;
>> head = remove_signals()
>> #1 // RELEASE: PF_EXITING must become visible
>> unlock(sighand)
>> flush_list(head)
>>
>> ...
>> posixtimer_exit()
>> posix_cpu_timers_exit_task()
>> lock(sighand)
>> ...
>> #2 // RELEASE: The stores in flush_list() must become visible
>> // They might be already in case of preemption
>> // or due a RELEASE operation in seccomp_filter_release()
>> unlock(sighand)
>
> That second step only appears at the end of the patchset, right? Otherwise
> it's done on release_task(), which is after transfer_pid().
Cleaning up the enqueued posix CPU timers has nothing to do with the
signals.
>> exit_notify()
>> lock(task_list_lock)
>> exit_state = EXIT_ZOMBIE;
>> #3 // RELEASE: exit_state must become visible
In context of patch 1 alone, this RELEASE operation guarantees that the
stores in flush_list() are visible.
The new leader cannot proceed with swapping the TIDs _before_ it
acquires task list lock and observes under task_list_lock
old_leader->exit_state != 0
The TID swap cannot be reordered by the CPU _before_ task list lock is
acquired and the exit_state is observed as non-zero.
As the exit_notify() RELEASE made both the exit_state store and the
preceeding flush_list() stores visible the third party must observe them
correctly as well when it can observe the TID swap.
It does not matter whether the RELEASE operation after flush_list() is
spin_unlock(siglock) or any other RELEASE operation before and including
the final one in exit_notify().
Any of them will provide the guarantee because _all_ preceeding stores
must be visible before the RELEASE operation is complete.
No?
Thanks,
tglx