Skip to contentSkip to conversation

tcp: properly release md5sig_pool references

PATCH Superseded Yan, Zheng 2 participants 3 messages Sep 26, 2011

Subsystems (3)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore

Yan, Zheng

author
#0 lore raw

PATCH 1/1 tcp: properly release md5sig_pool references

tcp_v4_md5_do_add() increases use count of md5sig_pool by one for each tcp md5sig peer, so we should call tcp_free_md5sig_pool() for each peer when destroying the socket.

---

net/ipv4/tcp_ipv4.c +3 -2
index c34f015..3ca72ae 100644
@@ -1007,10 +1007,11 @@ static void tcp_v4_clear_md5_list(struct sock *sk)
 	 */
 	if (tp->md5sig_info->entries4) {
 		int i;
-		for (i = 0; i < tp->md5sig_info->entries4; i++)
+		for (i = 0; i < tp->md5sig_info->entries4; i++) {
 			kfree(tp->md5sig_info->keys4[i].base.key);
+			tcp_free_md5sig_pool();
+		}
 		tp->md5sig_info->entries4 = 0;
-		tcp_free_md5sig_pool();
 	}
 	if (tp->md5sig_info->keys4) {
 		kfree(tp->md5sig_info->keys4);
net/ipv6/tcp_ipv6.c +6 -4
index 3c9fa61..9dcef7c 100644
@@ -668,10 +668,11 @@ static void tcp_v6_clear_md5_list (struct sock *sk)
 	int i;
 
 	if (tp->md5sig_info->entries6) {
-		for (i = 0; i < tp->md5sig_info->entries6; i++)
+		for (i = 0; i < tp->md5sig_info->entries6; i++) {
 			kfree(tp->md5sig_info->keys6[i].base.key);
+			tcp_free_md5sig_pool();
+		}
 		tp->md5sig_info->entries6 = 0;
-		tcp_free_md5sig_pool();
 	}
 
 	kfree(tp->md5sig_info->keys6);
@@ -679,10 +680,11 @@ static void tcp_v6_clear_md5_list (struct sock *sk)
 	tp->md5sig_info->alloced6 = 0;
 
 	if (tp->md5sig_info->entries4) {
-		for (i = 0; i < tp->md5sig_info->entries4; i++)
+		for (i = 0; i < tp->md5sig_info->entries4; i++) {
 			kfree(tp->md5sig_info->keys4[i].base.key);
+			tcp_free_md5sig_pool();
+		}
 		tp->md5sig_info->entries4 = 0;
-		tcp_free_md5sig_pool();
 	}
 
 	kfree(tp->md5sig_info->keys4);
#1 lore raw
Quoted 5 lines · Zheng

tcp_v4_md5_do_add() increases use count of md5sig_pool by one for each tcp md5sig peer, so we should call tcp_free_md5sig_pool() for each peer when destroying the socket.

As managing the use count is rather expensive, I think it would be better to hold a single reference instead of multiple ones ?

author
#2 lore raw
Quoted 11 lines · Eric Dumazet
Quoted 5 lines · Zheng

tcp_v4_md5_do_add() increases use count of md5sig_pool by one for each tcp md5sig peer, so we should call tcp_free_md5sig_pool() for each peer when destroying the socket.

As managing the use count is rather expensive, I think it would be better to hold a single reference instead of multiple ones ?

Here is the new patch, thanks.

---
tcp: properly handle md5sig_pool references

tcp_v4_clear_md5_list() assumes that multiple tcp md5sig peers only hold one reference to md5sig_pool. but tcp_v4_md5_do_add() increases use count of md5sig_pool for each peer. This patch makes tcp_v4_md5_do_add() only increases use count for the first tcp md5sig peer.

---

net/ipv4/tcp_ipv4.c +6 -4
index c34f015..29ecfa9 100644
@@ -927,18 +927,20 @@ int tcp_v4_md5_do_add(struct sock *sk, __be32 addr,
 			}
 			sk_nocaps_add(sk, NETIF_F_GSO_MASK);
 		}
-		if (tcp_alloc_md5sig_pool(sk) == NULL) {
+
+		md5sig = tp->md5sig_info;
+		if (md5sig->entries4 == 0 && tcp_alloc_md5sig_pool(sk) == NULL) {
 			kfree(newkey);
 			return -ENOMEM;
 		}
-		md5sig = tp->md5sig_info;
 
 		if (md5sig->alloced4 == md5sig->entries4) {
 			keys = kmalloc((sizeof(*keys) *
 					(md5sig->entries4 + 1)), GFP_ATOMIC);
 			if (!keys) {
 				kfree(newkey);
-				tcp_free_md5sig_pool();
+				if (md5sig->entries4 == 0)
+					tcp_free_md5sig_pool();
 				return -ENOMEM;
 			}
 
@@ -982,6 +984,7 @@ int tcp_v4_md5_do_del(struct sock *sk, __be32 addr)
 				kfree(tp->md5sig_info->keys4);
 				tp->md5sig_info->keys4 = NULL;
 				tp->md5sig_info->alloced4 = 0;
+				tcp_free_md5sig_pool();
 			} else if (tp->md5sig_info->entries4 != i) {
 				/* Need to do some manipulation */
 				memmove(&tp->md5sig_info->keys4[i],
@@ -989,7 +992,6 @@ int tcp_v4_md5_do_del(struct sock *sk, __be32 addr)
 					(tp->md5sig_info->entries4 - i) *
 					 sizeof(struct tcp4_md5sig_key));
 			}
-			tcp_free_md5sig_pool();
 			return 0;
 		}
 	}
net/ipv6/tcp_ipv6.c +5 -3
index 3c9fa61..20ac0fc 100644
@@ -591,7 +591,8 @@ static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer,
 			}
 			sk_nocaps_add(sk, NETIF_F_GSO_MASK);
 		}
-		if (tcp_alloc_md5sig_pool(sk) == NULL) {
+		if (tp->md5sig_info->entries6 == 0 &&
+			tcp_alloc_md5sig_pool(sk) == NULL) {
 			kfree(newkey);
 			return -ENOMEM;
 		}
@@ -600,8 +601,9 @@ static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer,
 				       (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC);
 
 			if (!keys) {
-				tcp_free_md5sig_pool();
 				kfree(newkey);
+				if (tp->md5sig_info->entries6 == 0)
+					tcp_free_md5sig_pool();
 				return -ENOMEM;
 			}
 
@@ -647,6 +649,7 @@ static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer)
 				kfree(tp->md5sig_info->keys6);
 				tp->md5sig_info->keys6 = NULL;
 				tp->md5sig_info->alloced6 = 0;
+				tcp_free_md5sig_pool();
 			} else {
 				/* shrink the database */
 				if (tp->md5sig_info->entries6 != i)
@@ -655,7 +658,6 @@ static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer)
 						(tp->md5sig_info->entries6 - i)
 						* sizeof (tp->md5sig_info->keys6[0]));
 			}
-			tcp_free_md5sig_pool();
 			return 0;
 		}
 	}