| From stable+bounces-185872-greg=kroah.com@vger.kernel.org Thu Oct 16 03:31:59 2025 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 15 Oct 2025 21:31:44 -0400 |
| Subject: rseq: Protect event mask against membarrier IPI |
| To: stable@vger.kernel.org |
| Cc: Thomas Gleixner <tglx@linutronix.de>, Boqun Feng <boqun.feng@gmail.com>, Mathieu Desnoyers <mathieu.desnoyers@efficios.com>, Sasha Levin <sashal@kernel.org> |
| Message-ID: <20251016013144.1560902-1-sashal@kernel.org> |
| |
| From: Thomas Gleixner <tglx@linutronix.de> |
| |
| [ 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> |
| --- |
| include/linux/sched.h | 11 ++++++++--- |
| kernel/rseq.c | 10 +++++----- |
| 2 files changed, 13 insertions(+), 8 deletions(-) |
| |
| --- 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_re |
| static inline void rseq_signal_deliver(struct ksignal *ksig, |
| struct pt_regs *regs) |
| { |
| - preempt_disable(); |
| - __set_bit(RSEQ_EVENT_SIGNAL_BIT, ¤t->rseq_event_mask); |
| - preempt_enable(); |
| + scoped_guard(RSEQ_EVENT_GUARD) |
| + __set_bit(RSEQ_EVENT_SIGNAL_BIT, ¤t->rseq_event_mask); |
| rseq_handle_notify_resume(ksig, regs); |
| } |
| |
| --- a/kernel/rseq.c |
| +++ b/kernel/rseq.c |
| @@ -255,12 +255,12 @@ static int rseq_need_restart(struct task |
| |
| /* |
| * 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; |
| } |