From: Thomas Gleixner <tglx@kernel.org>
To: Oleg Nesterov <oleg@redhat.com>
Cc: Frederic Weisbecker <frederic@kernel.org>,
Hyunwoo Kim <imv4bel@gmail.com>,
brauner@kernel.org, peterz@infradead.org,
anna-maria@linutronix.de, ebiederm@xmission.com,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH] signal: Use list_del_init_careful() in flush_sigqueue()
Date: Tue, 25 Aug 2026 21:58:00 +0200 [thread overview]
Message-ID: <87fr02gegn.ffs@fw13> (raw)
In-Reply-To: <ao3kt-eRxw4agOj7@redhat.com>
On Tue, Aug 25 2026 at 20:53, Oleg Nesterov wrote:
> On 08/25, Thomas Gleixner wrote:
>> > Is there something to prevent the timer from firing on another CPU,
>> > racing with this tiny window and queue the signal to the old leader? After
>> > all exchange_tids() is just some RCU pointers changed but there is nothing
>> > to synchronize the readers before the flush_sigqueue(). So pid_task() may
>> > still return the old leader after it?
>>
>> You beat me to it.
>>
>> That's what I initialy thought when I added that exiting check into
>> posixtimer_send_queue(), but then the trivial variant lured me away. :)
>
> I'm afraid I am wrong again... but if change posixtimer_send_sigqueue()
> to check !PF_EXITING, de_thread() still can do flush_sigqueue() after
> exchange_tids() outside of tasklist_lock?
>
> And I'd suggest to check t->exit_state instead of PF_EXITING,
> posixtimer_send_sigqueue() can't miss it if it is called after
> scoped_guard(spinlock_irq, lock).
It neither can miss PF_EXITING which is also set under sighand lock.
But I think we all looked at it way too narrowly focussed on that
specific non-leader exec() scenario. Let's take a step back and look at
the larger picture.
Once begin_new_exec() sets bprm->point_of_no_return = true there is
_ZERO_ reason to queue any posix timer signal anymore. Any failure after
that point will be fatal and shut the whole process down.
So why worrying about the non-leader exec() oddity?
begin_new_exex()
{
...
bprm->point_of_no_return = true;
scoped_guard(spinlock_irq, &me->sighand->siglock)
me->signal->flags |= SIGNAL_EXEC;
de_thread(me)
...
// FIXME: This sequence should be cleaned up with a
// posix_timer_exec() function with a proper stub
// for CONFIG_POSIX_TIMERS=n.
#ifdef CONFIG_POSIX_TIMERS
spin_lock_irq(&me->sighand->siglock);
posix_cpu_timers_exit(me);
spin_unlock_irq(&me->sighand->siglock);
exit_itimers(me);
flush_itimer_signals();
#endif
...
scoped_guard(spinlock_irq, &me->sighand->siglock)
me->signal->flags &= ~SIGNAL_EXEC;
// SUCCESS
return 0;
and in posixtimer_send_sigqueue()
if (!likely(lock_task_sighand(t, &flags)))
return;
if (unlikely(t->signal->flags & (SIGNAL_EXEC)))
goto unlock;
and as we need that check anyway we can just make it:
if (unlikely(t->signal->flags & (SIGNAL_EXEC | SIGNAL_GROUP_EXIT)))
goto unlock;
because there is no point either to queue posix timer signals when
SIGNAL_GROUP_EXIT is set, right?
Something like the untested below. At least I'm sure that I got the
scoped_guard() types right this time.
FWIW, I briefly pondered to hide the first part in de_thread(), but
that just made my tired brain fail to reason about it.
Thanks,
tglx
---
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1148,6 +1148,9 @@ int begin_new_exec(struct linux_binprm *
*/
bprm->point_of_no_return = true;
+ scoped_guard(spinlock_irq, &me->sighand->siglock)
+ me->signal->flags |= SIGNAL_EXEC;
+
/* Make this the only thread in the thread group */
retval = de_thread(me);
if (retval)
@@ -1324,6 +1327,10 @@ int begin_new_exec(struct linux_binprm *
}
bprm->execfd = retval;
}
+
+ scoped_guard(spinlock_irq, &me->sighand->siglock)
+ me->signal->flags &= ~SIGNAL_EXEC;
+
return 0;
out_unlock:
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -261,6 +261,8 @@ struct signal_struct {
#define SIGNAL_STOP_STOPPED 0x00000001 /* job control stop in effect */
#define SIGNAL_STOP_CONTINUED 0x00000002 /* SIGCONT since WCONTINUED reap */
#define SIGNAL_GROUP_EXIT 0x00000004 /* group exit in progress */
+#define SIGNAL_EXEC 0x00000008 /* exec in progress */
+
/*
* Pending notifications to parent.
*/
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1991,6 +1991,20 @@ void posixtimer_send_sigqueue(struct k_i
return;
/*
+ * If the process is in the middle of exec(), don't queue signals as the
+ * posix timers of this process are not longer accessible and about to
+ * be removed. This prevents a race between queueing the signal on a
+ * exiting former thread group leader in case of an non-leader exec.
+ * Aside of that it makes no sense to queue anything now when it has to
+ * be flushed a split second later anyway.
+ *
+ * As this conditional is required just use the opportunity and check
+ * for a group exit too, where queueing signals is equally pointless.
+ */
+ if (unlikely(t->signal->flags & (SIGNAL_EXEC | SIGNAL_GROUP_EXIT)))
+ goto unlock;
+
+ /*
* Update @tmr::sigqueue_seq for posix timer signals with sighand
* locked to prevent a race against dequeue_signal().
*/
@@ -2081,6 +2095,7 @@ void posixtimer_send_sigqueue(struct k_i
result = TRACE_SIGNAL_DELIVERED;
out:
trace_signal_generate(sig, &q->info, t, tmr->it_pid_type != PIDTYPE_PID, result);
+unlock:
unlock_task_sighand(t, &flags);
}
next prev parent reply other threads:[~2026-08-25 19:58 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-22 5:37 [PATCH] signal: Use list_del_init_careful() in flush_sigqueue() Hyunwoo Kim
2026-08-22 10:27 ` Bradley Morgan
2026-08-23 12:47 ` Oleg Nesterov
2026-08-24 2:53 ` Hyunwoo Kim
2026-08-24 8:28 ` Oleg Nesterov
2026-08-24 8:04 ` Thomas Gleixner
2026-08-24 9:45 ` Thomas Gleixner
2026-08-24 11:02 ` Oleg Nesterov
2026-08-24 11:54 ` Oleg Nesterov
2026-08-24 13:59 ` Frederic Weisbecker
2026-08-24 14:29 ` Oleg Nesterov
2026-08-25 16:58 ` Thomas Gleixner
2026-08-25 18:53 ` Oleg Nesterov
2026-08-25 19:58 ` Thomas Gleixner [this message]
2026-08-26 9:36 ` Oleg Nesterov
2026-08-24 12:11 ` Thomas Gleixner
2026-08-24 16:31 ` Frederic Weisbecker
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=87fr02gegn.ffs@fw13 \
--to=tglx@kernel.org \
--cc=anna-maria@linutronix.de \
--cc=brauner@kernel.org \
--cc=ebiederm@xmission.com \
--cc=frederic@kernel.org \
--cc=imv4bel@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=oleg@redhat.com \
--cc=peterz@infradead.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.