aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYan, Zheng <zheng.z.yan@intel.com>2011-09-29 13:10:10 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-11-11 12:36:27 -0500
commit37c88f5fe7f287a945949e6f4570700c210ebe0f (patch)
tree70ee5416e53203a4186d46fd493fb0ee02a8c74c
parent18743353b3154f0ff7c29f3c5ae3a8466a70d73a (diff)
tcp: properly handle md5sig_pool references
[ Upstream commit 260fcbeb1ae9e768a44c9925338fbacb0d7e5ba9 ] 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. Signed-off-by: Zheng Yan <zheng.z.yan@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--net/ipv4/tcp_ipv4.c11
-rw-r--r--net/ipv6/tcp_ipv6.c8
2 files changed, 12 insertions, 7 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index b3e6956d7ba..69790aa3198 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -909,18 +909,21 @@ int tcp_v4_md5_do_add(struct sock *sk, __be32 addr,
909 } 909 }
910 sk_nocaps_add(sk, NETIF_F_GSO_MASK); 910 sk_nocaps_add(sk, NETIF_F_GSO_MASK);
911 } 911 }
912 if (tcp_alloc_md5sig_pool(sk) == NULL) { 912
913 md5sig = tp->md5sig_info;
914 if (md5sig->entries4 == 0 &&
915 tcp_alloc_md5sig_pool(sk) == NULL) {
913 kfree(newkey); 916 kfree(newkey);
914 return -ENOMEM; 917 return -ENOMEM;
915 } 918 }
916 md5sig = tp->md5sig_info;
917 919
918 if (md5sig->alloced4 == md5sig->entries4) { 920 if (md5sig->alloced4 == md5sig->entries4) {
919 keys = kmalloc((sizeof(*keys) * 921 keys = kmalloc((sizeof(*keys) *
920 (md5sig->entries4 + 1)), GFP_ATOMIC); 922 (md5sig->entries4 + 1)), GFP_ATOMIC);
921 if (!keys) { 923 if (!keys) {
922 kfree(newkey); 924 kfree(newkey);
923 tcp_free_md5sig_pool(); 925 if (md5sig->entries4 == 0)
926 tcp_free_md5sig_pool();
924 return -ENOMEM; 927 return -ENOMEM;
925 } 928 }
926 929
@@ -964,6 +967,7 @@ int tcp_v4_md5_do_del(struct sock *sk, __be32 addr)
964 kfree(tp->md5sig_info->keys4); 967 kfree(tp->md5sig_info->keys4);
965 tp->md5sig_info->keys4 = NULL; 968 tp->md5sig_info->keys4 = NULL;
966 tp->md5sig_info->alloced4 = 0; 969 tp->md5sig_info->alloced4 = 0;
970 tcp_free_md5sig_pool();
967 } else if (tp->md5sig_info->entries4 != i) { 971 } else if (tp->md5sig_info->entries4 != i) {
968 /* Need to do some manipulation */ 972 /* Need to do some manipulation */
969 memmove(&tp->md5sig_info->keys4[i], 973 memmove(&tp->md5sig_info->keys4[i],
@@ -971,7 +975,6 @@ int tcp_v4_md5_do_del(struct sock *sk, __be32 addr)
971 (tp->md5sig_info->entries4 - i) * 975 (tp->md5sig_info->entries4 - i) *
972 sizeof(struct tcp4_md5sig_key)); 976 sizeof(struct tcp4_md5sig_key));
973 } 977 }
974 tcp_free_md5sig_pool();
975 return 0; 978 return 0;
976 } 979 }
977 } 980 }
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 7c43e861475..af78a16c830 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -605,7 +605,8 @@ static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer,
605 } 605 }
606 sk_nocaps_add(sk, NETIF_F_GSO_MASK); 606 sk_nocaps_add(sk, NETIF_F_GSO_MASK);
607 } 607 }
608 if (tcp_alloc_md5sig_pool(sk) == NULL) { 608 if (tp->md5sig_info->entries6 == 0 &&
609 tcp_alloc_md5sig_pool(sk) == NULL) {
609 kfree(newkey); 610 kfree(newkey);
610 return -ENOMEM; 611 return -ENOMEM;
611 } 612 }
@@ -614,8 +615,9 @@ static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer,
614 (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC); 615 (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC);
615 616
616 if (!keys) { 617 if (!keys) {
617 tcp_free_md5sig_pool();
618 kfree(newkey); 618 kfree(newkey);
619 if (tp->md5sig_info->entries6 == 0)
620 tcp_free_md5sig_pool();
619 return -ENOMEM; 621 return -ENOMEM;
620 } 622 }
621 623
@@ -661,6 +663,7 @@ static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer)
661 kfree(tp->md5sig_info->keys6); 663 kfree(tp->md5sig_info->keys6);
662 tp->md5sig_info->keys6 = NULL; 664 tp->md5sig_info->keys6 = NULL;
663 tp->md5sig_info->alloced6 = 0; 665 tp->md5sig_info->alloced6 = 0;
666 tcp_free_md5sig_pool();
664 } else { 667 } else {
665 /* shrink the database */ 668 /* shrink the database */
666 if (tp->md5sig_info->entries6 != i) 669 if (tp->md5sig_info->entries6 != i)
@@ -669,7 +672,6 @@ static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer)
669 (tp->md5sig_info->entries6 - i) 672 (tp->md5sig_info->entries6 - i)
670 * sizeof (tp->md5sig_info->keys6[0])); 673 * sizeof (tp->md5sig_info->keys6[0]));
671 } 674 }
672 tcp_free_md5sig_pool();
673 return 0; 675 return 0;
674 } 676 }
675 } 677 }