From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ot1-f70.google.com (mail-ot1-f70.google.com [209.85.210.70]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C36993A4F2F for ; Thu, 23 Jul 2026 06:08:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.70 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784786918; cv=none; b=AAddCu6vHdx6isxcOtdGQafkiLolQE0xxIubsxcpW9mFXG15KR/48n7WG5aCLb6M30Oiimgm33NYjLx5bb61IE18X9a6RD3tvucwxgBPc5oGj1jSwLm6dLL/jR5fN30PBHZk+u/1RwjKgO0PQHOzb2f+jwNhNLlM5CxO7rXhtq4= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784786918; c=relaxed/simple; bh=ZIQ8WgqnUPUX+euoT8lxHMtvvTtAC2Cvfeovj1InG4Y=; h=MIME-Version:Date:In-Reply-To:Message-ID:Subject:From:To: Content-Type; b=Z8k27Hf+GmETBKB0rHrhbreVEfc//TTNmx85Wz1d0QexYQvNe2hKJb9WaEbR/IPMELZBlqV0G2LSyvjEoKIdE6kHFcVWhzON+7yXnNHQug9u9keeD8ATRcHJFfwgYLvzC+vp6/TYdg/7xjmO0FKhZtadGTf03O/JBRnt4sGurnA= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=syzkaller.appspotmail.com; spf=pass smtp.mailfrom=M3KW2WVRGUFZ5GODRSRYTGD7.apphosting.bounces.google.com; arc=none smtp.client-ip=209.85.210.70 Authentication-Results: smtp.subspace.kernel.org; dmarc=fail (p=none dis=none) header.from=syzkaller.appspotmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=M3KW2WVRGUFZ5GODRSRYTGD7.apphosting.bounces.google.com Received: by mail-ot1-f70.google.com with SMTP id 46e09a7af769-7eb650e79adso385020a34.3 for ; Wed, 22 Jul 2026 23:08:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784786915; x=1785391715; h=content-type:to:from:subject:message-id:in-reply-to:date :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to:content-type; bh=4K7RzFa1zonz7pRbRw0UZCF9dE81eSb8tYc1l6D7cds=; b=tJH4JtxAdUPijqZx6yisIzQsfKivE6LFtsYE2EsIihkNdxK6MlK3ZUKqSVSCLnGQ/V ZQgbqO/2wU9jOPf3f1iLu7STi+n/b56iS+sIltih/54RHzm4xRiJr5wS4LqY7pmhI9y0 FoKpC5hO4NY4QO/KCRPPDjMQPh055Su72RsGDx5UfD8JmHE2IYHw1YxZDRyXYrfG7BiO QXDP9rzius33oSTi5sbFNJ3dXTWGTQd+e/E/sGh8ptBZ0H0IcPE+GqFf+J9fGd5HhuTw RnYzkEsfDIZYHdwD2Os7qC23QltSGxbieh/frK1qsgGGFz7Z5IY/B4w4bJVD4LumSc3s 9NeQ== X-Gm-Message-State: AOJu0YwBg3X2pm3dl+dvrS17IPW2bADsy5AUOOoTAxqDB47YrnuCzN30 C2B6Qbhv597f7siIpARFsGwS/QbtVgnZEiOo7gS+77ksDpyrD7BF4xXGWPD5lUiFFw/3HgBlDlX eNDJerkB+3V4XpXNwWT6MklbX8aJe2WoRpGykYfA3hV++1sSjxH7BwWk1Cxg= Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Received: by 2002:a05:6820:808:b0:6a3:8cf6:fe02 with SMTP id 006d021491bc7-6aad4106c45mr680622eaf.37.1784786915593; Wed, 22 Jul 2026 23:08:35 -0700 (PDT) Date: Wed, 22 Jul 2026 23:08:35 -0700 In-Reply-To: <6877daee.a70a0220.693ce.002d.GAE@google.com> X-Google-Appengine-App-Id: s~syzkaller X-Google-Appengine-App-Id-Alias: syzkaller Message-ID: <6a61afe3.16bfb6d0.3c48cb.000f.GAE@google.com> Subject: Forwarded: Re: [syzbot] [bpf?] [sctp?] [tipc?] INFO: rcu detected stall in sock_close (5) From: syzbot To: linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com Content-Type: text/plain; charset="UTF-8" For archival purposes, forwarding an incoming command email to linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com. *** Subject: Re: [syzbot] [bpf?] [sctp?] [tipc?] INFO: rcu detected stall in sock_close (5) Author: xuanqiang.luo@linux.dev From: luoxuanqiang tipc_sk_rcv() holds the destination socket spinlock while filtering incoming messages. The filter may flush the Nagle write backlog, and tipc_sk_push_backlog() currently transmits it immediately. For local delivery, that transmission re-enters tipc_sk_rcv(). A returned message can then target the socket locked by the outer receive call. Its spin_trylock_bh() never succeeds, the input skb is never dequeued, and the receive loop spins until an RCU stall is reported. Detach a pending write backlog while the socket lock is held and transmit it immediately after releasing the lock. Temporarily mark the socket congested while the queue is detached so concurrent senders cannot overtake it. Preserve real link congestion on -ELINKCONG; otherwise clear the temporary state and wake writers. Fixes: c0bceb97db9e ("tipc: add smart nagle feature") Reported-by: syzbot+9a29e1dba699b6f46a03@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=9a29e1dba699b6f46a03 Signed-off-by: luoxuanqiang #syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 248951ddc14de84de3910f9b13f51491a8cd91df --- net/tipc/socket.c | 69 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index e564341e0216..73c7c966c98c 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -156,7 +156,8 @@ static int tipc_sk_insert(struct tipc_sock *tsk); static void tipc_sk_remove(struct tipc_sock *tsk); static int __tipc_sendstream(struct socket *sock, struct msghdr *m, size_t dsz); static int __tipc_sendmsg(struct socket *sock, struct msghdr *m, size_t dsz); -static void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack); +static void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack, + struct sk_buff_head *deferq); static int tipc_wait_for_connect(struct socket *sock, long *timeo_p); static const struct proto_ops packet_ops; @@ -560,7 +561,7 @@ static void __tipc_shutdown(struct socket *sock, int error) !tsk_conn_cong(tsk))); /* Push out delayed messages if in Nagle mode */ - tipc_sk_push_backlog(tsk, false); + tipc_sk_push_backlog(tsk, false, NULL); /* Remove pending SYN */ __skb_queue_purge(&sk->sk_write_queue); @@ -1268,7 +1269,8 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq, /* tipc_sk_push_backlog(): send accumulated buffers in socket write queue * when socket is in Nagle mode */ -static void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack) +static void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack, + struct sk_buff_head *deferq) { struct sk_buff_head *txq = &tsk->sk.sk_write_queue; struct sk_buff *skb = skb_peek_tail(txq); @@ -1310,6 +1312,12 @@ static void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack) tsk->pkt_cnt += skb_queue_len(txq); tsk->snt_unacked += tsk->snd_backlog; tsk->snd_backlog = 0; + if (deferq) { + /* Block concurrent senders until the detached queue is sent. */ + tsk->cong_link_cnt = 1; + skb_queue_splice_tail_init(txq, deferq); + return; + } rc = tipc_node_xmit(net, txq, dnode, tsk->portid); if (rc == -ELINKCONG) tsk->cong_link_cnt = 1; @@ -1321,10 +1329,12 @@ static void tipc_sk_push_backlog(struct tipc_sock *tsk, bool nagle_ack) * @skb: pointer to message buffer. * @inputq: buffer list containing the buffers * @xmitq: output message area + * @deferq: socket write queue to transmit after releasing the socket lock */ static void tipc_sk_conn_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb, struct sk_buff_head *inputq, - struct sk_buff_head *xmitq) + struct sk_buff_head *xmitq, + struct sk_buff_head *deferq) { struct tipc_msg *hdr = buf_msg(skb); u32 onode = tsk_own_node(tsk); @@ -1367,7 +1377,7 @@ static void tipc_sk_conn_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb, goto exit; was_cong = tsk_conn_cong(tsk); - tipc_sk_push_backlog(tsk, msg_nagle_ack(hdr)); + tipc_sk_push_backlog(tsk, msg_nagle_ack(hdr), deferq); tsk->snt_unacked -= msg_conn_ack(hdr); if (tsk->peer_caps & TIPC_BLOCK_FLOWCTL) tsk->snd_win = msg_adv_win(hdr); @@ -2147,7 +2157,8 @@ static void tipc_sock_destruct(struct sock *sk) static void tipc_sk_proto_rcv(struct sock *sk, struct sk_buff_head *inputq, - struct sk_buff_head *xmitq) + struct sk_buff_head *xmitq, + struct sk_buff_head *deferq) { struct sk_buff *skb = __skb_dequeue(inputq); struct tipc_sock *tsk = tipc_sk(sk); @@ -2157,7 +2168,7 @@ static void tipc_sk_proto_rcv(struct sock *sk, switch (msg_user(hdr)) { case CONN_MANAGER: - tipc_sk_conn_proto_rcv(tsk, skb, inputq, xmitq); + tipc_sk_conn_proto_rcv(tsk, skb, inputq, xmitq, deferq); return; case SOCK_WAKEUP: tipc_dest_del(&tsk->cong_links, msg_orignode(hdr), 0); @@ -2165,7 +2176,7 @@ static void tipc_sk_proto_rcv(struct sock *sk, smp_wmb(); tsk->cong_link_cnt--; wakeup = true; - tipc_sk_push_backlog(tsk, false); + tipc_sk_push_backlog(tsk, false, deferq); break; case GROUP_PROTOCOL: tipc_group_proto_rcv(grp, &wakeup, hdr, inputq, xmitq); @@ -2189,10 +2200,12 @@ static void tipc_sk_proto_rcv(struct sock *sk, * @tsk: TIPC socket * @skb: pointer to message buffer. * @xmitq: for Nagle ACK if any + * @deferq: socket write queue to transmit after releasing the socket lock * Return: true if message should be added to receive queue, false otherwise */ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb, - struct sk_buff_head *xmitq) + struct sk_buff_head *xmitq, + struct sk_buff_head *deferq) { struct sock *sk = &tsk->sk; struct net *net = sock_net(sk); @@ -2256,7 +2269,7 @@ static bool tipc_sk_filter_connect(struct tipc_sock *tsk, struct sk_buff *skb, return false; case TIPC_ESTABLISHED: if (!skb_queue_empty(&sk->sk_write_queue)) - tipc_sk_push_backlog(tsk, false); + tipc_sk_push_backlog(tsk, false, deferq); /* Accept only connection-based messages sent by peer */ if (likely(con_msg && !err && pport == oport && pnode == onode)) { @@ -2329,6 +2342,7 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *skb) * @sk: socket * @skb: pointer to message. * @xmitq: output message area (FIXME) + * @deferq: socket write queue to transmit after releasing the socket lock * * Enqueues message on receive queue if acceptable; optionally handles * disconnect indication for a connected socket. @@ -2336,7 +2350,8 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *skb) * Called with socket lock already taken */ static void tipc_sk_filter_rcv(struct sock *sk, struct sk_buff *skb, - struct sk_buff_head *xmitq) + struct sk_buff_head *xmitq, + struct sk_buff_head *deferq) { bool sk_conn = !tipc_sk_type_connectionless(sk); struct tipc_sock *tsk = tipc_sk(sk); @@ -2353,7 +2368,7 @@ static void tipc_sk_filter_rcv(struct sock *sk, struct sk_buff *skb, __skb_queue_tail(&inputq, skb); if (unlikely(!msg_isdata(hdr))) - tipc_sk_proto_rcv(sk, &inputq, xmitq); + tipc_sk_proto_rcv(sk, &inputq, xmitq, deferq); if (unlikely(grp)) tipc_group_filter_msg(grp, &inputq, xmitq); @@ -2365,7 +2380,8 @@ static void tipc_sk_filter_rcv(struct sock *sk, struct sk_buff *skb, while ((skb = __skb_dequeue(&inputq))) { hdr = buf_msg(skb); limit = rcvbuf_limit(sk, skb); - if ((sk_conn && !tipc_sk_filter_connect(tsk, skb, xmitq)) || + if ((sk_conn && + !tipc_sk_filter_connect(tsk, skb, xmitq, deferq)) || (!sk_conn && msg_connected(hdr)) || (!grp && msg_in_group(hdr))) err = TIPC_ERR_NO_PORT; @@ -2408,7 +2424,7 @@ static int tipc_sk_backlog_rcv(struct sock *sk, struct sk_buff *skb) __skb_queue_head_init(&xmitq); - tipc_sk_filter_rcv(sk, skb, &xmitq); + tipc_sk_filter_rcv(sk, skb, &xmitq, NULL); added = sk_rmem_alloc_get(sk) - before; atomic_add(added, &tipc_sk(sk)->dupl_rcvcnt); @@ -2424,11 +2440,13 @@ static int tipc_sk_backlog_rcv(struct sock *sk, struct sk_buff *skb) * @sk: socket where the buffers should be enqueued * @dport: port number for the socket * @xmitq: output queue + * @deferq: socket write queue to transmit after releasing the socket lock * * Caller must hold socket lock */ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk, - u32 dport, struct sk_buff_head *xmitq) + u32 dport, struct sk_buff_head *xmitq, + struct sk_buff_head *deferq) { unsigned long time_limit = jiffies + usecs_to_jiffies(20000); struct sk_buff *skb; @@ -2446,7 +2464,9 @@ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk, /* Add message directly to receive queue if possible */ if (!sock_owned_by_user(sk)) { - tipc_sk_filter_rcv(sk, skb, xmitq); + tipc_sk_filter_rcv(sk, skb, xmitq, deferq); + if (deferq && !skb_queue_empty(deferq)) + return; continue; } @@ -2483,6 +2503,7 @@ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk, */ void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq) { + struct sk_buff_head deferq; struct sk_buff_head xmitq; u32 dnode, dport = 0; int err; @@ -2490,6 +2511,7 @@ void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq) struct sock *sk; struct sk_buff *skb; + __skb_queue_head_init(&deferq); __skb_queue_head_init(&xmitq); while (skb_queue_len(inputq)) { dport = tipc_skb_peek_port(inputq, dport); @@ -2498,9 +2520,22 @@ void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq) if (likely(tsk)) { sk = &tsk->sk; if (likely(spin_trylock_bh(&sk->sk_lock.slock))) { - tipc_sk_enqueue(inputq, sk, dport, &xmitq); + tipc_sk_enqueue(inputq, sk, dport, &xmitq, + &deferq); + if (!skb_queue_empty(&deferq)) + dnode = tsk_peer_node(tsk); spin_unlock_bh(&sk->sk_lock.slock); } + if (!skb_queue_empty(&deferq)) { + err = tipc_node_xmit(sock_net(sk), &deferq, + dnode, dport); + if (err != -ELINKCONG) { + spin_lock_bh(&sk->sk_lock.slock); + tsk->cong_link_cnt = 0; + sk->sk_write_space(sk); + spin_unlock_bh(&sk->sk_lock.slock); + } + } /* Send pending response/rejected messages, if any */ tipc_node_distr_xmit(sock_net(sk), &xmitq); sock_put(sk); -- 2.39.3 (Apple Git-145)