hugetlbfs: initialize shared policy as part of inode allocation
Any time after inode allocation, destroy_inode can be called. The hugetlbfs inode contains a shared_policy structure, and mpol_free_shared_policy is unconditionally called as part of hugetlbfs_destroy_inode. Initialize the policy as part of inode allocation so that any quick (error path) calls to destroy_inode will be handed an initialized policy. syzkaller fuzzer found this bug, that resulted in the following: BUG: KASAN: user-memory-access in atomic_inc include/asm-generic/atomic-instrumented.h:87 [inline] at addr 000000131730bd7a BUG: KASAN: user-memory-access in __lock_acquire+0x21a/0x3a80 kernel/locking/lockdep.c:3239 at addr 000000131730bd7a Write of size 4 by task syz-executor6/14086 CPU: 3 PID: 14086 Comm: syz-executor6 Not tainted 4.11.0-rc3+ #364 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 Call Trace: atomic_inc include/asm-generic/atomic-instrumented.h:87 [inline] __lock_acquire+0x21a/0x3a80 kernel/locking/lockdep.c:3239 lock_acquire+0x1ee/0x590 kernel/locking/lockdep.c:3762 __raw_write_lock include/linux/rwlock_api_smp.h:210 [inline] _raw_write_lock+0x33/0x50 kernel/locking/spinlock.c:295 mpol_free_shared_policy+0x43/0xb0 mm/mempolicy.c:2536 hugetlbfs_destroy_inode+0xca/0x120 fs/hugetlbfs/inode.c:952 alloc_inode+0x10d/0x180 fs/inode.c:216 new_inode_pseudo+0x69/0x190 fs/inode.c:889 new_inode+0x1c/0x40 fs/inode.c:918 hugetlbfs_get_inode+0x40/0x420 fs/hugetlbfs/inode.c:734 hugetlb_file_setup+0x329/0x9f0 fs/hugetlbfs/inode.c:1282 newseg+0x422/0xd30 ipc/shm.c:575 ipcget_new ipc/util.c:285 [inline] ipcget+0x21e/0x580 ipc/util.c:639 SYSC_shmget ipc/shm.c:673 [inline] SyS_shmget+0x158/0x230 ipc/shm.c:657 entry_SYSCALL_64_fastpath+0x1f/0xc2 Analysis provided by Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Link: http://lkml.kernel.org/r/1490477850-7944-1-git-send-email-mike.kravetz@oracle.com Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com> Reported-by: Dmitry Vyukov <dvyukov@google.com> Acked-by: Hillf Danton <hillf.zj@alibaba-inc.com> Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Cc: Michal Hocko <mhocko@suse.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
906f2a51c9
commit
4742a35d9d
|
@ -695,14 +695,11 @@ static struct inode *hugetlbfs_get_root(struct super_block *sb,
|
|||
|
||||
inode = new_inode(sb);
|
||||
if (inode) {
|
||||
struct hugetlbfs_inode_info *info;
|
||||
inode->i_ino = get_next_ino();
|
||||
inode->i_mode = S_IFDIR | config->mode;
|
||||
inode->i_uid = config->uid;
|
||||
inode->i_gid = config->gid;
|
||||
inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
|
||||
info = HUGETLBFS_I(inode);
|
||||
mpol_shared_policy_init(&info->policy, NULL);
|
||||
inode->i_op = &hugetlbfs_dir_inode_operations;
|
||||
inode->i_fop = &simple_dir_operations;
|
||||
/* directory inodes start off with i_nlink == 2 (for "." entry) */
|
||||
|
@ -733,7 +730,6 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
|
|||
|
||||
inode = new_inode(sb);
|
||||
if (inode) {
|
||||
struct hugetlbfs_inode_info *info;
|
||||
inode->i_ino = get_next_ino();
|
||||
inode_init_owner(inode, dir, mode);
|
||||
lockdep_set_class(&inode->i_mapping->i_mmap_rwsem,
|
||||
|
@ -741,15 +737,6 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
|
|||
inode->i_mapping->a_ops = &hugetlbfs_aops;
|
||||
inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
|
||||
inode->i_mapping->private_data = resv_map;
|
||||
info = HUGETLBFS_I(inode);
|
||||
/*
|
||||
* The policy is initialized here even if we are creating a
|
||||
* private inode because initialization simply creates an
|
||||
* an empty rb tree and calls rwlock_init(), later when we
|
||||
* call mpol_free_shared_policy() it will just return because
|
||||
* the rb tree will still be empty.
|
||||
*/
|
||||
mpol_shared_policy_init(&info->policy, NULL);
|
||||
switch (mode & S_IFMT) {
|
||||
default:
|
||||
init_special_inode(inode, mode, dev);
|
||||
|
@ -937,6 +924,18 @@ static struct inode *hugetlbfs_alloc_inode(struct super_block *sb)
|
|||
hugetlbfs_inc_free_inodes(sbinfo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Any time after allocation, hugetlbfs_destroy_inode can be called
|
||||
* for the inode. mpol_free_shared_policy is unconditionally called
|
||||
* as part of hugetlbfs_destroy_inode. So, initialize policy here
|
||||
* in case of a quick call to destroy.
|
||||
*
|
||||
* Note that the policy is initialized even if we are creating a
|
||||
* private inode. This simplifies hugetlbfs_destroy_inode.
|
||||
*/
|
||||
mpol_shared_policy_init(&p->policy, NULL);
|
||||
|
||||
return &p->vfs_inode;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue