Commit 7b6a893a authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

tcp: annotate races around tp->urg_data

tcp_poll() and tcp_ioctl() are reading tp->urg_data without socket lock
owned.

Also, it is faster to first check tp->urg_data in tcp_poll(),
then tp->urg_seq == tp->copied_seq, because tp->urg_seq is
located in a different/cold cache line.
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0307a0b7
...@@ -545,10 +545,11 @@ __poll_t tcp_poll(struct file *file, struct socket *sock, poll_table *wait) ...@@ -545,10 +545,11 @@ __poll_t tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
if (state != TCP_SYN_SENT && if (state != TCP_SYN_SENT &&
(state != TCP_SYN_RECV || rcu_access_pointer(tp->fastopen_rsk))) { (state != TCP_SYN_RECV || rcu_access_pointer(tp->fastopen_rsk))) {
int target = sock_rcvlowat(sk, 0, INT_MAX); int target = sock_rcvlowat(sk, 0, INT_MAX);
u16 urg_data = READ_ONCE(tp->urg_data);
if (READ_ONCE(tp->urg_seq) == READ_ONCE(tp->copied_seq) && if (urg_data &&
!sock_flag(sk, SOCK_URGINLINE) && READ_ONCE(tp->urg_seq) == READ_ONCE(tp->copied_seq) &&
tp->urg_data) !sock_flag(sk, SOCK_URGINLINE))
target++; target++;
if (tcp_stream_is_readable(sk, target)) if (tcp_stream_is_readable(sk, target))
...@@ -573,7 +574,7 @@ __poll_t tcp_poll(struct file *file, struct socket *sock, poll_table *wait) ...@@ -573,7 +574,7 @@ __poll_t tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
} else } else
mask |= EPOLLOUT | EPOLLWRNORM; mask |= EPOLLOUT | EPOLLWRNORM;
if (tp->urg_data & TCP_URG_VALID) if (urg_data & TCP_URG_VALID)
mask |= EPOLLPRI; mask |= EPOLLPRI;
} else if (state == TCP_SYN_SENT && inet_sk(sk)->defer_connect) { } else if (state == TCP_SYN_SENT && inet_sk(sk)->defer_connect) {
/* Active TCP fastopen socket with defer_connect /* Active TCP fastopen socket with defer_connect
...@@ -607,7 +608,7 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) ...@@ -607,7 +608,7 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
unlock_sock_fast(sk, slow); unlock_sock_fast(sk, slow);
break; break;
case SIOCATMARK: case SIOCATMARK:
answ = tp->urg_data && answ = READ_ONCE(tp->urg_data) &&
READ_ONCE(tp->urg_seq) == READ_ONCE(tp->copied_seq); READ_ONCE(tp->urg_seq) == READ_ONCE(tp->copied_seq);
break; break;
case SIOCOUTQ: case SIOCOUTQ:
...@@ -1465,7 +1466,7 @@ static int tcp_recv_urg(struct sock *sk, struct msghdr *msg, int len, int flags) ...@@ -1465,7 +1466,7 @@ static int tcp_recv_urg(struct sock *sk, struct msghdr *msg, int len, int flags)
char c = tp->urg_data; char c = tp->urg_data;
if (!(flags & MSG_PEEK)) if (!(flags & MSG_PEEK))
tp->urg_data = TCP_URG_READ; WRITE_ONCE(tp->urg_data, TCP_URG_READ);
/* Read urgent data. */ /* Read urgent data. */
msg->msg_flags |= MSG_OOB; msg->msg_flags |= MSG_OOB;
...@@ -2465,7 +2466,7 @@ static int tcp_recvmsg_locked(struct sock *sk, struct msghdr *msg, size_t len, ...@@ -2465,7 +2466,7 @@ static int tcp_recvmsg_locked(struct sock *sk, struct msghdr *msg, size_t len,
skip_copy: skip_copy:
if (tp->urg_data && after(tp->copied_seq, tp->urg_seq)) { if (tp->urg_data && after(tp->copied_seq, tp->urg_seq)) {
tp->urg_data = 0; WRITE_ONCE(tp->urg_data, 0);
tcp_fast_path_check(sk); tcp_fast_path_check(sk);
} }
...@@ -2959,7 +2960,7 @@ int tcp_disconnect(struct sock *sk, int flags) ...@@ -2959,7 +2960,7 @@ int tcp_disconnect(struct sock *sk, int flags)
tcp_clear_xmit_timers(sk); tcp_clear_xmit_timers(sk);
__skb_queue_purge(&sk->sk_receive_queue); __skb_queue_purge(&sk->sk_receive_queue);
WRITE_ONCE(tp->copied_seq, tp->rcv_nxt); WRITE_ONCE(tp->copied_seq, tp->rcv_nxt);
tp->urg_data = 0; WRITE_ONCE(tp->urg_data, 0);
tcp_write_queue_purge(sk); tcp_write_queue_purge(sk);
tcp_fastopen_active_disable_ofo_check(sk); tcp_fastopen_active_disable_ofo_check(sk);
skb_rbtree_purge(&tp->out_of_order_queue); skb_rbtree_purge(&tp->out_of_order_queue);
......
...@@ -5591,7 +5591,7 @@ static void tcp_check_urg(struct sock *sk, const struct tcphdr *th) ...@@ -5591,7 +5591,7 @@ static void tcp_check_urg(struct sock *sk, const struct tcphdr *th)
} }
} }
tp->urg_data = TCP_URG_NOTYET; WRITE_ONCE(tp->urg_data, TCP_URG_NOTYET);
WRITE_ONCE(tp->urg_seq, ptr); WRITE_ONCE(tp->urg_seq, ptr);
/* Disable header prediction. */ /* Disable header prediction. */
...@@ -5617,7 +5617,7 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, const struct tcphdr *t ...@@ -5617,7 +5617,7 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, const struct tcphdr *t
u8 tmp; u8 tmp;
if (skb_copy_bits(skb, ptr, &tmp, 1)) if (skb_copy_bits(skb, ptr, &tmp, 1))
BUG(); BUG();
tp->urg_data = TCP_URG_VALID | tmp; WRITE_ONCE(tp->urg_data, TCP_URG_VALID | tmp);
if (!sock_flag(sk, SOCK_DEAD)) if (!sock_flag(sk, SOCK_DEAD))
sk->sk_data_ready(sk); sk->sk_data_ready(sk);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment