Commit 7e56b5d6 authored by Catalin Marinas's avatar Catalin Marinas Committed by David S. Miller

net: Fix memory leak in the proto_register function

If the slub allocator is used, kmem_cache_create() may merge two or more
kmem_cache's into one but the cache name pointer is not updated and
kmem_cache_name() is no longer guaranteed to return the pointer passed
to the former function. This patch stores the kmalloc'ed pointers in the
corresponding request_sock_ops and timewait_sock_ops structures.
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Acked-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Reviewed-by: default avatarChristoph Lameter <cl@linux-foundation.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 33cf71ce
...@@ -31,6 +31,7 @@ struct request_sock_ops { ...@@ -31,6 +31,7 @@ struct request_sock_ops {
int family; int family;
int obj_size; int obj_size;
struct kmem_cache *slab; struct kmem_cache *slab;
char *slab_name;
int (*rtx_syn_ack)(struct sock *sk, int (*rtx_syn_ack)(struct sock *sk,
struct request_sock *req); struct request_sock *req);
void (*send_ack)(struct sock *sk, struct sk_buff *skb, void (*send_ack)(struct sock *sk, struct sk_buff *skb,
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
struct timewait_sock_ops { struct timewait_sock_ops {
struct kmem_cache *twsk_slab; struct kmem_cache *twsk_slab;
char *twsk_slab_name;
unsigned int twsk_obj_size; unsigned int twsk_obj_size;
int (*twsk_unique)(struct sock *sk, int (*twsk_unique)(struct sock *sk,
struct sock *sktw, void *twp); struct sock *sktw, void *twp);
......
...@@ -2035,9 +2035,6 @@ static inline void release_proto_idx(struct proto *prot) ...@@ -2035,9 +2035,6 @@ static inline void release_proto_idx(struct proto *prot)
int proto_register(struct proto *prot, int alloc_slab) int proto_register(struct proto *prot, int alloc_slab)
{ {
char *request_sock_slab_name = NULL;
char *timewait_sock_slab_name;
if (alloc_slab) { if (alloc_slab) {
prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0, prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0,
SLAB_HWCACHE_ALIGN, NULL); SLAB_HWCACHE_ALIGN, NULL);
...@@ -2051,12 +2048,12 @@ int proto_register(struct proto *prot, int alloc_slab) ...@@ -2051,12 +2048,12 @@ int proto_register(struct proto *prot, int alloc_slab)
if (prot->rsk_prot != NULL) { if (prot->rsk_prot != NULL) {
static const char mask[] = "request_sock_%s"; static const char mask[] = "request_sock_%s";
request_sock_slab_name = kmalloc(strlen(prot->name) + sizeof(mask) - 1, GFP_KERNEL); prot->rsk_prot->slab_name = kmalloc(strlen(prot->name) + sizeof(mask) - 1, GFP_KERNEL);
if (request_sock_slab_name == NULL) if (prot->rsk_prot->slab_name == NULL)
goto out_free_sock_slab; goto out_free_sock_slab;
sprintf(request_sock_slab_name, mask, prot->name); sprintf(prot->rsk_prot->slab_name, mask, prot->name);
prot->rsk_prot->slab = kmem_cache_create(request_sock_slab_name, prot->rsk_prot->slab = kmem_cache_create(prot->rsk_prot->slab_name,
prot->rsk_prot->obj_size, 0, prot->rsk_prot->obj_size, 0,
SLAB_HWCACHE_ALIGN, NULL); SLAB_HWCACHE_ALIGN, NULL);
...@@ -2070,14 +2067,14 @@ int proto_register(struct proto *prot, int alloc_slab) ...@@ -2070,14 +2067,14 @@ int proto_register(struct proto *prot, int alloc_slab)
if (prot->twsk_prot != NULL) { if (prot->twsk_prot != NULL) {
static const char mask[] = "tw_sock_%s"; static const char mask[] = "tw_sock_%s";
timewait_sock_slab_name = kmalloc(strlen(prot->name) + sizeof(mask) - 1, GFP_KERNEL); prot->twsk_prot->twsk_slab_name = kmalloc(strlen(prot->name) + sizeof(mask) - 1, GFP_KERNEL);
if (timewait_sock_slab_name == NULL) if (prot->twsk_prot->twsk_slab_name == NULL)
goto out_free_request_sock_slab; goto out_free_request_sock_slab;
sprintf(timewait_sock_slab_name, mask, prot->name); sprintf(prot->twsk_prot->twsk_slab_name, mask, prot->name);
prot->twsk_prot->twsk_slab = prot->twsk_prot->twsk_slab =
kmem_cache_create(timewait_sock_slab_name, kmem_cache_create(prot->twsk_prot->twsk_slab_name,
prot->twsk_prot->twsk_obj_size, prot->twsk_prot->twsk_obj_size,
0, SLAB_HWCACHE_ALIGN, 0, SLAB_HWCACHE_ALIGN,
NULL); NULL);
...@@ -2093,14 +2090,14 @@ int proto_register(struct proto *prot, int alloc_slab) ...@@ -2093,14 +2090,14 @@ int proto_register(struct proto *prot, int alloc_slab)
return 0; return 0;
out_free_timewait_sock_slab_name: out_free_timewait_sock_slab_name:
kfree(timewait_sock_slab_name); kfree(prot->twsk_prot->twsk_slab_name);
out_free_request_sock_slab: out_free_request_sock_slab:
if (prot->rsk_prot && prot->rsk_prot->slab) { if (prot->rsk_prot && prot->rsk_prot->slab) {
kmem_cache_destroy(prot->rsk_prot->slab); kmem_cache_destroy(prot->rsk_prot->slab);
prot->rsk_prot->slab = NULL; prot->rsk_prot->slab = NULL;
} }
out_free_request_sock_slab_name: out_free_request_sock_slab_name:
kfree(request_sock_slab_name); kfree(prot->rsk_prot->slab_name);
out_free_sock_slab: out_free_sock_slab:
kmem_cache_destroy(prot->slab); kmem_cache_destroy(prot->slab);
prot->slab = NULL; prot->slab = NULL;
...@@ -2123,18 +2120,14 @@ void proto_unregister(struct proto *prot) ...@@ -2123,18 +2120,14 @@ void proto_unregister(struct proto *prot)
} }
if (prot->rsk_prot != NULL && prot->rsk_prot->slab != NULL) { if (prot->rsk_prot != NULL && prot->rsk_prot->slab != NULL) {
const char *name = kmem_cache_name(prot->rsk_prot->slab);
kmem_cache_destroy(prot->rsk_prot->slab); kmem_cache_destroy(prot->rsk_prot->slab);
kfree(name); kfree(prot->rsk_prot->slab_name);
prot->rsk_prot->slab = NULL; prot->rsk_prot->slab = NULL;
} }
if (prot->twsk_prot != NULL && prot->twsk_prot->twsk_slab != NULL) { if (prot->twsk_prot != NULL && prot->twsk_prot->twsk_slab != NULL) {
const char *name = kmem_cache_name(prot->twsk_prot->twsk_slab);
kmem_cache_destroy(prot->twsk_prot->twsk_slab); kmem_cache_destroy(prot->twsk_prot->twsk_slab);
kfree(name); kfree(prot->twsk_prot->twsk_slab_name);
prot->twsk_prot->twsk_slab = NULL; prot->twsk_prot->twsk_slab = NULL;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment