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; |
