netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [net-next] tcp: don't free a FIN sk_buff in tcp_remove_empty_skb()
@ 2021-10-20 23:24 Jon Maxwell
  2021-10-21  1:10 ` Eric Dumazet
  2021-10-21  5:35 ` kernel test robot
  0 siblings, 2 replies; 5+ messages in thread
From: Jon Maxwell @ 2021-10-20 23:24 UTC (permalink / raw)
  To: edumazet; +Cc: davem, yoshfuji, dsahern, kuba, netdev, linux-kernel, jmaxwell37

A customer reported sockets stuck in the CLOSING state. A Vmcore revealed that 
the write_queue was not empty as determined by tcp_write_queue_empty() but the 
sk_buff containing the FIN flag had been freed and the socket was zombied in 
that state. Corresponding pcaps show no FIN from the Linux kernel on the wire.

Some instrumentation was added to the kernel and it was found that there is a 
timing window where tcp_sendmsg() can run after tcp_send_fin().

tcp_sendmsg() will hit an error, for example:

1269 ▹       if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))↩
1270 ▹       ▹       goto do_error;↩

tcp_remove_empty_skb() will then free the FIN sk_buff as "skb->len == 0". The
TCP socket is now wedged in the FIN-WAIT-1 state because the FIN is never sent.

If the other side sends a FIN packet the socket will transition to CLOSING and
remain that way until the system is rebooted.

Fix this by checking for the FIN flag in the sk_buff and don't free it if that 
is the case. Testing confirmed that fixed the issue.

Fixes: fdfc5c8594c2 ("tcp: remove empty skb from write queue in error cases")
Signed-off-by: Jon Maxwell <jmaxwell37@gmail.com>
---
 net/ipv4/tcp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index c2d9830136d2..d2b06d8f0c37 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -938,7 +938,7 @@ int tcp_send_mss(struct sock *sk, int *size_goal, int flags)
  */
 void tcp_remove_empty_skb(struct sock *sk, struct sk_buff *skb)
 {
-	if (skb && !skb->len) {
+	if (skb && !skb->len && !TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) {
 		tcp_unlink_write_queue(skb, sk);
 		if (tcp_write_queue_empty(sk))
 			tcp_chrono_stop(sk, TCP_CHRONO_BUSY);
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread
[parent not found: <202110221513.52ubgVaN-lkp@intel.com>]

end of thread, other threads:[~2021-10-24 17:19 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-10-20 23:24 [net-next] tcp: don't free a FIN sk_buff in tcp_remove_empty_skb() Jon Maxwell
2021-10-21  1:10 ` Eric Dumazet
2021-10-21  1:48   ` Jonathan Maxwell
2021-10-21  5:35 ` kernel test robot
     [not found] <202110221513.52ubgVaN-lkp@intel.com>
2021-10-24 17:18 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).