aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-05-16 03:34:04 -0400
committerDavid S. Miller <davem@davemloft.net>2010-05-16 03:34:04 -0400
commit35790c0421121364883a167bab8a2e37e1f67f78 (patch)
treea3e032a9ba6bb77337176bef407d7408d6a10a4d /net
parentd77f873fdd21912803836da78f627d2efd267082 (diff)
tcp: fix MD5 (RFC2385) support
TCP MD5 support uses percpu data for temporary storage. It currently disables preemption so that same storage cannot be reclaimed by another thread on same cpu. We also have to make sure a softirq handler wont try to use also same context. Various bug reports demonstrated corruptions. Fix is to disable preemption and BH. Reported-by: Bhaskar Dutta <bhaskie@gmail.com> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/tcp.c34
1 files changed, 24 insertions, 10 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 0f8caf64caa3..296150b2a62f 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2839,7 +2839,6 @@ static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool * __percpu *pool)
2839 if (p->md5_desc.tfm) 2839 if (p->md5_desc.tfm)
2840 crypto_free_hash(p->md5_desc.tfm); 2840 crypto_free_hash(p->md5_desc.tfm);
2841 kfree(p); 2841 kfree(p);
2842 p = NULL;
2843 } 2842 }
2844 } 2843 }
2845 free_percpu(pool); 2844 free_percpu(pool);
@@ -2937,25 +2936,40 @@ retry:
2937 2936
2938EXPORT_SYMBOL(tcp_alloc_md5sig_pool); 2937EXPORT_SYMBOL(tcp_alloc_md5sig_pool);
2939 2938
2940struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu) 2939
2940/**
2941 * tcp_get_md5sig_pool - get md5sig_pool for this user
2942 *
2943 * We use percpu structure, so if we succeed, we exit with preemption
2944 * and BH disabled, to make sure another thread or softirq handling
2945 * wont try to get same context.
2946 */
2947struct tcp_md5sig_pool *tcp_get_md5sig_pool(void)
2941{ 2948{
2942 struct tcp_md5sig_pool * __percpu *p; 2949 struct tcp_md5sig_pool * __percpu *p;
2943 spin_lock_bh(&tcp_md5sig_pool_lock); 2950
2951 local_bh_disable();
2952
2953 spin_lock(&tcp_md5sig_pool_lock);
2944 p = tcp_md5sig_pool; 2954 p = tcp_md5sig_pool;
2945 if (p) 2955 if (p)
2946 tcp_md5sig_users++; 2956 tcp_md5sig_users++;
2947 spin_unlock_bh(&tcp_md5sig_pool_lock); 2957 spin_unlock(&tcp_md5sig_pool_lock);
2948 return (p ? *per_cpu_ptr(p, cpu) : NULL); 2958
2949} 2959 if (p)
2960 return *per_cpu_ptr(p, smp_processor_id());
2950 2961
2951EXPORT_SYMBOL(__tcp_get_md5sig_pool); 2962 local_bh_enable();
2963 return NULL;
2964}
2965EXPORT_SYMBOL(tcp_get_md5sig_pool);
2952 2966
2953void __tcp_put_md5sig_pool(void) 2967void tcp_put_md5sig_pool(void)
2954{ 2968{
2969 local_bh_enable();
2955 tcp_free_md5sig_pool(); 2970 tcp_free_md5sig_pool();
2956} 2971}
2957 2972EXPORT_SYMBOL(tcp_put_md5sig_pool);
2958EXPORT_SYMBOL(__tcp_put_md5sig_pool);
2959 2973
2960int tcp_md5_hash_header(struct tcp_md5sig_pool *hp, 2974int tcp_md5_hash_header(struct tcp_md5sig_pool *hp,
2961 struct tcphdr *th) 2975 struct tcphdr *th)