Conversation
rose_transmit_link() queues an outgoing frame on rose_neigh->queue instead of sending it immediately whenever the neighbour isn't "restarted" yet (link not up) -- notably the CLEAR_REQUEST built by rose_write_internal() when a socket is released (e.g. its owning process is killed) while the underlying AX.25 link to that neighbour is still coming up. rose_neigh_put() already tears down both timers and drops the ax25/ digipeat references before freeing the neighbour, but never empties this queue. kfree(rose_neigh) only frees the rose_neigh struct itself (the sk_buff_head embedded in it is just three next/prev/len words), not the skbs still linked into it -- every frame still queued here at that point leaks for good. rose_remove_neigh() (rose_route.c) already purges this same queue, but it is only one of about two dozen call sites that can drop the last reference and trigger the real kfree() in rose_neigh_put() -- every socket releasing its own rose->neighbour reference (af_rose.c, rose_in.c, rose_timer.c) can just as well be the one that does. Doing the purge once, centrally, in rose_neigh_put() itself covers all of them regardless of which call site happens to be last, rather than relying on whichever caller happened to remember it. Matches a leak pattern observed and documented back in May 2026 (mailbbs killed -> rose_release() -> rose_write_internal() -> rose_transmit_link() queues the CLEAR_REQUEST -> skb never freed), never root-caused until now. Deployed and running since 2026-09-13/15 on three independent nodes (f6bvp-12, f6bvp-8, f6bvp-10 -- three different kernel bases, 6.12.94/6.18.46/6.18.34), no regression observed. Signed-off-by: F6BVP <bernard.f6bvp@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
rose_transmit_link() queues an outgoing frame on rose_neigh->queue
instead of sending it immediately whenever the neighbour isn't
"restarted" yet (link not up) -- notably the CLEAR_REQUEST built by
rose_write_internal() when a socket is released (e.g. its owning
process is killed) while the underlying AX.25 link to that neighbour
is still coming up.
rose_neigh_put() already tears down both timers and drops the ax25/
digipeat references before freeing the neighbour, but never empties
this queue. kfree(rose_neigh) only frees the rose_neigh struct itself
(the sk_buff_head embedded in it is just three next/prev/len words),
not the skbs still linked into it -- every frame still queued here at
that point leaks for good.
rose_remove_neigh() (rose_route.c) already purges this same queue, but
it is only one of about two dozen call sites that can drop the last
reference and trigger the real kfree() in rose_neigh_put() -- every
socket releasing its own rose->neighbour reference (af_rose.c,
rose_in.c, rose_timer.c) can just as well be the one that does. Doing
the purge once, centrally, in rose_neigh_put() itself covers all of
them regardless of which call site happens to be last, rather than
relying on whichever caller happened to remember it.
Matches a leak pattern observed and documented back in May 2026
(mailbbs killed -> rose_release() -> rose_write_internal() ->
rose_transmit_link() queues the CLEAR_REQUEST -> skb never freed),
never root-caused until now.
Testing: deployed on three independent nodes since 2026-09-13/15
(three different kernel bases -- 6.12.94, 6.18.46, 6.18.34), running
live production ROSE traffic since, no regression observed.