Commit ac8777cc3622 for kernel

commit ac8777cc36224b4705d2c6efb10c56135d479b21
Merge: 9a466382c5e1 07422c948f4b
Author: Christian Brauner <brauner@kernel.org>
Date:   Fri Apr 24 00:29:48 2026 +0200

    Merge patch series "eventpoll: fix ep_remove() UAF and follow-up cleanup"

    Christian Brauner <brauner@kernel.org> says:

    ep_remove() (via __ep_remove_file()) cleared file->f_ep under
    file->f_lock but then kept using @file in the same critical section:
    is_file_epoll(), hlist_del_rcu() through the head, spin_unlock. A
    concurrent __fput() on the watched eventpoll caught the transient
    NULL in eventpoll_release()'s lockless fast path, skipped
    eventpoll_release_file() entirely, and ran to ep_eventpoll_release()
    -> ep_clear_and_put() -> ep_free(). That kfree()s the struct
    eventpoll whose embedded ->refs hlist_head is exactly where
    epi->fllink.pprev points and the subsequent hlist_del_rcu()'s
    "*pprev = next" scribbles into freed kmalloc-192 memory, which is
    the slab-use-after-free KASAN caught.

    struct file is SLAB_TYPESAFE_BY_RCU on top of that so the same window
    also lets the slot recycle while ep_remove() is still nominally
    inside file->f_lock. The upshot is an attacker-influencable
    kmem_cache_free() against the wrong slab cache.

    The comment on eventpoll_release()'s fast path - "False positives
    simply cannot happen because the file in on the way to be removed
    and nobody ( but eventpoll ) has still a reference to this file" -
    was itself the wrong invariant this race exploits.

    The fix pins @file via epi_fget() at the top of ep_remove() and
    gates the f_ep clear / hlist_del_rcu() on the pin succeeding. With
    the pin held __fput() cannot start which transitively keeps the
    watched struct eventpoll alive across the critical section and also
    prevents the struct file slot from recycling. Both UAFs are closed.

    If the pin fails __fput() is already in flight on @file. Because we
    bail before clearing f_ep that path takes eventpoll_release()'s slow
    path into eventpoll_release_file() which blocks on ep->mtx until
    ep_clear_and_put() drops it and then cleans up the orphaned epi. The
    bailed epi's share of ep->refcount stays intact so
    ep_clear_and_put()'s trailing ep_refcount_dec_and_test() cannot free
    the eventpoll out from under eventpoll_release_file().

    With epi_fget() now gating every ep_remove() call the epi->dying
    flag becomes vestigial. epi->dying == true always coincides with
    file_ref_get() == false because __fput() is reachable only once the
    refcount hits zero and the refcount is monotone there. The last
    patch drops the flag and leaves a single coordination mechanism
    instead of two.

    * patches from https://patch.msgid.link/20260423-work-epoll-uaf-v1-0-2470f9eec0f5@kernel.org:
      eventpoll: drop vestigial epi->dying flag
      eventpoll: drop dead bool return from __ep_remove_epi()
      eventpoll: refresh eventpoll_release() fast-path comment
      eventpoll: move f_lock acquisition into __ep_remove_file()
      eventpoll: fix ep_remove struct eventpoll / struct file UAF
      eventpoll: move epi_fget() up
      eventpoll: rename ep_remove_safe() back to ep_remove()
      eventpoll: kill __ep_remove()
      eventpoll: split __ep_remove()
      eventpoll: use hlist_is_singular_node() in __ep_remove()

    Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-0-2470f9eec0f5@kernel.org
    Signed-off-by: Christian Brauner <brauner@kernel.org>