Re: [PATCH v1] irq_work: Fix use-after-free in irq_work_single on PREEMPT_RT
From: Jiayuan Chen
Date: Wed Mar 25 2026 - 22:27:28 EST
On 3/26/26 1:59 AM, Sebastian Andrzej Siewior wrote:
On 2026-03-25 13:55:40 [-0400], Steven Rostedt wrote:Combining your and Steven's suggestions, I think the simplest fix would be:
On Wed, 25 Mar 2026 18:51:50 +0100I was thinking about your helper doing synchronize_rcu().
Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> wrote:
Oh, I was talking about how the patch open coded rcuwait (which we shouldn't do).Perhaps Jiayuan's idea is better as it will not require modifying currentDon't you need to replace irq_work_sync() with this new one?
callers and does fix the issue.
But it would still need helper functions from RCU as I really do not thinkWhy is rcuwait a concern?
it's a good idea to open code the rcuwait logic.
Are you saying that if we stick a synchronize_rcu() in irq_work_sync() that
could work too?
I haven't looked at irq_work_sync() but it would need solve the problem,
too. There shouldn't be any user of irq_work_sync() which does not
intend to free the object, why else should they wait, right? So it might
be even simpler.
static void run_irq_workd(unsigned int cpu)
{
+ guard(rcu)();
irq_work_run_list(this_cpu_ptr(&lazy_list));
}
void irq_work_sync(struct irq_work *work)
{
lockdep_assert_irqs_enabled();
might_sleep();
if ((IS_ENABLED(CONFIG_PREEMPT_RT) && !irq_work_is_hard(work)) ||
!arch_irq_work_has_interrupt()) {
rcuwait_wait_event(&work->irqwait, !irq_work_is_busy(work),
TASK_UNINTERRUPTIBLE);
+ /*
+ * Ensure run_irq_workd() / irq_work_single() is done
+ * accessing @work before the caller can free it.
+ */
+ synchronize_rcu();
return;
}
while (irq_work_is_busy(work))
cpu_relax();
}