Netdev List
 help / color / mirror / Atom feed
* [PATCH net v3] tipc: fix refcount panic in tipc_rcv() when receiving shared skb
@ 2026-10-22  1:15 Tung Nguyen
  2026-10-22 17:20 ` Eric Dumazet
  2026-10-23  2:03 ` netdev-bot+sashiko
  0 siblings, 2 replies; 3+ messages in thread
From: Tung Nguyen @ 2026-10-22  1:15 UTC (permalink / raw)
  To: netdev
  Cc: davem, kuba, edumazet, pabeni, jmaloy, horms, tipc-discussion,
	Tung Nguyen, syzbot+0017742620a9d06f06ef, Nguyen Ngoc Thang

TIPC assumes that the received skb is not shared with other users.
However, syzbot reports a bug triggered by receiving a shared skb:

...
RIP: 0010:pskb_expand_head+0x135a/0x13a0 net/core/skbuff.c:2308
__pskb_pull_tail+0x111/0x1870 net/core/skbuff.c:2890
skb_cow_data+0x2ed/0xc50 net/core/skbuff.c:5398
tipc_aead_decrypt net/tipc/crypto.c:892 [inline]
tipc_crypto_rcv+0x346/0x23d0 net/tipc/crypto.c:1843
tipc_rcv+0x4b7/0x1040 net/tipc/node.c:2119
tipc_l2_rcv_msg+0x2d9/0x470 net/tipc/bearer.c:669
deliver_ptype_list_skb net/core/dev.c:2533 [inline]
...

The root cause is that local delivery hooks in the kernel (e.g.,
deliver_skb()) may increment the skb's reference count (`users`) before
TIPC processes it on ingress.

Fix this by calling skb_share_check() to ensure exclusive ownership
before passing the skb to tipc_rcv(). As TIPC needs to modify the skb's
data, the cloned skb needs to be uncloned in tipc_sk_conn_proto_rcv(),
tipc_sk_filter_connect(), tipc_msg_lookup_dest() and tipc_link_tnl_rcv().

Reported-by: syzbot+0017742620a9d06f06ef@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=0017742620a9d06f06ef
Closes: https://lore.kernel.org/all/20261018145928.58317-1-ngocthang2710.1999@gmail.com/T/
Fixes: 6e967adf798a ("tipc: relocate common functions from media to bearer")
Co-developed-by: Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com>
Signed-off-by: Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com>
Signed-off-by: Tung Nguyen <tung.quang.nguyen@est.tech>
---
v3: Use skb_share_check() to unshare the skb and unclone that skb
    when needed.
v2: https://lore.kernel.org/all/20261020104852.90350-1-tung.quang.nguyen@est.tech/
v1: https://lore.kernel.org/all/20261019050648.287309-1-tung.quang.nguyen@est.tech/

 net/tipc/bearer.c |  4 ++++
 net/tipc/link.c   |  7 +++++++
 net/tipc/msg.c    |  3 +++
 net/tipc/socket.c | 10 ++++++++++
 4 files changed, 24 insertions(+)

diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 05dcd2f9e887..5e7e220fa7f5 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -659,6 +659,10 @@ static int tipc_l2_rcv_msg(struct sk_buff *skb, struct net_device *dev,
 {
 	struct tipc_bearer *b;
 
+	skb = skb_share_check(skb, GFP_ATOMIC);
+	if (!skb)
+		return NET_RX_DROP;
+
 	rcu_read_lock();
 	b = rcu_dereference(dev->tipc_ptr) ?:
 		rcu_dereference(orig_dev->tipc_ptr);
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 6427c69f8929..d7ce384d3b89 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -1363,6 +1363,13 @@ static int tipc_link_tnl_rcv(struct tipc_link *l, struct sk_buff *skb,
 		}
 		kfree_skb(skb);
 	} else {
+		if (skb_unclone(skb, GFP_ATOMIC) == -ENOMEM) {
+			kfree_skb(skb);
+			return tipc_link_fsm_evt(l, LINK_FAILURE_EVT);
+		}
+
+		hdr = buf_msg(skb);
+
 		/* Set fragment type for buf_append */
 		if (msg_fragm_no(hdr) == 1)
 			msg_set_type(hdr, FIRST_FRAGMENT);
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index b0bba0feef56..9a222e15ed31 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -736,6 +736,9 @@ bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, int *err)
 	sk.node = tipc_scope2node(net, scope);
 	if (!tipc_nametbl_lookup_anycast(net, &ua, &sk))
 		return false;
+	if (skb_unclone(skb, GFP_ATOMIC) == -ENOMEM)
+		return false;
+	msg = buf_msg(skb);
 	msg_incr_reroute_cnt(msg);
 	if (sk.node != self)
 		msg_set_prevnode(msg, self);
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index d5d70eb230b5..9789d1ce6bd4 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -1345,6 +1345,10 @@ static void tipc_sk_conn_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
 				      tsk_peer_port(tsk));
 		sk->sk_state_change(sk);
 
+		if (skb_unclone(skb, GFP_ATOMIC) == -ENOMEM)
+			goto exit;
+		hdr = buf_msg(skb);
+
 		/* State change is ignored if socket already awake,
 		 * - convert msg to abort msg and add to inqueue
 		 */
@@ -1359,6 +1363,9 @@ static void tipc_sk_conn_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,
 	tsk->probe_unacked = false;
 
 	if (mtyp == CONN_PROBE) {
+		if (skb_unclone(skb, GFP_ATOMIC) == -ENOMEM)
+			goto exit;
+		hdr = buf_msg(skb);
 		msg_set_type(hdr, CONN_PROBE_REPLY);
 		if (tipc_msg_reverse(onode, &skb, TIPC_OK))
 			__skb_queue_tail(xmitq, skb);
@@ -2223,6 +2230,9 @@ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb,
 				return true;
 			/* Empty ACK-, - wake up sleeping connect() and drop */
 			sk->sk_state_change(sk);
+			if (skb_unclone(skb, GFP_ATOMIC) == -ENOMEM)
+				break;
+			hdr = buf_msg(skb);
 			msg_set_dest_droppable(hdr, 1);
 			return false;
 		}
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-10-23  2:03 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-22  1:15 [PATCH net v3] tipc: fix refcount panic in tipc_rcv() when receiving shared skb Tung Nguyen
2026-10-22 17:20 ` Eric Dumazet
2026-10-23  2:03 ` netdev-bot+sashiko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox