Re: gpio: gpiolib: final put of the gpio_device happens inside the SRCU read critical section on the setup-failure path -- deterministic use-after-free read at guard release (unfixed upstream)

From: Linus Walleij

Date: Thu Nov 05 2026 - 03:57:16 EST


On Tue, Nov 3, 2026 at 1:10 PM 徐晗翔 <xuhx@xxxxxxxxxxx> wrote:

> On gpiolib's setup-failure path, the guard that protects the
> gpio_device lookup (srcu_read_lock at gpiolib.c:1094) is also held
> while the device is being torn down: gpiochip_setup_devs()'s error
> path drops the last reference (gpiodev_release at :893-906, which
> calls cleanup_srcu_struct at :904 and kfree at :905) while the
> caller's guard is still inside the read critical section -- so the
> guard's own release (srcu_read_unlock) reads ssp->sda out of an
> already freed gpio_device. In the hog path the refcount can be
> exactly 1 at that point, which is the common case, so this is not
> an exotic window: it is a sequential-ordering violation that fires
> whenever that error path is taken, no concurrency needed. On a
> stock 7.3 KASAN kernel, replaying gpiolib's exact single-threaded
> statement sequence 1:1 (lock at the :1094 guard point -> the :904
> cleanup -> the :905 kfree -> the guard's unlock) hits
> WARNING: kernel/rcu/srcutree.c:696 at cleanup_srcu_struct (the
> self-held-reader defensive branch: sda and srcu_sup leaked, not
> freed), and the subsequent srcu_read_unlock produces
> BUG: KASAN: slab-use-after-free in __srcu_read_unlock+0x1a reading
> object+8 -- exactly the ssp->sda field of the freed container. The
> setup-failure path also misses the list_del_rcu() that the success
> path performs, so the destroyed device can remain reachable through
> the global list. As far as I can tell this is unfixed upstream.
>
> The detailed description:
> * The ordering (Linux 7.3, drivers/gpio/gpiolib.c)
> The caller takes the lookup guard (srcu_read_lock, :1094), then
> gpiochip_setup_devs() fails (e.g. cdev/hog registration errors),
> and the error path drops the final reference;
> gpiodev_release() runs cleanup_srcu_struct(&gdev->srcu) at :904
> and kfree(gdev) at :905 -- while the caller is still inside the
> SRCU read critical section it took at :1094. When the caller's
> guard destructs, srcu_read_unlock(&gdev->srcu, idx) touches the
> freed object (reads ssp->sda at object offset +8). The hog path
> leaves refcount==1 here as the common case (no other holders
> yet), so the final put is genuinely final.
> Secondary: the failure path lacks the list_del_rcu() the success
> path performs, leaving the freed device linked.
>
> * Evidence (stock 7.3 KASAN; deterministic, single-threaded;
> reproducer attached)
> gpiodevsim.c replays gpiolib's own sequence with a kzalloc'd
> container of the same layout: srcu_read_lock (the :1094 guard) ->
> cleanup_srcu_struct (the :904 call; hits the srcutree.c:696
> WARNING -- the library's own "reader still inside" defense
> triggers, leaking sda/srcu_sup exactly as the source predicts) ->
> kfree (the :905 call) -> srcu_read_unlock (the guard's
> destructor):
> WARNING: kernel/rcu/srcutree.c:696 at cleanup_srcu_struct
> (leak branch: srcu.sda non-NULL, srcu.srcu_sup non-NULL)
> BUG: KASAN: slab-use-after-free in __srcu_read_unlock+0x1a
> Read of size 8, address = object+8 == the ssp->sda field
> alloc: insmod kzalloc; free: the kfree step above
> One run, no interleaving, no kprobe parking -- the violation is
> in the ordering itself.

TL;DR, Dostoyevsky commit, make it terse and human-readable,
inline the patch do not send it as an attachment.

Yours,
Linus Walleij