Skip to content

Commit 081d5c4

Browse files
committed
unix: Fix race in SOCK_SEQPACKET's unix_dgram_sendmsg()
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2164865 Upstream Status: net.git commit 3ff8bff commit 3ff8bff Author: Kirill Tkhai <tkhai@ya.ru> Date: Tue Dec 13 00:05:53 2022 +0300 unix: Fix race in SOCK_SEQPACKET's unix_dgram_sendmsg() There is a race resulting in alive SOCK_SEQPACKET socket may change its state from TCP_ESTABLISHED to TCP_CLOSE: unix_release_sock(peer) unix_dgram_sendmsg(sk) sock_orphan(peer) sock_set_flag(peer, SOCK_DEAD) sock_alloc_send_pskb() if !(sk->sk_shutdown & SEND_SHUTDOWN) OK if sock_flag(peer, SOCK_DEAD) sk->sk_state = TCP_CLOSE sk->sk_shutdown = SHUTDOWN_MASK After that socket sk remains almost normal: it is able to connect, listen, accept and recvmsg, while it can't sendmsg. Since this is the only possibility for alive SOCK_SEQPACKET to change the state in such way, we should better fix this strange and potentially danger corner case. Note, that we will return EPIPE here like this is normally done in sock_alloc_send_pskb(). Originally used ECONNREFUSED looks strange, since it's strange to return a specific retval in dependence of race in kernel, when user can't affect on this. Also, move TCP_CLOSE assignment for SOCK_DGRAM sockets under state lock to fix race with unix_dgram_connect(): unix_dgram_connect(other) unix_dgram_sendmsg(sk) unix_peer(sk) = NULL unix_state_unlock(sk) unix_state_double_lock(sk, other) sk->sk_state = TCP_ESTABLISHED unix_peer(sk) = other unix_state_double_unlock(sk, other) sk->sk_state = TCP_CLOSED This patch fixes both of these races. Fixes: 83301b5 ("af_unix: Set TCP_ESTABLISHED for datagram sockets too") Signed-off-by: Kirill Tkhai <tkhai@ya.ru> Link: https://lore.kernel.org/r/135fda25-22d5-837a-782b-ceee50e19844@ya.ru Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Davide Caratti <dcaratti@redhat.com>
1 parent c2e1968 commit 081d5c4

File tree

1 file changed

+9
-2
lines changed

1 file changed

+9
-2
lines changed

net/unix/af_unix.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1945,13 +1945,20 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
19451945
unix_state_lock(sk);
19461946

19471947
err = 0;
1948-
if (unix_peer(sk) == other) {
1948+
if (sk->sk_type == SOCK_SEQPACKET) {
1949+
/* We are here only when racing with unix_release_sock()
1950+
* is clearing @other. Never change state to TCP_CLOSE
1951+
* unlike SOCK_DGRAM wants.
1952+
*/
1953+
unix_state_unlock(sk);
1954+
err = -EPIPE;
1955+
} else if (unix_peer(sk) == other) {
19491956
unix_peer(sk) = NULL;
19501957
unix_dgram_peer_wake_disconnect_wakeup(sk, other);
19511958

1959+
sk->sk_state = TCP_CLOSE;
19521960
unix_state_unlock(sk);
19531961

1954-
sk->sk_state = TCP_CLOSE;
19551962
unix_dgram_disconnected(sk, other);
19561963
sock_put(other);
19571964
err = -ECONNREFUSED;

0 commit comments

Comments
 (0)