Skip to content

Commit eb0718f

Browse files
q2venPaolo Abeni
authored andcommitted
af_unix: Annotate data-races around sk->sk_state in unix_write_space() and poll().
unix_poll() and unix_dgram_poll() read sk->sk_state locklessly and calls unix_writable() which also reads sk->sk_state without holding unix_state_lock(). Let's use READ_ONCE() in unix_poll() and unix_dgram_poll() and pass it to unix_writable(). While at it, we remove TCP_SYN_SENT check in unix_dgram_poll() as that state does not exist for AF_UNIX socket since the code was added. Fixes: 1586a58 ("af_unix: do not report POLLOUT on listeners") Fixes: 3c73419 ("af_unix: fix 'poll for write'/ connected DGRAM sockets") Fixes: 1da177e ("Linux-2.6.12-rc2") Signed-off-by: Kuniyuki Iwashima <[email protected]> Signed-off-by: Paolo Abeni <[email protected]>
1 parent 3a0f38e commit eb0718f

File tree

1 file changed

+12
-13
lines changed

1 file changed

+12
-13
lines changed

net/unix/af_unix.c

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -530,9 +530,9 @@ static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other)
530530
return 0;
531531
}
532532

533-
static int unix_writable(const struct sock *sk)
533+
static int unix_writable(const struct sock *sk, unsigned char state)
534534
{
535-
return sk->sk_state != TCP_LISTEN &&
535+
return state != TCP_LISTEN &&
536536
(refcount_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf;
537537
}
538538

@@ -541,7 +541,7 @@ static void unix_write_space(struct sock *sk)
541541
struct socket_wq *wq;
542542

543543
rcu_read_lock();
544-
if (unix_writable(sk)) {
544+
if (unix_writable(sk, READ_ONCE(sk->sk_state))) {
545545
wq = rcu_dereference(sk->sk_wq);
546546
if (skwq_has_sleeper(wq))
547547
wake_up_interruptible_sync_poll(&wq->wait,
@@ -3129,12 +3129,14 @@ static int unix_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned lon
31293129
static __poll_t unix_poll(struct file *file, struct socket *sock, poll_table *wait)
31303130
{
31313131
struct sock *sk = sock->sk;
3132+
unsigned char state;
31323133
__poll_t mask;
31333134
u8 shutdown;
31343135

31353136
sock_poll_wait(file, sock, wait);
31363137
mask = 0;
31373138
shutdown = READ_ONCE(sk->sk_shutdown);
3139+
state = READ_ONCE(sk->sk_state);
31383140

31393141
/* exceptional events? */
31403142
if (READ_ONCE(sk->sk_err))
@@ -3156,14 +3158,14 @@ static __poll_t unix_poll(struct file *file, struct socket *sock, poll_table *wa
31563158

31573159
/* Connection-based need to check for termination and startup */
31583160
if ((sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) &&
3159-
sk->sk_state == TCP_CLOSE)
3161+
state == TCP_CLOSE)
31603162
mask |= EPOLLHUP;
31613163

31623164
/*
31633165
* we set writable also when the other side has shut down the
31643166
* connection. This prevents stuck sockets.
31653167
*/
3166-
if (unix_writable(sk))
3168+
if (unix_writable(sk, state))
31673169
mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
31683170

31693171
return mask;
@@ -3174,12 +3176,14 @@ static __poll_t unix_dgram_poll(struct file *file, struct socket *sock,
31743176
{
31753177
struct sock *sk = sock->sk, *other;
31763178
unsigned int writable;
3179+
unsigned char state;
31773180
__poll_t mask;
31783181
u8 shutdown;
31793182

31803183
sock_poll_wait(file, sock, wait);
31813184
mask = 0;
31823185
shutdown = READ_ONCE(sk->sk_shutdown);
3186+
state = READ_ONCE(sk->sk_state);
31833187

31843188
/* exceptional events? */
31853189
if (READ_ONCE(sk->sk_err) ||
@@ -3199,19 +3203,14 @@ static __poll_t unix_dgram_poll(struct file *file, struct socket *sock,
31993203
mask |= EPOLLIN | EPOLLRDNORM;
32003204

32013205
/* Connection-based need to check for termination and startup */
3202-
if (sk->sk_type == SOCK_SEQPACKET) {
3203-
if (sk->sk_state == TCP_CLOSE)
3204-
mask |= EPOLLHUP;
3205-
/* connection hasn't started yet? */
3206-
if (sk->sk_state == TCP_SYN_SENT)
3207-
return mask;
3208-
}
3206+
if (sk->sk_type == SOCK_SEQPACKET && state == TCP_CLOSE)
3207+
mask |= EPOLLHUP;
32093208

32103209
/* No write status requested, avoid expensive OUT tests. */
32113210
if (!(poll_requested_events(wait) & (EPOLLWRBAND|EPOLLWRNORM|EPOLLOUT)))
32123211
return mask;
32133212

3214-
writable = unix_writable(sk);
3213+
writable = unix_writable(sk, state);
32153214
if (writable) {
32163215
unix_state_lock(sk);
32173216

0 commit comments

Comments
 (0)