Commit d0c6416b authored by Jiang Wang's avatar Jiang Wang Committed by Daniel Borkmann

unix: Fix an issue in unix_shutdown causing the other end read/write failures

Commit 94531cfc ("af_unix: Add unix_stream_proto for sockmap") sets
unix domain socket peer state to TCP_CLOSE in unix_shutdown. This could
happen when the local end is shutdown but the other end is not. Then,
the other end will get read or write failures which is not expected.
Fix the issue by setting the local state to shutdown.

Fixes: 94531cfc ("af_unix: Add unix_stream_proto for sockmap")
Reported-by: default avatarCasey Schaufler <casey@schaufler-ca.com>
Suggested-by: default avatarCong Wang <cong.wang@bytedance.com>
Signed-off-by: default avatarJiang Wang <jiang.wang@bytedance.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Tested-by: default avatarCasey Schaufler <casey@schaufler-ca.com>
Reviewed-by: default avatarCasey Schaufler <casey@schaufler-ca.com>
Acked-by: default avatarSong Liu <songliubraving@fb.com>
Link: https://lore.kernel.org/bpf/20211004232530.2377085-1-jiang.wang@bytedance.com
parent b0e875ba
...@@ -2860,6 +2860,9 @@ static int unix_shutdown(struct socket *sock, int mode) ...@@ -2860,6 +2860,9 @@ static int unix_shutdown(struct socket *sock, int mode)
unix_state_lock(sk); unix_state_lock(sk);
sk->sk_shutdown |= mode; sk->sk_shutdown |= mode;
if ((sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) &&
mode == SHUTDOWN_MASK)
sk->sk_state = TCP_CLOSE;
other = unix_peer(sk); other = unix_peer(sk);
if (other) if (other)
sock_hold(other); sock_hold(other);
...@@ -2882,13 +2885,11 @@ static int unix_shutdown(struct socket *sock, int mode) ...@@ -2882,13 +2885,11 @@ static int unix_shutdown(struct socket *sock, int mode)
other->sk_shutdown |= peer_mode; other->sk_shutdown |= peer_mode;
unix_state_unlock(other); unix_state_unlock(other);
other->sk_state_change(other); other->sk_state_change(other);
if (peer_mode == SHUTDOWN_MASK) { if (peer_mode == SHUTDOWN_MASK)
sk_wake_async(other, SOCK_WAKE_WAITD, POLL_HUP); sk_wake_async(other, SOCK_WAKE_WAITD, POLL_HUP);
other->sk_state = TCP_CLOSE; else if (peer_mode & RCV_SHUTDOWN)
} else if (peer_mode & RCV_SHUTDOWN) {
sk_wake_async(other, SOCK_WAKE_WAITD, POLL_IN); sk_wake_async(other, SOCK_WAKE_WAITD, POLL_IN);
} }
}
if (other) if (other)
sock_put(other); sock_put(other);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment