[PATCH net] can: j1939: fix skb refcount underflow in session teardown paths
From: Tristan Madani
Date: Mon Nov 02 2026 - 12:03:03 EST
j1939_session_destroy() and j1939_session_skb_drop_old() both call
skb_unref() followed by kfree_skb() on session-queued skbs. Since
kfree_skb() already handles the refcount decrement internally via
skb_unref(), the preceding explicit skb_unref() causes a double
decrement, triggering a refcount underflow warning on every session
teardown.
The extra skb_get() reference taken in j1939_session_skb_queue() needs
exactly one corresponding release. kfree_skb() provides that single
release by decrementing the refcount and freeing the skb when it reaches
zero. Remove the redundant skb_unref() calls in both teardown paths.
Fixes: 8c21c54a53ab ("can: j1939: j1939_session_destroy(): fix memory leak of skbs")
Fixes: 2030043e616c ("can: j1939: fix Use-after-Free, hold skb ref while in use")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Tristan Madani <tristan@xxxxxxxxxxxxxxxxxxx>
---
net/can/j1939/transport.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
index 8fcfd13e5e6f8..3173936bd6f6e 100644
--- a/net/can/j1939/transport.c
+++ b/net/can/j1939/transport.c
@@ -277,11 +277,8 @@ static void j1939_session_destroy(struct j1939_session *session)
WARN_ON_ONCE(!list_empty(&session->sk_session_queue_entry));
WARN_ON_ONCE(!list_empty(&session->active_session_list_entry));
- while ((skb = skb_dequeue(&session->skb_queue)) != NULL) {
- /* drop ref taken in j1939_session_skb_queue() */
- skb_unref(skb);
+ while ((skb = skb_dequeue(&session->skb_queue)) != NULL)
kfree_skb(skb);
- }
__j1939_session_drop(session);
netdev_put(session->priv->ndev, &session->priv_dev_tracker);
j1939_priv_put(session->priv);
@@ -342,8 +339,6 @@ static void j1939_session_skb_drop_old(struct j1939_session *session)
if ((do_skcb->offset + do_skb->len) < offset_start) {
__skb_unlink(do_skb, &session->skb_queue);
- /* drop ref taken in j1939_session_skb_queue() */
- skb_unref(do_skb);
spin_unlock_irqrestore(&session->skb_queue.lock, flags);
kfree_skb(do_skb);
--
2.47.3