diff options
author | Eric Dumazet <edumazet@google.com> | 2024-05-28 14:52:53 +0200 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2024-05-30 02:21:36 +0200 |
commit | fde6f897f2a184546bf5516ac736523ef24dc6a7 (patch) | |
tree | fc8014baaf67f7eb33fa5249a7c068a43438c7cc /net/ipv4/tcp_ipv4.c | |
parent | tcp: fix races in tcp_abort() (diff) | |
download | linux-fde6f897f2a184546bf5516ac736523ef24dc6a7.tar.xz linux-fde6f897f2a184546bf5516ac736523ef24dc6a7.zip |
tcp: fix races in tcp_v[46]_err()
These functions have races when they:
1) Write sk->sk_err
2) call sk_error_report(sk)
3) call tcp_done(sk)
As described in prior patches in this series:
An smp_wmb() is missing.
We should call tcp_done() before sk_error_report(sk)
to have consistent tcp_poll() results on SMP hosts.
Use tcp_done_with_error() where we centralized the
correct sequence.
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-5-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 11 |
1 files changed, 3 insertions, 8 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 8f70b8d1d1e5..041c7eda9abe 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -611,15 +611,10 @@ int tcp_v4_err(struct sk_buff *skb, u32 info) ip_icmp_error(sk, skb, err, th->dest, info, (u8 *)th); - if (!sock_owned_by_user(sk)) { - WRITE_ONCE(sk->sk_err, err); - - sk_error_report(sk); - - tcp_done(sk); - } else { + if (!sock_owned_by_user(sk)) + tcp_done_with_error(sk, err); + else WRITE_ONCE(sk->sk_err_soft, err); - } goto out; } |