]> git.baikalelectronics.ru Git - kernel.git/commitdiff
net: datagram: fix data-races in datagram_poll()
authorEric Dumazet <edumazet@google.com>
Tue, 9 May 2023 17:31:31 +0000 (17:31 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 30 May 2023 11:44:02 +0000 (12:44 +0100)
[ Upstream commit 5bca1d081f44c9443e61841842ce4e9179d327b6 ]

datagram_poll() runs locklessly, we should add READ_ONCE()
annotations while reading sk->sk_err, sk->sk_shutdown and sk->sk_state.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://lore.kernel.org/r/20230509173131.3263780-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/core/datagram.c

index b0488f30f2c4e35a551988fb55c9acec677af908..a5fc44448d6000aa1d1ce0208e6037dcae7a6cf2 100644 (file)
@@ -778,18 +778,21 @@ __poll_t datagram_poll(struct file *file, struct socket *sock,
 {
        struct sock *sk = sock->sk;
        __poll_t mask;
+       u8 shutdown;
 
        sock_poll_wait(file, sock, wait);
        mask = 0;
 
        /* exceptional events? */
-       if (sk->sk_err || !skb_queue_empty_lockless(&sk->sk_error_queue))
+       if (READ_ONCE(sk->sk_err) ||
+           !skb_queue_empty_lockless(&sk->sk_error_queue))
                mask |= EPOLLERR |
                        (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? EPOLLPRI : 0);
 
-       if (sk->sk_shutdown & RCV_SHUTDOWN)
+       shutdown = READ_ONCE(sk->sk_shutdown);
+       if (shutdown & RCV_SHUTDOWN)
                mask |= EPOLLRDHUP | EPOLLIN | EPOLLRDNORM;
-       if (sk->sk_shutdown == SHUTDOWN_MASK)
+       if (shutdown == SHUTDOWN_MASK)
                mask |= EPOLLHUP;
 
        /* readable? */
@@ -798,10 +801,12 @@ __poll_t datagram_poll(struct file *file, struct socket *sock,
 
        /* Connection-based need to check for termination and startup */
        if (connection_based(sk)) {
-               if (sk->sk_state == TCP_CLOSE)
+               int state = READ_ONCE(sk->sk_state);
+
+               if (state == TCP_CLOSE)
                        mask |= EPOLLHUP;
                /* connection hasn't started yet? */
-               if (sk->sk_state == TCP_SYN_SENT)
+               if (state == TCP_SYN_SENT)
                        return mask;
        }