aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/net/tcp.h21
-rw-r--r--net/ipv4/tcp.c34
2 files changed, 27 insertions, 28 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 75be5a28815d..aa04b9a5093b 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1197,30 +1197,15 @@ extern int tcp_v4_md5_do_del(struct sock *sk,
1197extern struct tcp_md5sig_pool * __percpu *tcp_alloc_md5sig_pool(struct sock *); 1197extern struct tcp_md5sig_pool * __percpu *tcp_alloc_md5sig_pool(struct sock *);
1198extern void tcp_free_md5sig_pool(void); 1198extern void tcp_free_md5sig_pool(void);
1199 1199
1200extern struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu); 1200extern struct tcp_md5sig_pool *tcp_get_md5sig_pool(void);
1201extern void __tcp_put_md5sig_pool(void); 1201extern void tcp_put_md5sig_pool(void);
1202
1202extern int tcp_md5_hash_header(struct tcp_md5sig_pool *, struct tcphdr *); 1203extern int tcp_md5_hash_header(struct tcp_md5sig_pool *, struct tcphdr *);
1203extern int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, struct sk_buff *, 1204extern int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, struct sk_buff *,
1204 unsigned header_len); 1205 unsigned header_len);
1205extern int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, 1206extern int tcp_md5_hash_key(struct tcp_md5sig_pool *hp,
1206 struct tcp_md5sig_key *key); 1207 struct tcp_md5sig_key *key);
1207 1208
1208static inline
1209struct tcp_md5sig_pool *tcp_get_md5sig_pool(void)
1210{
1211 int cpu = get_cpu();
1212 struct tcp_md5sig_pool *ret = __tcp_get_md5sig_pool(cpu);
1213 if (!ret)
1214 put_cpu();
1215 return ret;
1216}
1217
1218static inline void tcp_put_md5sig_pool(void)
1219{
1220 __tcp_put_md5sig_pool();
1221 put_cpu();
1222}
1223
1224/* write queue abstraction */ 1209/* write queue abstraction */
1225static inline void tcp_write_queue_purge(struct sock *sk) 1210static inline void tcp_write_queue_purge(struct sock *sk)
1226{ 1211{
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)