mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 04:18:39 +08:00
net: deal with most data-races in sk_wait_event()
[ Upstream commitd0ac89f6f9
] __condition is evaluated twice in sk_wait_event() macro. First invocation is lockless, and reads can race with writes, as spotted by syzbot. BUG: KCSAN: data-race in sk_stream_wait_connect / tcp_disconnect write to 0xffff88812d83d6a0 of 4 bytes by task 9065 on cpu 1: tcp_disconnect+0x2cd/0xdb0 inet_shutdown+0x19e/0x1f0 net/ipv4/af_inet.c:911 __sys_shutdown_sock net/socket.c:2343 [inline] __sys_shutdown net/socket.c:2355 [inline] __do_sys_shutdown net/socket.c:2363 [inline] __se_sys_shutdown+0xf8/0x140 net/socket.c:2361 __x64_sys_shutdown+0x31/0x40 net/socket.c:2361 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd read to 0xffff88812d83d6a0 of 4 bytes by task 9040 on cpu 0: sk_stream_wait_connect+0x1de/0x3a0 net/core/stream.c:75 tcp_sendmsg_locked+0x2e4/0x2120 net/ipv4/tcp.c:1266 tcp_sendmsg+0x30/0x50 net/ipv4/tcp.c:1484 inet6_sendmsg+0x63/0x80 net/ipv6/af_inet6.c:651 sock_sendmsg_nosec net/socket.c:724 [inline] sock_sendmsg net/socket.c:747 [inline] __sys_sendto+0x246/0x300 net/socket.c:2142 __do_sys_sendto net/socket.c:2154 [inline] __se_sys_sendto net/socket.c:2150 [inline] __x64_sys_sendto+0x78/0x90 net/socket.c:2150 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd value changed: 0x00000000 -> 0x00000068 Fixes:1da177e4c3
("Linux-2.6.12-rc2") Reported-by: syzbot <syzkaller@googlegroups.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
bd0f360ee8
commit
65531f5675
@ -73,8 +73,8 @@ int sk_stream_wait_connect(struct sock *sk, long *timeo_p)
|
||||
add_wait_queue(sk_sleep(sk), &wait);
|
||||
sk->sk_write_pending++;
|
||||
done = sk_wait_event(sk, timeo_p,
|
||||
!sk->sk_err &&
|
||||
!((1 << sk->sk_state) &
|
||||
!READ_ONCE(sk->sk_err) &&
|
||||
!((1 << READ_ONCE(sk->sk_state)) &
|
||||
~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)), &wait);
|
||||
remove_wait_queue(sk_sleep(sk), &wait);
|
||||
sk->sk_write_pending--;
|
||||
@ -87,9 +87,9 @@ EXPORT_SYMBOL(sk_stream_wait_connect);
|
||||
* sk_stream_closing - Return 1 if we still have things to send in our buffers.
|
||||
* @sk: socket to verify
|
||||
*/
|
||||
static inline int sk_stream_closing(struct sock *sk)
|
||||
static int sk_stream_closing(const struct sock *sk)
|
||||
{
|
||||
return (1 << sk->sk_state) &
|
||||
return (1 << READ_ONCE(sk->sk_state)) &
|
||||
(TCPF_FIN_WAIT1 | TCPF_CLOSING | TCPF_LAST_ACK);
|
||||
}
|
||||
|
||||
@ -142,8 +142,8 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
|
||||
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk->sk_write_pending++;
|
||||
sk_wait_event(sk, ¤t_timeo, sk->sk_err ||
|
||||
(sk->sk_shutdown & SEND_SHUTDOWN) ||
|
||||
sk_wait_event(sk, ¤t_timeo, READ_ONCE(sk->sk_err) ||
|
||||
(READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN) ||
|
||||
(sk_stream_memory_free(sk) &&
|
||||
!vm_wait), &wait);
|
||||
sk->sk_write_pending--;
|
||||
|
@ -168,7 +168,7 @@ static int tcp_msg_wait_data(struct sock *sk, struct sk_psock *psock,
|
||||
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
|
||||
ret = sk_wait_event(sk, &timeo,
|
||||
!list_empty(&psock->ingress_msg) ||
|
||||
!skb_queue_empty(&sk->sk_receive_queue), &wait);
|
||||
!skb_queue_empty_lockless(&sk->sk_receive_queue), &wait);
|
||||
sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
|
||||
remove_wait_queue(sk_sleep(sk), &wait);
|
||||
return ret;
|
||||
|
@ -583,7 +583,8 @@ static int llc_ui_wait_for_disc(struct sock *sk, long timeout)
|
||||
|
||||
add_wait_queue(sk_sleep(sk), &wait);
|
||||
while (1) {
|
||||
if (sk_wait_event(sk, &timeout, sk->sk_state == TCP_CLOSE, &wait))
|
||||
if (sk_wait_event(sk, &timeout,
|
||||
READ_ONCE(sk->sk_state) == TCP_CLOSE, &wait))
|
||||
break;
|
||||
rc = -ERESTARTSYS;
|
||||
if (signal_pending(current))
|
||||
@ -603,7 +604,8 @@ static bool llc_ui_wait_for_conn(struct sock *sk, long timeout)
|
||||
|
||||
add_wait_queue(sk_sleep(sk), &wait);
|
||||
while (1) {
|
||||
if (sk_wait_event(sk, &timeout, sk->sk_state != TCP_SYN_SENT, &wait))
|
||||
if (sk_wait_event(sk, &timeout,
|
||||
READ_ONCE(sk->sk_state) != TCP_SYN_SENT, &wait))
|
||||
break;
|
||||
if (signal_pending(current) || !timeout)
|
||||
break;
|
||||
@ -622,7 +624,7 @@ static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout)
|
||||
while (1) {
|
||||
rc = 0;
|
||||
if (sk_wait_event(sk, &timeout,
|
||||
(sk->sk_shutdown & RCV_SHUTDOWN) ||
|
||||
(READ_ONCE(sk->sk_shutdown) & RCV_SHUTDOWN) ||
|
||||
(!llc_data_accept_state(llc->state) &&
|
||||
!llc->remote_busy_flag &&
|
||||
!llc->p_flag), &wait))
|
||||
|
@ -67,8 +67,8 @@ static void smc_close_stream_wait(struct smc_sock *smc, long timeout)
|
||||
|
||||
rc = sk_wait_event(sk, &timeout,
|
||||
!smc_tx_prepared_sends(&smc->conn) ||
|
||||
sk->sk_err == ECONNABORTED ||
|
||||
sk->sk_err == ECONNRESET ||
|
||||
READ_ONCE(sk->sk_err) == ECONNABORTED ||
|
||||
READ_ONCE(sk->sk_err) == ECONNRESET ||
|
||||
smc->conn.killed,
|
||||
&wait);
|
||||
if (rc)
|
||||
|
@ -263,9 +263,9 @@ int smc_rx_wait(struct smc_sock *smc, long *timeo,
|
||||
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
|
||||
add_wait_queue(sk_sleep(sk), &wait);
|
||||
rc = sk_wait_event(sk, timeo,
|
||||
sk->sk_err ||
|
||||
READ_ONCE(sk->sk_err) ||
|
||||
cflags->peer_conn_abort ||
|
||||
sk->sk_shutdown & RCV_SHUTDOWN ||
|
||||
READ_ONCE(sk->sk_shutdown) & RCV_SHUTDOWN ||
|
||||
conn->killed ||
|
||||
fcrit(conn),
|
||||
&wait);
|
||||
|
@ -113,8 +113,8 @@ static int smc_tx_wait(struct smc_sock *smc, int flags)
|
||||
break; /* at least 1 byte of free & no urgent data */
|
||||
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
|
||||
sk_wait_event(sk, &timeo,
|
||||
sk->sk_err ||
|
||||
(sk->sk_shutdown & SEND_SHUTDOWN) ||
|
||||
READ_ONCE(sk->sk_err) ||
|
||||
(READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN) ||
|
||||
smc_cdc_rxed_any_close(conn) ||
|
||||
(atomic_read(&conn->sndbuf_space) &&
|
||||
!conn->urg_tx_pend),
|
||||
|
@ -313,9 +313,9 @@ static void tsk_rej_rx_queue(struct sock *sk, int error)
|
||||
tipc_sk_respond(sk, skb, error);
|
||||
}
|
||||
|
||||
static bool tipc_sk_connected(struct sock *sk)
|
||||
static bool tipc_sk_connected(const struct sock *sk)
|
||||
{
|
||||
return sk->sk_state == TIPC_ESTABLISHED;
|
||||
return READ_ONCE(sk->sk_state) == TIPC_ESTABLISHED;
|
||||
}
|
||||
|
||||
/* tipc_sk_type_connectionless - check if the socket is datagram socket
|
||||
|
@ -111,7 +111,8 @@ int wait_on_pending_writer(struct sock *sk, long *timeo)
|
||||
break;
|
||||
}
|
||||
|
||||
if (sk_wait_event(sk, timeo, !sk->sk_write_pending, &wait))
|
||||
if (sk_wait_event(sk, timeo,
|
||||
!READ_ONCE(sk->sk_write_pending), &wait))
|
||||
break;
|
||||
}
|
||||
remove_wait_queue(sk_sleep(sk), &wait);
|
||||
|
Loading…
Reference in New Issue
Block a user