Re: [PATCH] locking/mutex: Restore RCU read-side protection for optimistic spinning

From: Peter Zijlstra

Date: Tue Aug 25 2026 - 05:26:48 EST


On Tue, Aug 25, 2026 at 05:13:30PM +0800, Yang Zi wrote:
> The optimistic spinning paths in kernel/locking/mutex.c dereference the
> current lock owner's task_struct (via owner_on_cpu() -> owner->on_cpu and
> task_cpu(owner)) without any lifetime protection on the owner pointer.
>
> __mutex_owner() (kernel/locking/mutex.h) returns a bare task_struct
> pointer that is read directly from lock->owner. mutex_spin_on_owner() and
> mutex_can_spin_on_owner() then dereference it inside "while
> (__mutex_owner(lock) == owner)" / immediately after the owner load, while
> relying only on preempt_disable().
>
> Since commit 6c2787f2a20c ("locking: Remove rcu_read_{,un}lock() for
> preempt_{dis,en}able()"), the code has assumed that preempt_disable() is
> equivalent to an RCU read-side critical section and therefore that the
> owner's task_struct "won't go away during the spinning period". That
> assumption does not hold on PREEMPT_LAZY kernels: preempt_disable() there
> no longer actually disables preemption, so the RCU callback that frees a
> just-exited owner's task_struct (put_task_struct_rcu_user() ->
> call_rcu(), run in rcu_do_batch()) can fire and free the object while a
> spinner still holds the stale pointer, leading to a slab use-after-free
> read of owner->on_cpu.

This doesn't make sense, rcu_preempt was subsumed (again) into regular
rcu proper (along with rcu_bh). Any preempt disable region will prohibit
the GP from advancing.