Commit 84c1cf62 authored by Pekka Enberg's avatar Pekka Enberg

SLUB: Fix merged slab cache names

As explained by Linus "I'm Proud to be an American" Torvalds:

  Looking at the merging code, I actually think it's totally
  buggy. If you have something like this:

   - load module A: create slab cache A

   - load module B: create slab cache B that can merge with A

   - unload module A

   - "cat /proc/slabinfo": BOOM. Oops.

  exactly because the name is not handled correctly, and you'll have
  module B holding open a slab cache that has a name pointer that points
  to module A that no longer exists.

This patch fixes the problem by using kstrdup() to allocate dynamic memory for
->name of "struct kmem_cache" as suggested by Christoph Lameter.
Acked-by: default avatarChristoph Lameter <cl@linux.com>
Cc: David Rientjes <rientjes@google.com>
Reported-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarPekka Enberg <penberg@kernel.org>

Conflicts:

	mm/slub.c
parent db210e70
...@@ -209,6 +209,7 @@ static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p) ...@@ -209,6 +209,7 @@ static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p)
{ return 0; } { return 0; }
static inline void sysfs_slab_remove(struct kmem_cache *s) static inline void sysfs_slab_remove(struct kmem_cache *s)
{ {
kfree(s->name);
kfree(s); kfree(s);
} }
...@@ -3169,6 +3170,16 @@ void __init kmem_cache_init(void) ...@@ -3169,6 +3170,16 @@ void __init kmem_cache_init(void)
slab_state = UP; slab_state = UP;
/* Provide the correct kmalloc names now that the caches are up */ /* Provide the correct kmalloc names now that the caches are up */
if (KMALLOC_MIN_SIZE <= 32) {
kmalloc_caches[1]->name = kstrdup(kmalloc_caches[1]->name, GFP_NOWAIT);
BUG_ON(!kmalloc_caches[1]->name);
}
if (KMALLOC_MIN_SIZE <= 64) {
kmalloc_caches[2]->name = kstrdup(kmalloc_caches[2]->name, GFP_NOWAIT);
BUG_ON(!kmalloc_caches[2]->name);
}
for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) { for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) {
char *s = kasprintf(GFP_NOWAIT, "kmalloc-%d", 1 << i); char *s = kasprintf(GFP_NOWAIT, "kmalloc-%d", 1 << i);
...@@ -3271,6 +3282,7 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, ...@@ -3271,6 +3282,7 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
size_t align, unsigned long flags, void (*ctor)(void *)) size_t align, unsigned long flags, void (*ctor)(void *))
{ {
struct kmem_cache *s; struct kmem_cache *s;
char *n;
if (WARN_ON(!name)) if (WARN_ON(!name))
return NULL; return NULL;
...@@ -3294,19 +3306,25 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, ...@@ -3294,19 +3306,25 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
return s; return s;
} }
n = kstrdup(name, GFP_KERNEL);
if (!n)
goto err;
s = kmalloc(kmem_size, GFP_KERNEL); s = kmalloc(kmem_size, GFP_KERNEL);
if (s) { if (s) {
if (kmem_cache_open(s, name, if (kmem_cache_open(s, n,
size, align, flags, ctor)) { size, align, flags, ctor)) {
list_add(&s->list, &slab_caches); list_add(&s->list, &slab_caches);
if (sysfs_slab_add(s)) { if (sysfs_slab_add(s)) {
list_del(&s->list); list_del(&s->list);
kfree(n);
kfree(s); kfree(s);
goto err; goto err;
} }
up_write(&slub_lock); up_write(&slub_lock);
return s; return s;
} }
kfree(n);
kfree(s); kfree(s);
} }
up_write(&slub_lock); up_write(&slub_lock);
...@@ -4439,6 +4457,7 @@ static void kmem_cache_release(struct kobject *kobj) ...@@ -4439,6 +4457,7 @@ static void kmem_cache_release(struct kobject *kobj)
{ {
struct kmem_cache *s = to_slab(kobj); struct kmem_cache *s = to_slab(kobj);
kfree(s->name);
kfree(s); kfree(s);
} }
......
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