From: Arjan van de Ven Subject: [PATCH] net: rose: cancel timers before freeing rose_neigh in rose_neigh_put() This patch is based on a KASAN slab-use-after-free as reported by syzbot at https://lore.kernel.org/r/69ef2847.170a0220.11de9.001a.GAE@google.com. rose_neigh_put() was introduced by d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t") to free rose_neigh when its refcount drops to zero. The struct rose_neigh embeds two timer_list fields (ftimer and t0timer) that may still be pending in the timer wheel when the final rose_neigh_put() is called from rose_timer_expiry() in softirq context. The race is: CPU 0 (TIMER_SOFTIRQ, one batch): 1. rose_timer_expiry() handles ROSE_STATE_2: rose_neigh_put(rose->neighbour) -> refcount_dec_and_test() returns true -> kfree(rose_neigh->digipeat) /* frees ax25_digi */ -> kfree(rose_neigh) 2. rose_t0timer_expiry() fires next in the same batch: neigh = timer_container_of(neigh, t, t0timer) /* dangling */ rose_transmit_restart_request(neigh) -> rose_send_frame() passes neigh->digipeat to ax25_send_frame() -> kmemdup(digi, 66, GFP_ATOMIC) /* UAF read */ Before commit d860d1faa6b2, rose_timer_expiry() only decremented the plain 'use' counter without ever freeing the struct; the free was always done by rose_remove_neigh() which calls timer_delete_sync() on both timers before freeing. The refcount conversion introduced a new free path from softirq context that omitted the timer cancellation. Cancel both timers inside rose_neigh_put() before freeing, mirroring rose_remove_neigh(). timer_delete() (non-synchronous) is required because rose_neigh_put() may be called from softirq context where timer_delete_sync() would deadlock. The cancellation is safe: after refcount_dec_and_test() returns true no other thread holds a reference, so no new timer arm can occur before the kfree. Reported-by: syzbot+9c8999af06ca7df15fc6@syzkaller.appspotmail.com Link: https://lore.kernel.org/r/69ef2847.170a0220.11de9.001a.GAE@google.com Oops-Analysis: http://oops.fenrus.org/reports/lkml/69ef2847.170a0220.11de9.001a.GAE_google.com/report.html Fixes: d860d1faa6b2 ("net: rose: convert 'use' field to refcount_t") Assisted-by: Copilot:claude-sonnet-4.6 linux-kernel-oops-x86. Signed-off-by: Arjan van de Ven Cc: linux-hams@vger.kernel.org Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: "David S. Miller" Cc: Eric Dumazet --- include/net/rose.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/net/rose.h b/include/net/rose.h index 2b5491bbf39a..93a26b08e648 100644 --- a/include/net/rose.h +++ b/include/net/rose.h @@ -160,6 +160,8 @@ static inline void rose_neigh_hold(struct rose_neigh *rose_neigh) static inline void rose_neigh_put(struct rose_neigh *rose_neigh) { if (refcount_dec_and_test(&rose_neigh->use)) { + timer_delete(&rose_neigh->ftimer); + timer_delete(&rose_neigh->t0timer); if (rose_neigh->ax25) ax25_cb_put(rose_neigh->ax25); kfree(rose_neigh->digipeat); -- 2.43.0