Commit 942238f9 authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by Paolo Abeni
Browse files

af_unix: Annodate data-races around sk->sk_state for writers.



sk->sk_state is changed under unix_state_lock(), but it's read locklessly
in many places.

This patch adds WRITE_ONCE() on the writer side.

We will add READ_ONCE() to the lockless readers in the following patches.

Fixes: 83301b53 ("af_unix: Set TCP_ESTABLISHED for datagram sockets too")
Fixes: 1da177e4 ("Linux-2.6.12-rc2")
Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@amazon.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 26bfb8b5
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -616,7 +616,7 @@ static void unix_release_sock(struct sock *sk, int embrion)
	u->path.dentry = NULL;
	u->path.mnt = NULL;
	state = sk->sk_state;
	sk->sk_state = TCP_CLOSE;
	WRITE_ONCE(sk->sk_state, TCP_CLOSE);

	skpair = unix_peer(sk);
	unix_peer(sk) = NULL;
@@ -738,7 +738,8 @@ static int unix_listen(struct socket *sock, int backlog)
	if (backlog > sk->sk_max_ack_backlog)
		wake_up_interruptible_all(&u->peer_wait);
	sk->sk_max_ack_backlog	= backlog;
	sk->sk_state		= TCP_LISTEN;
	WRITE_ONCE(sk->sk_state, TCP_LISTEN);

	/* set credentials so connect can copy them */
	init_peercred(sk);
	err = 0;
@@ -1401,7 +1402,8 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,
		if (err)
			goto out_unlock;

		sk->sk_state = other->sk_state = TCP_ESTABLISHED;
		WRITE_ONCE(sk->sk_state, TCP_ESTABLISHED);
		WRITE_ONCE(other->sk_state, TCP_ESTABLISHED);
	} else {
		/*
		 *	1003.1g breaking connected state with AF_UNSPEC
@@ -1418,7 +1420,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,

		unix_peer(sk) = other;
		if (!other)
			sk->sk_state = TCP_CLOSE;
			WRITE_ONCE(sk->sk_state, TCP_CLOSE);
		unix_dgram_peer_wake_disconnect_wakeup(sk, old_peer);

		unix_state_double_unlock(sk, other);
@@ -1639,7 +1641,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
	copy_peercred(sk, other);

	sock->state	= SS_CONNECTED;
	sk->sk_state	= TCP_ESTABLISHED;
	WRITE_ONCE(sk->sk_state, TCP_ESTABLISHED);
	sock_hold(newsk);

	smp_mb__after_atomic();	/* sock_hold() does an atomic_inc() */
@@ -2050,7 +2052,7 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
			unix_peer(sk) = NULL;
			unix_dgram_peer_wake_disconnect_wakeup(sk, other);

			sk->sk_state = TCP_CLOSE;
			WRITE_ONCE(sk->sk_state, TCP_CLOSE);
			unix_state_unlock(sk);

			unix_dgram_disconnected(sk, other);