From: Thomas Gleixner <tglx@kernel.org>
To: Frederic Weisbecker <frederic@kernel.org>
Cc: LKML <linux-kernel@vger.kernel.org>,
"Cc: Hyunwoo Kim" <imv4bel@gmail.com>,
Oleg Nesterov <oleg@redhat.com>,
Christian Brauner <brauner@kernel.org>,
Peter Zijlstra <peterz@infradead.org>,
John Stultz <jstultz@google.com>, Ingo Molnar <mingo@kernel.org>,
Alexander Viro <viro@zeniv.linux.org.uk>,
"Eric W. Biederman" <ebiederm@xmission.com>,
stable@vger.kernel.org
Subject: Re: [patch V2 1/8] signal: Prevent exec() race
Date: Mon, 07 Sep 2026 17:26:04 +0200 [thread overview]
Message-ID: <87ik4h2icz.ffs@fw13> (raw)
In-Reply-To: <ap6urw5aAxrKO3Ck@localhost.localdomain>
On Mon, Sep 07 2026 at 14:31, Frederic Weisbecker wrote:
> Le Sat, Sep 05, 2026 at 08:59:01PM +0200, Thomas Gleixner a écrit :
>> -out:
>> - spin_unlock_irq(&tsk->sighand->siglock);
>> + flush_sigqueue_list(&sigq_list);
>
> It probably doesn't matter in practice, I don't know feel free to ignore,
> but FWIW it looks like it's still vulnerable to the theoretical far fetched
> race I described. The head is moved under the lock but individual nodes are
> deleted without the lock.
>
> CPU 0 CPU 1 CPU 2
> ----- ----- -----
>
> exit_signals()
> spin_lock(sighand)
> tsk->flags |= PF_EXITING;
> list_splice_init(&queue->list, head);
> spin_unlock(sighand)
>
> list_for_each_safe(head, node)
> list_del_init(node)
> node->next = node // A
> node->prev = node // B
> ...
> de_thread()
> // acquired tsk->flags
> // and signal flushed
> // through tasklist_lock
> transfer_pid() // C
>
> posix_timer_fn()
> posixtimer_send_sigqueue()
> // OBSERVES C
> t = posixtimer_get_target(tmr)
> lock_task_sighand()
> // OBSERVES A
> if (!list_empty(q))
> // BUT NOT B
> list_add_tail(q) // D
>
> Then who knows which write wins, B or D?
For a moment you almost convinced me, but that's not possible:
de_thread()
....
if (!thread_leader()) {
wait_until(old_leader->exit_state);
transfer_pid();
old_leader sets the exit_state in exit_notify():
do_exit()
exit_signals()
lock(sighand)
old_leader->flags |= PF_EXITING;
head = remove_signals()
unlock(sighand)
flush_list(head)
...
exit_notify()
old_leader->exit_state = EXIT_XXX;
From a program order POV the flush is completed _before_ the new leader
can observe old_leader->exit_state and swap TIDS. exit_notify() and the
wait in de_thread() are serialized via tasklist_lock.
The signal is either dropped before transfer_pid() is observable due to
PF_EXITING on the old leader or queued on the new leader and then
discarded in posixtimer_exit() -> flush_itimer_signals().
The only valid question is whether it is guaranteed that on a weakly
ordered system the stores in flush_sigqueue_list() are visible _before_
transfer_pid() is visible to the third party.
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)
...
exit_notify()
lock(task_list_lock)
exit_state = EXIT_ZOMBIE;
#3 // RELEASE: exit_state must become visible
unlock(task_list_lock)
So the new leader cannot proceed before #3 which means it can't swap
TIDs before that point. That requires task_list_lock so there is no way
that the TID swap can trickle before the lock is held and exit_state
being non-zero.
Though the important part is that the third party on CPU3 has to acquire
sighand lock in posixtimer_send_sigqueue(), which is an ACQUIRE
operation. That means _all_ accesses to tsk::flags and to the sigqueue
must happen _after_ the lock is acquired.
If it acquires it after #1 and before the TID swap it must observe
PF_EXITING and return immediately. So a concurrent modification of
timer::sigqueue in flush_list() or not-yet visible stores are
irrelevant.
If it acquires it after #2 it must observe the full writes to the
sigqueue. So after that point it does not longer matter whether the PID
resolves to T1 or T2.
No?
Thanks,
tglx
next prev parent reply other threads:[~2026-09-07 15:26 UTC|newest]
Thread overview: 56+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-05 18:58 [patch V2 0/8] exec/exit: POSIX timer related bugfixes and related cleanups Thomas Gleixner
2026-09-05 18:59 ` [patch V2 1/8] signal: Prevent exec() race Thomas Gleixner
2026-09-06 13:17 ` Oleg Nesterov
2026-09-06 22:39 ` Eric W. Biederman
2026-09-06 23:28 ` Oleg Nesterov
2026-09-07 11:26 ` Thomas Gleixner
2026-09-07 12:31 ` Frederic Weisbecker
2026-09-07 15:26 ` Thomas Gleixner [this message]
2026-09-07 20:15 ` Frederic Weisbecker
2026-09-07 22:28 ` Thomas Gleixner
2026-09-08 10:15 ` Frederic Weisbecker
2026-09-09 0:03 ` Oleg Nesterov
2026-09-09 9:17 ` Frederic Weisbecker
2026-09-09 8:04 ` Peter Zijlstra
2026-09-09 9:08 ` Thomas Gleixner
2026-09-09 9:55 ` Peter Zijlstra
2026-09-09 10:20 ` Peter Zijlstra
2026-09-09 11:31 ` Thomas Gleixner
2026-09-09 12:13 ` Frederic Weisbecker
2026-09-09 12:45 ` Peter Zijlstra
2026-09-09 12:51 ` Peter Zijlstra
2026-09-09 13:45 ` Thomas Gleixner
2026-09-09 15:48 ` Frederic Weisbecker
2026-09-09 16:00 ` Frederic Weisbecker
2026-09-09 14:33 ` Alan Stern
2026-09-09 14:45 ` Frederic Weisbecker
2026-09-09 19:28 ` Alan Stern
2026-09-09 20:49 ` Thomas Gleixner
2026-09-09 21:11 ` Alan Stern
2026-09-10 13:21 ` Frederic Weisbecker
2026-09-10 13:28 ` Peter Zijlstra
2026-09-11 9:58 ` Frederic Weisbecker
2026-09-11 10:22 ` Peter Zijlstra
2026-09-11 12:36 ` Frederic Weisbecker
2026-09-11 14:52 ` Alan Stern
2026-09-10 15:26 ` Alan Stern
2026-09-11 12:27 ` Frederic Weisbecker
2026-09-11 19:05 ` Alan Stern
2026-09-09 10:18 ` Frederic Weisbecker
2026-09-09 9:11 ` Frederic Weisbecker
2026-09-05 18:59 ` [patch V2 2/8] exec: Cleanup POSIX timers right after de_thread() Thomas Gleixner
2026-09-06 13:21 ` Oleg Nesterov
2026-09-07 22:13 ` Frederic Weisbecker
2026-09-05 18:59 ` [patch V2 3/8] posix-timers: Move posixtimer_exec_cleanup() out of exec.c Thomas Gleixner
2026-09-10 13:50 ` Frederic Weisbecker
2026-09-05 18:59 ` [patch V2 4/8] posix-timers: Move POSIX timer group exit related code out of do_exit() Thomas Gleixner
2026-09-10 13:59 ` Frederic Weisbecker
2026-09-05 18:59 ` [patch V2 5/8] posix-cpu-timers: Move inlines out of public header Thomas Gleixner
2026-09-10 14:00 ` Frederic Weisbecker
2026-09-05 18:59 ` [patch V2 6/8] posix-cpu-timers: Use PF_EXITING to indicate exit Thomas Gleixner
2026-09-05 18:59 ` [patch V2 7/8] posix-cpu-timers: Prevent enqueueing when PF_EXITING is set Thomas Gleixner
2026-09-06 16:26 ` Oleg Nesterov
2026-09-07 12:20 ` Thomas Gleixner
2026-09-05 18:59 ` [patch V2 8/8] posix-timers: Handle exit in do_exit() completely Thomas Gleixner
2026-09-06 16:40 ` Oleg Nesterov
2026-09-07 12:27 ` Thomas Gleixner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87ik4h2icz.ffs@fw13 \
--to=tglx@kernel.org \
--cc=brauner@kernel.org \
--cc=ebiederm@xmission.com \
--cc=frederic@kernel.org \
--cc=imv4bel@gmail.com \
--cc=jstultz@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=oleg@redhat.com \
--cc=peterz@infradead.org \
--cc=stable@vger.kernel.org \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®