aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_output.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2015-03-24 18:58:52 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-24 21:16:29 -0400
commit80f03e27a309f3e32ebdd9629ac0320005a2180b (patch)
tree4516faa5da144dde9c1cd899ae3d99090e3852db /net/ipv4/tcp_output.c
parent9ead3527f5967440f2ff57fd2fa25dd0e460fc5a (diff)
tcp: md5: fix rcu lockdep splat
While timer handler effectively runs a rcu read locked section, there is no explicit rcu_read_lock()/rcu_read_unlock() annotations and lockdep can be confused here : net/ipv4/tcp_ipv4.c-906- /* caller either holds rcu_read_lock() or socket lock */ net/ipv4/tcp_ipv4.c:907: md5sig = rcu_dereference_check(tp->md5sig_info, net/ipv4/tcp_ipv4.c-908- sock_owned_by_user(sk) || net/ipv4/tcp_ipv4.c-909- lockdep_is_held(&sk->sk_lock.slock)); Let's explicitely acquire rcu_read_lock() in tcp_make_synack() Before commit fa76ce7328b ("inet: get rid of central tcp/dccp listener timer"), we were holding listener lock so lockdep was happy. Fixes: fa76ce7328b ("inet: get rid of central tcp/dccp listener timer") Signed-off-by: Eric DUmazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_output.c')
-rw-r--r--net/ipv4/tcp_output.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 18474088c3d0..5b7fad4b314c 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -601,15 +601,14 @@ static unsigned int tcp_synack_options(struct sock *sk,
601 struct request_sock *req, 601 struct request_sock *req,
602 unsigned int mss, struct sk_buff *skb, 602 unsigned int mss, struct sk_buff *skb,
603 struct tcp_out_options *opts, 603 struct tcp_out_options *opts,
604 struct tcp_md5sig_key **md5, 604 const struct tcp_md5sig_key *md5,
605 struct tcp_fastopen_cookie *foc) 605 struct tcp_fastopen_cookie *foc)
606{ 606{
607 struct inet_request_sock *ireq = inet_rsk(req); 607 struct inet_request_sock *ireq = inet_rsk(req);
608 unsigned int remaining = MAX_TCP_OPTION_SPACE; 608 unsigned int remaining = MAX_TCP_OPTION_SPACE;
609 609
610#ifdef CONFIG_TCP_MD5SIG 610#ifdef CONFIG_TCP_MD5SIG
611 *md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req); 611 if (md5) {
612 if (*md5) {
613 opts->options |= OPTION_MD5; 612 opts->options |= OPTION_MD5;
614 remaining -= TCPOLEN_MD5SIG_ALIGNED; 613 remaining -= TCPOLEN_MD5SIG_ALIGNED;
615 614
@@ -620,8 +619,6 @@ static unsigned int tcp_synack_options(struct sock *sk,
620 */ 619 */
621 ireq->tstamp_ok &= !ireq->sack_ok; 620 ireq->tstamp_ok &= !ireq->sack_ok;
622 } 621 }
623#else
624 *md5 = NULL;
625#endif 622#endif
626 623
627 /* We always send an MSS option. */ 624 /* We always send an MSS option. */
@@ -2913,7 +2910,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
2913 struct tcp_sock *tp = tcp_sk(sk); 2910 struct tcp_sock *tp = tcp_sk(sk);
2914 struct tcphdr *th; 2911 struct tcphdr *th;
2915 struct sk_buff *skb; 2912 struct sk_buff *skb;
2916 struct tcp_md5sig_key *md5; 2913 struct tcp_md5sig_key *md5 = NULL;
2917 int tcp_header_size; 2914 int tcp_header_size;
2918 int mss; 2915 int mss;
2919 2916
@@ -2938,7 +2935,12 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
2938 else 2935 else
2939#endif 2936#endif
2940 skb_mstamp_get(&skb->skb_mstamp); 2937 skb_mstamp_get(&skb->skb_mstamp);
2941 tcp_header_size = tcp_synack_options(sk, req, mss, skb, &opts, &md5, 2938
2939#ifdef CONFIG_TCP_MD5SIG
2940 rcu_read_lock();
2941 md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req);
2942#endif
2943 tcp_header_size = tcp_synack_options(sk, req, mss, skb, &opts, md5,
2942 foc) + sizeof(*th); 2944 foc) + sizeof(*th);
2943 2945
2944 skb_push(skb, tcp_header_size); 2946 skb_push(skb, tcp_header_size);
@@ -2969,10 +2971,10 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
2969 2971
2970#ifdef CONFIG_TCP_MD5SIG 2972#ifdef CONFIG_TCP_MD5SIG
2971 /* Okay, we have all we need - do the md5 hash if needed */ 2973 /* Okay, we have all we need - do the md5 hash if needed */
2972 if (md5) { 2974 if (md5)
2973 tcp_rsk(req)->af_specific->calc_md5_hash(opts.hash_location, 2975 tcp_rsk(req)->af_specific->calc_md5_hash(opts.hash_location,
2974 md5, NULL, req, skb); 2976 md5, NULL, req, skb);
2975 } 2977 rcu_read_unlock();
2976#endif 2978#endif
2977 2979
2978 return skb; 2980 return skb;