Skip to content

Commit 581264e

Browse files
q2venSasha Levin
authored andcommitted
af_unix: Annotate data-races around sk->sk_state in unix_write_space() and poll().
[ Upstream commit eb0718f ] 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 <kuniyu@amazon.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 6416722 commit 581264e

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
@@ -518,9 +518,9 @@ static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other)
518518
return 0;
519519
}
520520

521-
static int unix_writable(const struct sock *sk)
521+
static int unix_writable(const struct sock *sk, unsigned char state)
522522
{
523-
return sk->sk_state != TCP_LISTEN &&
523+
return state != TCP_LISTEN &&
524524
(refcount_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf;
525525
}
526526

@@ -529,7 +529,7 @@ static void unix_write_space(struct sock *sk)
529529
struct socket_wq *wq;
530530

531531
rcu_read_lock();
532-
if (unix_writable(sk)) {
532+
if (unix_writable(sk, READ_ONCE(sk->sk_state))) {
533533
wq = rcu_dereference(sk->sk_wq);
534534
if (skwq_has_sleeper(wq))
535535
wake_up_interruptible_sync_poll(&wq->wait,
@@ -3180,12 +3180,14 @@ static int unix_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned lon
31803180
static __poll_t unix_poll(struct file *file, struct socket *sock, poll_table *wait)
31813181
{
31823182
struct sock *sk = sock->sk;
3183+
unsigned char state;
31833184
__poll_t mask;
31843185
u8 shutdown;
31853186

31863187
sock_poll_wait(file, sock, wait);
31873188
mask = 0;
31883189
shutdown = READ_ONCE(sk->sk_shutdown);
3190+
state = READ_ONCE(sk->sk_state);
31893191

31903192
/* exceptional events? */
31913193
if (sk->sk_err)
@@ -3207,14 +3209,14 @@ static __poll_t unix_poll(struct file *file, struct socket *sock, poll_table *wa
32073209

32083210
/* Connection-based need to check for termination and startup */
32093211
if ((sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) &&
3210-
sk->sk_state == TCP_CLOSE)
3212+
state == TCP_CLOSE)
32113213
mask |= EPOLLHUP;
32123214

32133215
/*
32143216
* we set writable also when the other side has shut down the
32153217
* connection. This prevents stuck sockets.
32163218
*/
3217-
if (unix_writable(sk))
3219+
if (unix_writable(sk, state))
32183220
mask |= EPOLLOUT | EPOLLWRNORM | EPOLLWRBAND;
32193221

32203222
return mask;
@@ -3225,12 +3227,14 @@ static __poll_t unix_dgram_poll(struct file *file, struct socket *sock,
32253227
{
32263228
struct sock *sk = sock->sk, *other;
32273229
unsigned int writable;
3230+
unsigned char state;
32283231
__poll_t mask;
32293232
u8 shutdown;
32303233

32313234
sock_poll_wait(file, sock, wait);
32323235
mask = 0;
32333236
shutdown = READ_ONCE(sk->sk_shutdown);
3237+
state = READ_ONCE(sk->sk_state);
32343238

32353239
/* exceptional events? */
32363240
if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue))
@@ -3249,19 +3253,14 @@ static __poll_t unix_dgram_poll(struct file *file, struct socket *sock,
32493253
mask |= EPOLLIN | EPOLLRDNORM;
32503254

32513255
/* Connection-based need to check for termination and startup */
3252-
if (sk->sk_type == SOCK_SEQPACKET) {
3253-
if (sk->sk_state == TCP_CLOSE)
3254-
mask |= EPOLLHUP;
3255-
/* connection hasn't started yet? */
3256-
if (sk->sk_state == TCP_SYN_SENT)
3257-
return mask;
3258-
}
3256+
if (sk->sk_type == SOCK_SEQPACKET && state == TCP_CLOSE)
3257+
mask |= EPOLLHUP;
32593258

32603259
/* No write status requested, avoid expensive OUT tests. */
32613260
if (!(poll_requested_events(wait) & (EPOLLWRBAND|EPOLLWRNORM|EPOLLOUT)))
32623261
return mask;
32633262

3264-
writable = unix_writable(sk);
3263+
writable = unix_writable(sk, state);
32653264
if (writable) {
32663265
unix_state_lock(sk);
32673266

0 commit comments

Comments
 (0)