summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2025-10-15 21:31:44 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-10-19 16:30:59 +0200
commitd0d9fa88d7ab7e3ef6adc4cb4d1419b7c2d8016f (patch)
treed2b8e2677b1d3bf940f64d7320a2b07541d30bde
parent1810b6084aea5ae95e68f0cce444485a17671129 (diff)
downloadlinux-d0d9fa88d7ab7e3ef6adc4cb4d1419b7c2d8016f.tar.gz
linux-d0d9fa88d7ab7e3ef6adc4cb4d1419b7c2d8016f.tar.bz2
linux-d0d9fa88d7ab7e3ef6adc4cb4d1419b7c2d8016f.zip
rseq: Protect event mask against membarrier IPI
[ Upstream commit 6eb350a2233100a283f882c023e5ad426d0ed63b ] rseq_need_restart() reads and clears task::rseq_event_mask with preemption disabled to guard against the scheduler. But membarrier() uses an IPI and sets the PREEMPT bit in the event mask from the IPI, which leaves that RMW operation unprotected. Use guard(irq) if CONFIG_MEMBARRIER is enabled to fix that. Fixes: 2a36ab717e8f ("rseq/membarrier: Add MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ") Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Boqun Feng <boqun.feng@gmail.com> Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: stable@vger.kernel.org [ Applied changes to include/linux/sched.h instead of include/linux/rseq.h ] Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--include/linux/sched.h11
-rw-r--r--kernel/rseq.c10
2 files changed, 13 insertions, 8 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h
index cb38eee732fd..9559501236af 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -2343,6 +2343,12 @@ enum rseq_event_mask {
RSEQ_EVENT_MIGRATE = (1U << RSEQ_EVENT_MIGRATE_BIT),
};
+#ifdef CONFIG_MEMBARRIER
+# define RSEQ_EVENT_GUARD irq
+#else
+# define RSEQ_EVENT_GUARD preempt
+#endif
+
static inline void rseq_set_notify_resume(struct task_struct *t)
{
if (t->rseq)
@@ -2361,9 +2367,8 @@ static inline void rseq_handle_notify_resume(struct ksignal *ksig,
static inline void rseq_signal_deliver(struct ksignal *ksig,
struct pt_regs *regs)
{
- preempt_disable();
- __set_bit(RSEQ_EVENT_SIGNAL_BIT, &current->rseq_event_mask);
- preempt_enable();
+ scoped_guard(RSEQ_EVENT_GUARD)
+ __set_bit(RSEQ_EVENT_SIGNAL_BIT, &current->rseq_event_mask);
rseq_handle_notify_resume(ksig, regs);
}
diff --git a/kernel/rseq.c b/kernel/rseq.c
index 23894ba8250c..810005f927d7 100644
--- a/kernel/rseq.c
+++ b/kernel/rseq.c
@@ -255,12 +255,12 @@ static int rseq_need_restart(struct task_struct *t, u32 cs_flags)
/*
* Load and clear event mask atomically with respect to
- * scheduler preemption.
+ * scheduler preemption and membarrier IPIs.
*/
- preempt_disable();
- event_mask = t->rseq_event_mask;
- t->rseq_event_mask = 0;
- preempt_enable();
+ scoped_guard(RSEQ_EVENT_GUARD) {
+ event_mask = t->rseq_event_mask;
+ t->rseq_event_mask = 0;
+ }
return !!event_mask;
}