diff options
author | Eric Dumazet <edumazet@google.com> | 2015-03-24 18:58:52 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-24 21:16:29 -0400 |
commit | 80f03e27a309f3e32ebdd9629ac0320005a2180b (patch) | |
tree | 4516faa5da144dde9c1cd899ae3d99090e3852db /net/ipv4/tcp_output.c | |
parent | 9ead3527f5967440f2ff57fd2fa25dd0e460fc5a (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.c | 20 |
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; |