| From foo@baz Mon 17 Aug 2020 11:30:21 AM CEST |
| From: Miaohe Lin <linmiaohe@huawei.com> |
| Date: Mon, 10 Aug 2020 08:16:58 -0400 |
| Subject: net: Fix potential memory leak in proto_register() |
| |
| From: Miaohe Lin <linmiaohe@huawei.com> |
| |
| [ Upstream commit 0f5907af39137f8183ed536aaa00f322d7365130 ] |
| |
| If we failed to assign proto idx, we free the twsk_slab_name but forget to |
| free the twsk_slab. Add a helper function tw_prot_cleanup() to free these |
| together and also use this helper function in proto_unregister(). |
| |
| Fixes: b45ce32135d1 ("sock: fix potential memory leak in proto_register()") |
| Signed-off-by: Miaohe Lin <linmiaohe@huawei.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/core/sock.c | 25 +++++++++++++++---------- |
| 1 file changed, 15 insertions(+), 10 deletions(-) |
| |
| --- a/net/core/sock.c |
| +++ b/net/core/sock.c |
| @@ -3354,6 +3354,16 @@ static void sock_inuse_add(struct net *n |
| } |
| #endif |
| |
| +static void tw_prot_cleanup(struct timewait_sock_ops *twsk_prot) |
| +{ |
| + if (!twsk_prot) |
| + return; |
| + kfree(twsk_prot->twsk_slab_name); |
| + twsk_prot->twsk_slab_name = NULL; |
| + kmem_cache_destroy(twsk_prot->twsk_slab); |
| + twsk_prot->twsk_slab = NULL; |
| +} |
| + |
| static void req_prot_cleanup(struct request_sock_ops *rsk_prot) |
| { |
| if (!rsk_prot) |
| @@ -3424,7 +3434,7 @@ int proto_register(struct proto *prot, i |
| prot->slab_flags, |
| NULL); |
| if (prot->twsk_prot->twsk_slab == NULL) |
| - goto out_free_timewait_sock_slab_name; |
| + goto out_free_timewait_sock_slab; |
| } |
| } |
| |
| @@ -3432,15 +3442,15 @@ int proto_register(struct proto *prot, i |
| ret = assign_proto_idx(prot); |
| if (ret) { |
| mutex_unlock(&proto_list_mutex); |
| - goto out_free_timewait_sock_slab_name; |
| + goto out_free_timewait_sock_slab; |
| } |
| list_add(&prot->node, &proto_list); |
| mutex_unlock(&proto_list_mutex); |
| return ret; |
| |
| -out_free_timewait_sock_slab_name: |
| +out_free_timewait_sock_slab: |
| if (alloc_slab && prot->twsk_prot) |
| - kfree(prot->twsk_prot->twsk_slab_name); |
| + tw_prot_cleanup(prot->twsk_prot); |
| out_free_request_sock_slab: |
| if (alloc_slab) { |
| req_prot_cleanup(prot->rsk_prot); |
| @@ -3464,12 +3474,7 @@ void proto_unregister(struct proto *prot |
| prot->slab = NULL; |
| |
| req_prot_cleanup(prot->rsk_prot); |
| - |
| - if (prot->twsk_prot != NULL && prot->twsk_prot->twsk_slab != NULL) { |
| - kmem_cache_destroy(prot->twsk_prot->twsk_slab); |
| - kfree(prot->twsk_prot->twsk_slab_name); |
| - prot->twsk_prot->twsk_slab = NULL; |
| - } |
| + tw_prot_cleanup(prot->twsk_prot); |
| } |
| EXPORT_SYMBOL(proto_unregister); |
| |