Skip to content

Commit 9e8fc21

Browse files
f6bvpgregkh
authored andcommitted
rose: cancel neighbour timers in rose_neigh_put() before freeing
commit 9b222cb1d23ff210975e9df5ebab7b011acb6fad upstream. rose_neigh_put() kfree()s the neighbour but never cancels its ftimer and t0timer. Until now every caller that dropped the final reference first called rose_remove_neigh(), which deletes those timers. The socket heartbeat reaping path drops the last reference directly, so a neighbour could be freed with t0timer still armed -- it re-arms itself in rose_t0timer_expiry() -- leading to a use-after-free write in enqueue_timer(). Cancel both timers with timer_delete_sync() (the synchronous variant, to wait out a concurrently running, self-rearming handler) in the refcount-zero branch of rose_neigh_put(). Signed-off-by: Bernard Pidoux <bernard.f6bvp@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent c31a0fa commit 9e8fc21

1 file changed

Lines changed: 12 additions & 0 deletions

File tree

include/net/rose.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,18 @@ static inline void rose_neigh_hold(struct rose_neigh *rose_neigh)
160160
static inline void rose_neigh_put(struct rose_neigh *rose_neigh)
161161
{
162162
if (refcount_dec_and_test(&rose_neigh->use)) {
163+
/* We are dropping the last reference, so we are about to free the
164+
* neighbour. Its timers may still be armed -- t0timer in particular
165+
* re-arms itself in rose_t0timer_expiry(). rose_remove_neigh()
166+
* cancels them before its own put, but callers that drop the final
167+
* reference without first calling rose_remove_neigh() (the socket
168+
* heartbeat reaping path) would otherwise kfree() a neighbour with a
169+
* live timer -> use-after-free. timer_delete_sync() (not the async
170+
* variant) is required: it waits out a concurrently running handler
171+
* and loops until the self-rearming timer stays stopped.
172+
*/
173+
timer_delete_sync(&rose_neigh->ftimer);
174+
timer_delete_sync(&rose_neigh->t0timer);
163175
if (rose_neigh->ax25)
164176
ax25_cb_put(rose_neigh->ax25);
165177
kfree(rose_neigh->digipeat);

0 commit comments

Comments
 (0)