vfs: allocate page instead of names_cache buffer in mount_block_root
authorJeff Layton <jlayton@redhat.com>
Wed, 10 Oct 2012 19:25:26 +0000 (15:25 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 12 Oct 2012 04:32:03 +0000 (00:32 -0400)
First, it's incorrect to call putname() after __getname_gfp() since the
bare __getname_gfp() call skips the auditing code, while putname()
doesn't.

mount_block_root allocates a PATH_MAX buffer via __getname_gfp, and then
calls get_fs_names to fill the buffer. That function can call
get_filesystem_list which assumes that that buffer is a full page in
size. On arches where PAGE_SIZE != 4k, then this could potentially
overrun.

In practice, it's hard to imagine the list of filesystem names even
approaching 4k, but it's best to be safe. Just allocate a page for this
purpose instead.

With this, we can also remove the __getname_gfp() definition since there
are no more callers.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
include/linux/fs.h
init/do_mounts.c

index 8ef2fc9..b44b4ca 100644 (file)
@@ -2228,8 +2228,7 @@ extern void __init vfs_caches_init(unsigned long);
 
 extern struct kmem_cache *names_cachep;
 
-#define __getname_gfp(gfp)     kmem_cache_alloc(names_cachep, (gfp))
-#define __getname()            __getname_gfp(GFP_KERNEL)
+#define __getname()            kmem_cache_alloc(names_cachep, GFP_KERNEL)
 #define __putname(name)                kmem_cache_free(names_cachep, (void *)(name))
 #ifndef CONFIG_AUDITSYSCALL
 #define putname(name)   __putname(name)
index d3f0aee..f8a6642 100644 (file)
@@ -353,8 +353,9 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data)
 
 void __init mount_block_root(char *name, int flags)
 {
-       char *fs_names = __getname_gfp(GFP_KERNEL
-               | __GFP_NOTRACK_FALSE_POSITIVE);
+       struct page *page = alloc_page(GFP_KERNEL |
+                                       __GFP_NOTRACK_FALSE_POSITIVE);
+       char *fs_names = page_address(page);
        char *p;
 #ifdef CONFIG_BLOCK
        char b[BDEVNAME_SIZE];
@@ -406,7 +407,7 @@ retry:
 #endif
        panic("VFS: Unable to mount root fs on %s", b);
 out:
-       putname(fs_names);
+       put_page(page);
 }
  
 #ifdef CONFIG_ROOT_NFS