tcp: properly release md5sig_pool references
Subsystems (3)
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
@@ -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
@@ -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);
Quoted 5 lines · Zheng
tcp_v4_md5_do_add()increases use count ofmd5sig_poolby one for each tcp md5sig peer, so we should calltcp_free_md5sig_pool()for each peer when destroying the socket.Signed-off-by Zheng Yan <[email protected]>
As managing the use count is rather expensive, I think it would be better to hold a single reference instead of multiple ones ?
Quoted 11 lines · Eric Dumazet
Quoted 5 lines · Zheng
tcp_v4_md5_do_add()increases use count ofmd5sig_poolby one for each tcp md5sig peer, so we should calltcp_free_md5sig_pool()for each peer when destroying the socket.Signed-off-by Zheng Yan <[email protected]>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
@@ -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
@@ -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 ; } }