diff options
author | Eric Dumazet <edumazet@google.com> | 2018-10-02 15:35:05 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-10-02 18:52:12 -0400 |
commit | 2ab2ddd301a22ca3c5f0b743593e4ad2953dfa53 (patch) | |
tree | 3ec72a50a6be78a4bc8eb73d8c9bd14df798aa26 | |
parent | ff58e2df62ce29d0552278c290ae494b30fe0c6f (diff) |
inet: make sure to grab rcu_read_lock before using ireq->ireq_opt
Timer handlers do not imply rcu_read_lock(), so my recent fix
triggered a LOCKDEP warning when SYNACK is retransmit.
Lets add rcu_read_lock()/rcu_read_unlock() pairs around ireq->ireq_opt
usages instead of guessing what is done by callers, since it is
not worth the pain.
Get rid of ireq_opt_deref() helper since it hides the logic
without real benefit, since it is now a standard rcu_dereference().
Fixes: 1ad98e9d1bdf ("tcp/dccp: fix lockdep issue when SYN is backlogged")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/inet_sock.h | 5 | ||||
-rw-r--r-- | net/dccp/ipv4.c | 4 | ||||
-rw-r--r-- | net/ipv4/inet_connection_sock.c | 5 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 4 |
4 files changed, 10 insertions, 8 deletions
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index a8cd5cf9ff5b..a80fd0ac4563 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h | |||
@@ -130,11 +130,6 @@ static inline int inet_request_bound_dev_if(const struct sock *sk, | |||
130 | return sk->sk_bound_dev_if; | 130 | return sk->sk_bound_dev_if; |
131 | } | 131 | } |
132 | 132 | ||
133 | static inline struct ip_options_rcu *ireq_opt_deref(const struct inet_request_sock *ireq) | ||
134 | { | ||
135 | return rcu_dereference(ireq->ireq_opt); | ||
136 | } | ||
137 | |||
138 | struct inet_cork { | 133 | struct inet_cork { |
139 | unsigned int flags; | 134 | unsigned int flags; |
140 | __be32 addr; | 135 | __be32 addr; |
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index b08feb219b44..8e08cea6f178 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -493,9 +493,11 @@ static int dccp_v4_send_response(const struct sock *sk, struct request_sock *req | |||
493 | 493 | ||
494 | dh->dccph_checksum = dccp_v4_csum_finish(skb, ireq->ir_loc_addr, | 494 | dh->dccph_checksum = dccp_v4_csum_finish(skb, ireq->ir_loc_addr, |
495 | ireq->ir_rmt_addr); | 495 | ireq->ir_rmt_addr); |
496 | rcu_read_lock(); | ||
496 | err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, | 497 | err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, |
497 | ireq->ir_rmt_addr, | 498 | ireq->ir_rmt_addr, |
498 | ireq_opt_deref(ireq)); | 499 | rcu_dereference(ireq->ireq_opt)); |
500 | rcu_read_unlock(); | ||
499 | err = net_xmit_eval(err); | 501 | err = net_xmit_eval(err); |
500 | } | 502 | } |
501 | 503 | ||
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index dfd5009f96ef..15e7f7915a21 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c | |||
@@ -544,7 +544,8 @@ struct dst_entry *inet_csk_route_req(const struct sock *sk, | |||
544 | struct ip_options_rcu *opt; | 544 | struct ip_options_rcu *opt; |
545 | struct rtable *rt; | 545 | struct rtable *rt; |
546 | 546 | ||
547 | opt = ireq_opt_deref(ireq); | 547 | rcu_read_lock(); |
548 | opt = rcu_dereference(ireq->ireq_opt); | ||
548 | 549 | ||
549 | flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark, | 550 | flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark, |
550 | RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, | 551 | RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, |
@@ -558,11 +559,13 @@ struct dst_entry *inet_csk_route_req(const struct sock *sk, | |||
558 | goto no_route; | 559 | goto no_route; |
559 | if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway) | 560 | if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway) |
560 | goto route_err; | 561 | goto route_err; |
562 | rcu_read_unlock(); | ||
561 | return &rt->dst; | 563 | return &rt->dst; |
562 | 564 | ||
563 | route_err: | 565 | route_err: |
564 | ip_rt_put(rt); | 566 | ip_rt_put(rt); |
565 | no_route: | 567 | no_route: |
568 | rcu_read_unlock(); | ||
566 | __IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); | 569 | __IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); |
567 | return NULL; | 570 | return NULL; |
568 | } | 571 | } |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 44c09eddbb78..cd426313a298 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -943,9 +943,11 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, | |||
943 | if (skb) { | 943 | if (skb) { |
944 | __tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr); | 944 | __tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr); |
945 | 945 | ||
946 | rcu_read_lock(); | ||
946 | err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, | 947 | err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, |
947 | ireq->ir_rmt_addr, | 948 | ireq->ir_rmt_addr, |
948 | ireq_opt_deref(ireq)); | 949 | rcu_dereference(ireq->ireq_opt)); |
950 | rcu_read_unlock(); | ||
949 | err = net_xmit_eval(err); | 951 | err = net_xmit_eval(err); |
950 | } | 952 | } |
951 | 953 | ||