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: Christoph Lameter <cl@linux.com> Cc: David Rientjes <rientjes@google.com> Reported-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Pekka Enberg <penberg@kernel.org> Conflicts: mm/slub.c
This commit is contained in:
parent
db210e70e5
commit
84c1cf6246
21
mm/slub.c
21
mm/slub.c
@ -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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
struct kmem_cache *s = to_slab(kobj);
|
struct kmem_cache *s = to_slab(kobj);
|
||||||
|
|
||||||
|
kfree(s->name);
|
||||||
kfree(s);
|
kfree(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user