History

tcp: add rcu protection around tp->fastopen_rsk

Both tcp_v4_err() and tcp_v6_err() do the following operations while they do not own the socket lock : fastopen = tp->fastopen_rsk; snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; The problem is that without appropriate barrier, the compiler might reload tp->fastopen_rsk and trigger a NULL deref. request sockets are protected by RCU, we can simply add the missing annotations and barriers to solve the issue.

Eric Dumazet committed 7 years ago

Commit d983ea61 parent 8caf8a911 files · +35 −24Browse files

Unified · Split

11 files
  1. include/linux/tcp.h +3 −3
  2. net/core/request_sock.c +1 −1
  3. net/ipv4/inet_connection_sock.c +2 −2
  4. net/ipv4/tcp.c +8 −3
  5. net/ipv4/tcp_fastopen.c +1 −1
  6. net/ipv4/tcp_input.c +9 −4
  7. net/ipv4/tcp_ipv4.c +2 −2
  8. net/ipv4/tcp_minisocks.c +1 −1
  9. net/ipv4/tcp_output.c +1 −1
  10. net/ipv4/tcp_timer.c +6 −5
  11. net/ipv6/tcp_ipv6.c +1 −1
include/linux/tcp.h+3−3
@@ -393,7 +393,7 @@ struct tcp_sock { · 392 unmodified lines
393393 /* fastopen_rsk points to request_sock that resulted in this big
394394 * socket. Used to retransmit SYNACKs etc.
395395 */
396− struct request_sock *fastopen_rsk;
396+ struct request_sock __rcu *fastopen_rsk;
397397 u32 *saved_syn;
398398 };
399399
@@ -447,8 +447,8 @@ static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) · 47 unmodified lines
447447
448448 static inline bool tcp_passive_fastopen(const struct sock *sk)
449449 {
450− return (sk->sk_state == TCP_SYN_RECV &&
451− tcp_sk(sk)->fastopen_rsk != NULL);
450+ return sk->sk_state == TCP_SYN_RECV &&
451+ rcu_access_pointer(tcp_sk(sk)->fastopen_rsk) != NULL;
452452 }
453453
454454 static inline void fastopen_queue_tune(struct sock *sk, int backlog)
net/core/request_sock.c+1−1
@@ -96,7 +96,7 @@ void reqsk_fastopen_remove(struct sock *sk, struct request_sock *req, · 95 unmodified lines
9696
9797 fastopenq = &inet_csk(lsk)->icsk_accept_queue.fastopenq;
9898
99− tcp_sk(sk)->fastopen_rsk = NULL;
99+ RCU_INIT_POINTER(tcp_sk(sk)->fastopen_rsk, NULL);
100100 spin_lock_bh(&fastopenq->lock);
101101 fastopenq->qlen--;
102102 tcp_rsk(req)->tfo_listener = false;
net/ipv4/inet_connection_sock.c+2−2
@@ -906,7 +906,7 @@ static void inet_child_forget(struct sock *sk, struct request_sock *req, · 905 unmodified lines
906906 percpu_counter_inc(sk->sk_prot->orphan_count);
907907
908908 if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(req)->tfo_listener) {
909− BUG_ON(tcp_sk(child)->fastopen_rsk != req);
909+ BUG_ON(rcu_access_pointer(tcp_sk(child)->fastopen_rsk) != req);
910910 BUG_ON(sk != req->rsk_listener);
911911
912912 /* Paranoid, to prevent race condition if
@@ -915,7 +915,7 @@ static void inet_child_forget(struct sock *sk, struct request_sock *req, · 2 unmodified lines
915915 * Also to satisfy an assertion in
916916 * tcp_v4_destroy_sock().
917917 */
918− tcp_sk(child)->fastopen_rsk = NULL;
918+ RCU_INIT_POINTER(tcp_sk(child)->fastopen_rsk, NULL);
919919 }
920920 inet_csk_destroy_sock(child);
921921 }
net/ipv4/tcp.c+8−3
@@ -543,7 +543,7 @@ __poll_t tcp_poll(struct file *file, struct socket *sock, poll_table *wait) · 542 unmodified lines
543543
544544 /* Connected or passive Fast Open socket? */
545545 if (state != TCP_SYN_SENT &&
546− (state != TCP_SYN_RECV || tp->fastopen_rsk)) {
546+ (state != TCP_SYN_RECV || rcu_access_pointer(tp->fastopen_rsk))) {
547547 int target = sock_rcvlowat(sk, 0, INT_MAX);
548548
549549 if (tp->urg_seq == tp->copied_seq &&
@@ -2487,7 +2487,10 @@ adjudge_to_death: · 1937 unmodified lines
24872487 }
24882488
24892489 if (sk->sk_state == TCP_CLOSE) {
2490− struct request_sock *req = tcp_sk(sk)->fastopen_rsk;
2490+ struct request_sock *req;
2491+
2492+ req = rcu_dereference_protected(tcp_sk(sk)->fastopen_rsk,
2493+ lockdep_sock_is_held(sk));
24912494 /* We could get here with a non-NULL req if the socket is
24922495 * aborted (e.g., closed with unread data) before 3WHS
24932496 * finishes.
@@ -3831,8 +3834,10 @@ EXPORT_SYMBOL(tcp_md5_hash_key); · 1337 unmodified lines
38313834
38323835 void tcp_done(struct sock *sk)
38333836 {
3834− struct request_sock *req = tcp_sk(sk)->fastopen_rsk;
3837+ struct request_sock *req;
38353838
3839+ req = rcu_dereference_protected(tcp_sk(sk)->fastopen_rsk,
3840+ lockdep_sock_is_held(sk));
38363841 if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV)
38373842 TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS);
38383843
net/ipv4/tcp_fastopen.c+1−1
@@ -253,7 +253,7 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk, · 252 unmodified lines
253253 */
254254 tp = tcp_sk(child);
255255
256− tp->fastopen_rsk = req;
256+ rcu_assign_pointer(tp->fastopen_rsk, req);
257257 tcp_rsk(req)->tfo_listener = true;
258258
259259 /* RFC1323: The window in SYN & SYN/ACK segments is never
net/ipv4/tcp_input.c+9−4
@@ -2666,7 +2666,7 @@ static void tcp_process_loss(struct sock *sk, int flag, int num_dupack, · 2665 unmodified lines
26662666 struct tcp_sock *tp = tcp_sk(sk);
26672667 bool recovered = !before(tp->snd_una, tp->high_seq);
26682668
2669− if ((flag & FLAG_SND_UNA_ADVANCED || tp->fastopen_rsk) &&
2669+ if ((flag & FLAG_SND_UNA_ADVANCED || rcu_access_pointer(tp->fastopen_rsk)) &&
26702670 tcp_try_undo_loss(sk, false))
26712671 return;
26722672
@@ -2990,7 +2990,7 @@ void tcp_rearm_rto(struct sock *sk) · 317 unmodified lines
29902990 /* If the retrans timer is currently being used by Fast Open
29912991 * for SYN-ACK retrans purpose, stay put.
29922992 */
2993− if (tp->fastopen_rsk)
2993+ if (rcu_access_pointer(tp->fastopen_rsk))
29942994 return;
29952995
29962996 if (!tp->packets_out) {
@@ -6087,6 +6087,8 @@ reset_and_undo: · 3090 unmodified lines
60876087
60886088 static void tcp_rcv_synrecv_state_fastopen(struct sock *sk)
60896089 {
6090+ struct request_sock *req;
6091+
60906092 tcp_try_undo_loss(sk, false);
60916093
60926094 /* Reset rtx states to prevent spurious retransmits_timed_out() */
@@ -6096,7 +6098,9 @@ static void tcp_rcv_synrecv_state_fastopen(struct sock *sk) · 3 unmodified lines
60966098 /* Once we leave TCP_SYN_RECV or TCP_FIN_WAIT_1,
60976099 * we no longer need req so release it.
60986100 */
6099− reqsk_fastopen_remove(sk, tcp_sk(sk)->fastopen_rsk, false);
6101+ req = rcu_dereference_protected(tcp_sk(sk)->fastopen_rsk,
6102+ lockdep_sock_is_held(sk));
6103+ reqsk_fastopen_remove(sk, req, false);
61006104
61016105 /* Re-arm the timer because data may have been sent out.
61026106 * This is similar to the regular data transmission case
@@ -6171,7 +6175,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) · 68 unmodified lines
61716175
61726176 tcp_mstamp_refresh(tp);
61736177 tp->rx_opt.saw_tstamp = 0;
6174− req = tp->fastopen_rsk;
6178+ req = rcu_dereference_protected(tp->fastopen_rsk,
6179+ lockdep_sock_is_held(sk));
61756180 if (req) {
61766181 bool req_stolen;
61776182
net/ipv4/tcp_ipv4.c+2−2
@@ -478,7 +478,7 @@ int tcp_v4_err(struct sk_buff *icmp_skb, u32 info) · 477 unmodified lines
478478 icsk = inet_csk(sk);
479479 tp = tcp_sk(sk);
480480 /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */
481− fastopen = tp->fastopen_rsk;
481+ fastopen = rcu_dereference(tp->fastopen_rsk);
482482 snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una;
483483 if (sk->sk_state != TCP_LISTEN &&
484484 !between(seq, snd_una, tp->snd_nxt)) {
@@ -2121,7 +2121,7 @@ void tcp_v4_destroy_sock(struct sock *sk) · 1636 unmodified lines
21212121 if (inet_csk(sk)->icsk_bind_hash)
21222122 inet_put_port(sk);
21232123
2124− BUG_ON(tp->fastopen_rsk);
2124+ BUG_ON(rcu_access_pointer(tp->fastopen_rsk));
21252125
21262126 /* If socket is aborted during connect operation */
21272127 tcp_free_fastopen_req(tp);
net/ipv4/tcp_minisocks.c+1−1
@@ -541,7 +541,7 @@ struct sock *tcp_create_openreq_child(const struct sock *sk, · 540 unmodified lines
541541 newtp->rx_opt.mss_clamp = req->mss;
542542 tcp_ecn_openreq_child(newtp, req);
543543 newtp->fastopen_req = NULL;
544− newtp->fastopen_rsk = NULL;
544+ RCU_INIT_POINTER(newtp->fastopen_rsk, NULL);
545545
546546 __TCP_INC_STATS(sock_net(sk), TCP_MIB_PASSIVEOPENS);
547547
net/ipv4/tcp_output.c+1−1
@@ -2482,7 +2482,7 @@ bool tcp_schedule_loss_probe(struct sock *sk, bool advancing_rto) · 2481 unmodified lines
24822482 /* Don't do any loss probe on a Fast Open connection before 3WHS
24832483 * finishes.
24842484 */
2485− if (tp->fastopen_rsk)
2485+ if (rcu_access_pointer(tp->fastopen_rsk))
24862486 return false;
24872487
24882488 early_retrans = sock_net(sk)->ipv4.sysctl_tcp_early_retrans;
net/ipv4/tcp_timer.c+6−5
@@ -386,15 +386,13 @@ abort: tcp_write_err(sk); · 385 unmodified lines
386386 * Timer for Fast Open socket to retransmit SYNACK. Note that the
387387 * sk here is the child socket, not the parent (listener) socket.
388388 */
389−static void tcp_fastopen_synack_timer(struct sock *sk)
389+static void tcp_fastopen_synack_timer(struct sock *sk, struct request_sock *req)
390390 {
391391 struct inet_connection_sock *icsk = inet_csk(sk);
392392 int max_retries = icsk->icsk_syn_retries ? :
393393 sock_net(sk)->ipv4.sysctl_tcp_synack_retries + 1; /* add one more retry for fastopen */
394394 struct tcp_sock *tp = tcp_sk(sk);
395− struct request_sock *req;
396395
397− req = tcp_sk(sk)->fastopen_rsk;
398396 req->rsk_ops->syn_ack_timeout(req);
399397
400398 if (req->num_timeout >= max_retries) {
@@ -435,11 +433,14 @@ void tcp_retransmit_timer(struct sock *sk) · 34 unmodified lines
435433 struct tcp_sock *tp = tcp_sk(sk);
436434 struct net *net = sock_net(sk);
437435 struct inet_connection_sock *icsk = inet_csk(sk);
436+ struct request_sock *req;
438437
439− if (tp->fastopen_rsk) {
438+ req = rcu_dereference_protected(tp->fastopen_rsk,
439+ lockdep_sock_is_held(sk));
440+ if (req) {
440441 WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV &&
441442 sk->sk_state != TCP_FIN_WAIT1);
442− tcp_fastopen_synack_timer(sk);
443+ tcp_fastopen_synack_timer(sk, req);
443444 /* Before we receive ACK to our SYN-ACK don't retransmit
444445 * anything else (e.g., data or FIN segments).
445446 */
net/ipv6/tcp_ipv6.c+1−1
@@ -406,7 +406,7 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, · 405 unmodified lines
406406
407407 tp = tcp_sk(sk);
408408 /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */
409− fastopen = tp->fastopen_rsk;
409+ fastopen = rcu_dereference(tp->fastopen_rsk);
410410 snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una;
411411 if (sk->sk_state != TCP_LISTEN &&
412412 !between(seq, snd_una, tp->snd_nxt)) {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t