| From foo@baz Wed 01 Jan 2020 10:36:29 PM CET |
| From: Eric Dumazet <edumazet@google.com> |
| Date: Thu, 12 Dec 2019 12:55:29 -0800 |
| Subject: tcp: do not send empty skb from tcp_write_xmit() |
| |
| From: Eric Dumazet <edumazet@google.com> |
| |
| [ Upstream commit 1f85e6267caca44b30c54711652b0726fadbb131 ] |
| |
| Backport of commit fdfc5c8594c2 ("tcp: remove empty skb from |
| write queue in error cases") in linux-4.14 stable triggered |
| various bugs. One of them has been fixed in commit ba2ddb43f270 |
| ("tcp: Don't dequeue SYN/FIN-segments from write-queue"), but |
| we still have crashes in some occasions. |
| |
| Root-cause is that when tcp_sendmsg() has allocated a fresh |
| skb and could not append a fragment before being blocked |
| in sk_stream_wait_memory(), tcp_write_xmit() might be called |
| and decide to send this fresh and empty skb. |
| |
| Sending an empty packet is not only silly, it might have caused |
| many issues we had in the past with tp->packets_out being |
| out of sync. |
| |
| Fixes: c65f7f00c587 ("[TCP]: Simplify SKB data portion allocation with NETIF_F_SG.") |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Cc: Christoph Paasch <cpaasch@apple.com> |
| Acked-by: Neal Cardwell <ncardwell@google.com> |
| Cc: Jason Baron <jbaron@akamai.com> |
| Acked-by: Soheil Hassas Yeganeh <soheil@google.com> |
| Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv4/tcp_output.c | 8 ++++++++ |
| 1 file changed, 8 insertions(+) |
| |
| --- a/net/ipv4/tcp_output.c |
| +++ b/net/ipv4/tcp_output.c |
| @@ -2376,6 +2376,14 @@ static bool tcp_write_xmit(struct sock * |
| if (tcp_small_queue_check(sk, skb, 0)) |
| break; |
| |
| + /* Argh, we hit an empty skb(), presumably a thread |
| + * is sleeping in sendmsg()/sk_stream_wait_memory(). |
| + * We do not want to send a pure-ack packet and have |
| + * a strange looking rtx queue with empty packet(s). |
| + */ |
| + if (TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) |
| + break; |
| + |
| if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp))) |
| break; |
| |