]> git.ipfire.org Git - thirdparty/kernel/linux.git/commit
tcp: fix race in tcp_write_err()
authorEric Dumazet <edumazet@google.com>
Tue, 28 May 2024 12:52:51 +0000 (12:52 +0000)
committerJakub Kicinski <kuba@kernel.org>
Thu, 30 May 2024 00:21:35 +0000 (17:21 -0700)
commit853c3bd7b7917670224c9fe5245bd045cac411dd
tree74e6d3420c431784c0f5715a8c267a8267c0476d
parent5e514f1cba090e1c8fff03e92a175eccfe46305f
tcp: fix race in tcp_write_err()

I noticed flakes in a packetdrill test, expecting an epoll_wait()
to return EPOLLERR | EPOLLHUP on a failed connect() attempt,
after multiple SYN retransmits. It sometimes return EPOLLERR only.

The issue is that tcp_write_err():
 1) writes an error in sk->sk_err,
 2) calls sk_error_report(),
 3) then calls tcp_done().

tcp_done() is writing SHUTDOWN_MASK into sk->sk_shutdown,
among other things.

Problem is that the awaken user thread (from 2) sk_error_report())
might call tcp_poll() before tcp_done() has written sk->sk_shutdown.

tcp_poll() only sees a non zero sk->sk_err and returns EPOLLERR.

This patch fixes the issue by making sure to call sk_error_report()
after tcp_done().

tcp_write_err() also lacks an smp_wmb().

We can reuse tcp_done_with_error() to factor out the details,
as Neal suggested.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Acked-by: Neal Cardwell <ncardwell@google.com>
Link: https://lore.kernel.org/r/20240528125253.1966136-3-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv4/tcp_timer.c