Skip to content

Commit d0ac89f

Browse files
edumazetdavem330
authored andcommitted
net: deal with most data-races in sk_wait_event()
__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: 1da177e4c3f4 ("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>
1 parent e05a5f5 commit d0ac89f

8 files changed

Lines changed: 22 additions & 19 deletions

File tree

net/core/stream.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ int sk_stream_wait_connect(struct sock *sk, long *timeo_p)
7373
add_wait_queue(sk_sleep(sk), &wait);
7474
sk->sk_write_pending++;
7575
done = sk_wait_event(sk, timeo_p,
76-
!sk->sk_err &&
77-
!((1 << sk->sk_state) &
76+
!READ_ONCE(sk->sk_err) &&
77+
!((1 << READ_ONCE(sk->sk_state)) &
7878
~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)), &wait);
7979
remove_wait_queue(sk_sleep(sk), &wait);
8080
sk->sk_write_pending--;
@@ -87,9 +87,9 @@ EXPORT_SYMBOL(sk_stream_wait_connect);
8787
* sk_stream_closing - Return 1 if we still have things to send in our buffers.
8888
* @sk: socket to verify
8989
*/
90-
static inline int sk_stream_closing(struct sock *sk)
90+
static int sk_stream_closing(const struct sock *sk)
9191
{
92-
return (1 << sk->sk_state) &
92+
return (1 << READ_ONCE(sk->sk_state)) &
9393
(TCPF_FIN_WAIT1 | TCPF_CLOSING | TCPF_LAST_ACK);
9494
}
9595

@@ -142,8 +142,8 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
142142

143143
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
144144
sk->sk_write_pending++;
145-
sk_wait_event(sk, &current_timeo, sk->sk_err ||
146-
(sk->sk_shutdown & SEND_SHUTDOWN) ||
145+
sk_wait_event(sk, &current_timeo, READ_ONCE(sk->sk_err) ||
146+
(READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN) ||
147147
(sk_stream_memory_free(sk) &&
148148
!vm_wait), &wait);
149149
sk->sk_write_pending--;

net/ipv4/tcp_bpf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ static int tcp_msg_wait_data(struct sock *sk, struct sk_psock *psock,
168168
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
169169
ret = sk_wait_event(sk, &timeo,
170170
!list_empty(&psock->ingress_msg) ||
171-
!skb_queue_empty(&sk->sk_receive_queue), &wait);
171+
!skb_queue_empty_lockless(&sk->sk_receive_queue), &wait);
172172
sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
173173
remove_wait_queue(sk_sleep(sk), &wait);
174174
return ret;

net/llc/af_llc.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,8 @@ static int llc_ui_wait_for_disc(struct sock *sk, long timeout)
583583

584584
add_wait_queue(sk_sleep(sk), &wait);
585585
while (1) {
586-
if (sk_wait_event(sk, &timeout, sk->sk_state == TCP_CLOSE, &wait))
586+
if (sk_wait_event(sk, &timeout,
587+
READ_ONCE(sk->sk_state) == TCP_CLOSE, &wait))
587588
break;
588589
rc = -ERESTARTSYS;
589590
if (signal_pending(current))
@@ -603,7 +604,8 @@ static bool llc_ui_wait_for_conn(struct sock *sk, long timeout)
603604

604605
add_wait_queue(sk_sleep(sk), &wait);
605606
while (1) {
606-
if (sk_wait_event(sk, &timeout, sk->sk_state != TCP_SYN_SENT, &wait))
607+
if (sk_wait_event(sk, &timeout,
608+
READ_ONCE(sk->sk_state) != TCP_SYN_SENT, &wait))
607609
break;
608610
if (signal_pending(current) || !timeout)
609611
break;
@@ -622,7 +624,7 @@ static int llc_ui_wait_for_busy_core(struct sock *sk, long timeout)
622624
while (1) {
623625
rc = 0;
624626
if (sk_wait_event(sk, &timeout,
625-
(sk->sk_shutdown & RCV_SHUTDOWN) ||
627+
(READ_ONCE(sk->sk_shutdown) & RCV_SHUTDOWN) ||
626628
(!llc_data_accept_state(llc->state) &&
627629
!llc->remote_busy_flag &&
628630
!llc->p_flag), &wait))

net/smc/smc_close.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ static void smc_close_stream_wait(struct smc_sock *smc, long timeout)
6767

6868
rc = sk_wait_event(sk, &timeout,
6969
!smc_tx_prepared_sends(&smc->conn) ||
70-
sk->sk_err == ECONNABORTED ||
71-
sk->sk_err == ECONNRESET ||
70+
READ_ONCE(sk->sk_err) == ECONNABORTED ||
71+
READ_ONCE(sk->sk_err) == ECONNRESET ||
7272
smc->conn.killed,
7373
&wait);
7474
if (rc)

net/smc/smc_rx.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,9 @@ int smc_rx_wait(struct smc_sock *smc, long *timeo,
267267
sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
268268
add_wait_queue(sk_sleep(sk), &wait);
269269
rc = sk_wait_event(sk, timeo,
270-
sk->sk_err ||
270+
READ_ONCE(sk->sk_err) ||
271271
cflags->peer_conn_abort ||
272-
sk->sk_shutdown & RCV_SHUTDOWN ||
272+
READ_ONCE(sk->sk_shutdown) & RCV_SHUTDOWN ||
273273
conn->killed ||
274274
fcrit(conn),
275275
&wait);

net/smc/smc_tx.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ static int smc_tx_wait(struct smc_sock *smc, int flags)
113113
break; /* at least 1 byte of free & no urgent data */
114114
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
115115
sk_wait_event(sk, &timeo,
116-
sk->sk_err ||
117-
(sk->sk_shutdown & SEND_SHUTDOWN) ||
116+
READ_ONCE(sk->sk_err) ||
117+
(READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN) ||
118118
smc_cdc_rxed_any_close(conn) ||
119119
(atomic_read(&conn->sndbuf_space) &&
120120
!conn->urg_tx_pend),

net/tipc/socket.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,9 +314,9 @@ static void tsk_rej_rx_queue(struct sock *sk, int error)
314314
tipc_sk_respond(sk, skb, error);
315315
}
316316

317-
static bool tipc_sk_connected(struct sock *sk)
317+
static bool tipc_sk_connected(const struct sock *sk)
318318
{
319-
return sk->sk_state == TIPC_ESTABLISHED;
319+
return READ_ONCE(sk->sk_state) == TIPC_ESTABLISHED;
320320
}
321321

322322
/* tipc_sk_type_connectionless - check if the socket is datagram socket

net/tls/tls_main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ int wait_on_pending_writer(struct sock *sk, long *timeo)
111111
break;
112112
}
113113

114-
if (sk_wait_event(sk, timeo, !sk->sk_write_pending, &wait))
114+
if (sk_wait_event(sk, timeo,
115+
!READ_ONCE(sk->sk_write_pending), &wait))
115116
break;
116117
}
117118
remove_wait_queue(sk_sleep(sk), &wait);

0 commit comments

Comments
 (0)