mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:24:47 +01:00
net: annotate data-races around sk->sk_{data_ready,write_space}
skmsg (and probably other layers) are changing these pointers
while other cpus might read them concurrently.
Add corresponding READ_ONCE()/WRITE_ONCE() annotations
for UDP, TCP and AF_UNIX.
Fixes: 604326b41a ("bpf, sockmap: convert to generic sk_msg interface")
Reported-by: syzbot+87f770387a9e5dc6b79b@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/699ee9fc.050a0220.1cd54b.0009.GAE@google.com/
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: John Fastabend <john.fastabend@gmail.com>
Cc: Jakub Sitnicki <jakub@cloudflare.com>
Cc: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260225131547.1085509-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
754a3d081a
commit
2ef2b20cf4
8 changed files with 25 additions and 23 deletions
|
|
@ -1205,8 +1205,8 @@ void sk_psock_start_strp(struct sock *sk, struct sk_psock *psock)
|
|||
return;
|
||||
|
||||
psock->saved_data_ready = sk->sk_data_ready;
|
||||
sk->sk_data_ready = sk_psock_strp_data_ready;
|
||||
sk->sk_write_space = sk_psock_write_space;
|
||||
WRITE_ONCE(sk->sk_data_ready, sk_psock_strp_data_ready);
|
||||
WRITE_ONCE(sk->sk_write_space, sk_psock_write_space);
|
||||
}
|
||||
|
||||
void sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock)
|
||||
|
|
@ -1216,8 +1216,8 @@ void sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock)
|
|||
if (!psock->saved_data_ready)
|
||||
return;
|
||||
|
||||
sk->sk_data_ready = psock->saved_data_ready;
|
||||
psock->saved_data_ready = NULL;
|
||||
WRITE_ONCE(sk->sk_data_ready, psock->saved_data_ready);
|
||||
WRITE_ONCE(psock->saved_data_ready, NULL);
|
||||
strp_stop(&psock->strp);
|
||||
}
|
||||
|
||||
|
|
@ -1296,8 +1296,8 @@ void sk_psock_start_verdict(struct sock *sk, struct sk_psock *psock)
|
|||
return;
|
||||
|
||||
psock->saved_data_ready = sk->sk_data_ready;
|
||||
sk->sk_data_ready = sk_psock_verdict_data_ready;
|
||||
sk->sk_write_space = sk_psock_write_space;
|
||||
WRITE_ONCE(sk->sk_data_ready, sk_psock_verdict_data_ready);
|
||||
WRITE_ONCE(sk->sk_write_space, sk_psock_write_space);
|
||||
}
|
||||
|
||||
void sk_psock_stop_verdict(struct sock *sk, struct sk_psock *psock)
|
||||
|
|
@ -1308,6 +1308,6 @@ void sk_psock_stop_verdict(struct sock *sk, struct sk_psock *psock)
|
|||
if (!psock->saved_data_ready)
|
||||
return;
|
||||
|
||||
sk->sk_data_ready = psock->saved_data_ready;
|
||||
WRITE_ONCE(sk->sk_data_ready, psock->saved_data_ready);
|
||||
psock->saved_data_ready = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1446,7 +1446,7 @@ out_err:
|
|||
err = sk_stream_error(sk, flags, err);
|
||||
/* make sure we wake any epoll edge trigger waiter */
|
||||
if (unlikely(tcp_rtx_and_write_queues_empty(sk) && err == -EAGAIN)) {
|
||||
sk->sk_write_space(sk);
|
||||
READ_ONCE(sk->sk_write_space)(sk);
|
||||
tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED);
|
||||
}
|
||||
if (binding)
|
||||
|
|
@ -4181,7 +4181,7 @@ ao_parse:
|
|||
break;
|
||||
case TCP_NOTSENT_LOWAT:
|
||||
WRITE_ONCE(tp->notsent_lowat, val);
|
||||
sk->sk_write_space(sk);
|
||||
READ_ONCE(sk->sk_write_space)(sk);
|
||||
break;
|
||||
case TCP_INQ:
|
||||
if (val > 1 || val < 0)
|
||||
|
|
|
|||
|
|
@ -725,7 +725,7 @@ int tcp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore)
|
|||
WRITE_ONCE(sk->sk_prot->unhash, psock->saved_unhash);
|
||||
tcp_update_ulp(sk, psock->sk_proto, psock->saved_write_space);
|
||||
} else {
|
||||
sk->sk_write_space = psock->saved_write_space;
|
||||
WRITE_ONCE(sk->sk_write_space, psock->saved_write_space);
|
||||
/* Pairs with lockless read in sk_clone_lock() */
|
||||
sock_replace_proto(sk, psock->sk_proto);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5425,7 +5425,7 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
|
|||
|
||||
if (unlikely(tcp_try_rmem_schedule(sk, skb, skb->truesize))) {
|
||||
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPOFODROP);
|
||||
sk->sk_data_ready(sk);
|
||||
READ_ONCE(sk->sk_data_ready)(sk);
|
||||
tcp_drop_reason(sk, skb, SKB_DROP_REASON_PROTO_MEM);
|
||||
return;
|
||||
}
|
||||
|
|
@ -5635,7 +5635,7 @@ err:
|
|||
void tcp_data_ready(struct sock *sk)
|
||||
{
|
||||
if (tcp_epollin_ready(sk, sk->sk_rcvlowat) || sock_flag(sk, SOCK_DONE))
|
||||
sk->sk_data_ready(sk);
|
||||
READ_ONCE(sk->sk_data_ready)(sk);
|
||||
}
|
||||
|
||||
static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
|
||||
|
|
@ -5691,7 +5691,7 @@ queue_and_out:
|
|||
inet_csk(sk)->icsk_ack.pending |=
|
||||
(ICSK_ACK_NOMEM | ICSK_ACK_NOW);
|
||||
inet_csk_schedule_ack(sk);
|
||||
sk->sk_data_ready(sk);
|
||||
READ_ONCE(sk->sk_data_ready)(sk);
|
||||
|
||||
if (skb_queue_len(&sk->sk_receive_queue) && skb->len) {
|
||||
reason = SKB_DROP_REASON_PROTO_MEM;
|
||||
|
|
@ -6114,7 +6114,9 @@ static void tcp_new_space(struct sock *sk)
|
|||
tp->snd_cwnd_stamp = tcp_jiffies32;
|
||||
}
|
||||
|
||||
INDIRECT_CALL_1(sk->sk_write_space, sk_stream_write_space, sk);
|
||||
INDIRECT_CALL_1(READ_ONCE(sk->sk_write_space),
|
||||
sk_stream_write_space,
|
||||
sk);
|
||||
}
|
||||
|
||||
/* Caller made space either from:
|
||||
|
|
@ -6325,7 +6327,7 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, const struct tcphdr *t
|
|||
BUG();
|
||||
WRITE_ONCE(tp->urg_data, TCP_URG_VALID | tmp);
|
||||
if (!sock_flag(sk, SOCK_DEAD))
|
||||
sk->sk_data_ready(sk);
|
||||
READ_ONCE(sk->sk_data_ready)(sk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7792,7 +7794,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
|
|||
sock_put(fastopen_sk);
|
||||
goto drop_and_free;
|
||||
}
|
||||
sk->sk_data_ready(sk);
|
||||
READ_ONCE(sk->sk_data_ready)(sk);
|
||||
bh_unlock_sock(fastopen_sk);
|
||||
sock_put(fastopen_sk);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1004,7 +1004,7 @@ enum skb_drop_reason tcp_child_process(struct sock *parent, struct sock *child,
|
|||
reason = tcp_rcv_state_process(child, skb);
|
||||
/* Wakeup parent, send SIGIO */
|
||||
if (state == TCP_SYN_RECV && child->sk_state != state)
|
||||
parent->sk_data_ready(parent);
|
||||
READ_ONCE(parent->sk_data_ready)(parent);
|
||||
} else {
|
||||
/* Alas, it is possible again, because we do lookup
|
||||
* in main socket hash table and lock on listening
|
||||
|
|
|
|||
|
|
@ -1787,7 +1787,7 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
|
|||
* using prepare_to_wait_exclusive().
|
||||
*/
|
||||
while (nb) {
|
||||
INDIRECT_CALL_1(sk->sk_data_ready,
|
||||
INDIRECT_CALL_1(READ_ONCE(sk->sk_data_ready),
|
||||
sock_def_readable, sk);
|
||||
nb--;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ int udp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore)
|
|||
int family = sk->sk_family == AF_INET ? UDP_BPF_IPV4 : UDP_BPF_IPV6;
|
||||
|
||||
if (restore) {
|
||||
sk->sk_write_space = psock->saved_write_space;
|
||||
WRITE_ONCE(sk->sk_write_space, psock->saved_write_space);
|
||||
sock_replace_proto(sk, psock->sk_proto);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1785,7 +1785,7 @@ restart:
|
|||
__skb_queue_tail(&other->sk_receive_queue, skb);
|
||||
spin_unlock(&other->sk_receive_queue.lock);
|
||||
unix_state_unlock(other);
|
||||
other->sk_data_ready(other);
|
||||
READ_ONCE(other->sk_data_ready)(other);
|
||||
sock_put(other);
|
||||
return 0;
|
||||
|
||||
|
|
@ -2278,7 +2278,7 @@ restart_locked:
|
|||
scm_stat_add(other, skb);
|
||||
skb_queue_tail(&other->sk_receive_queue, skb);
|
||||
unix_state_unlock(other);
|
||||
other->sk_data_ready(other);
|
||||
READ_ONCE(other->sk_data_ready)(other);
|
||||
sock_put(other);
|
||||
scm_destroy(&scm);
|
||||
return len;
|
||||
|
|
@ -2351,7 +2351,7 @@ static int queue_oob(struct sock *sk, struct msghdr *msg, struct sock *other,
|
|||
|
||||
sk_send_sigurg(other);
|
||||
unix_state_unlock(other);
|
||||
other->sk_data_ready(other);
|
||||
READ_ONCE(other->sk_data_ready)(other);
|
||||
|
||||
return 0;
|
||||
out_unlock:
|
||||
|
|
@ -2477,7 +2477,7 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
|
|||
spin_unlock(&other->sk_receive_queue.lock);
|
||||
|
||||
unix_state_unlock(other);
|
||||
other->sk_data_ready(other);
|
||||
READ_ONCE(other->sk_data_ready)(other);
|
||||
sent += size;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue