lkml.org 
[lkml]   [2019]   [Apr]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 4.4 12/15] hugetlbfs: fix memory leak for resv_map
    Date
    From: Mike Kravetz <mike.kravetz@oracle.com>

    [ Upstream commit 58b6e5e8f1addd44583d61b0a03c0f5519527e35 ]

    When mknod is used to create a block special file in hugetlbfs, it will
    allocate an inode and kmalloc a 'struct resv_map' via resv_map_alloc().
    inode->i_mapping->private_data will point the newly allocated resv_map.
    However, when the device special file is opened bd_acquire() will set
    inode->i_mapping to bd_inode->i_mapping. Thus the pointer to the
    allocated resv_map is lost and the structure is leaked.

    Programs to reproduce:
    mount -t hugetlbfs nodev hugetlbfs
    mknod hugetlbfs/dev b 0 0
    exec 30<> hugetlbfs/dev
    umount hugetlbfs/

    resv_map structures are only needed for inodes which can have associated
    page allocations. To fix the leak, only allocate resv_map for those
    inodes which could possibly be associated with page allocations.

    Link: http://lkml.kernel.org/r/20190401213101.16476-1-mike.kravetz@oracle.com
    Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com>
    Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
    Reported-by: Yufen Yu <yuyufen@huawei.com>
    Suggested-by: Yufen Yu <yuyufen@huawei.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    fs/hugetlbfs/inode.c | 20 ++++++++++++++------
    1 file changed, 14 insertions(+), 6 deletions(-)

    diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
    index cefae2350da5..27c4e2ac39a9 100644
    --- a/fs/hugetlbfs/inode.c
    +++ b/fs/hugetlbfs/inode.c
    @@ -745,11 +745,17 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
    umode_t mode, dev_t dev)
    {
    struct inode *inode;
    - struct resv_map *resv_map;
    + struct resv_map *resv_map = NULL;

    - resv_map = resv_map_alloc();
    - if (!resv_map)
    - return NULL;
    + /*
    + * Reserve maps are only needed for inodes that can have associated
    + * page allocations.
    + */
    + if (S_ISREG(mode) || S_ISLNK(mode)) {
    + resv_map = resv_map_alloc();
    + if (!resv_map)
    + return NULL;
    + }

    inode = new_inode(sb);
    if (inode) {
    @@ -790,8 +796,10 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
    break;
    }
    lockdep_annotate_inode_mutex_key(inode);
    - } else
    - kref_put(&resv_map->refs, resv_map_release);
    + } else {
    + if (resv_map)
    + kref_put(&resv_map->refs, resv_map_release);
    + }

    return inode;
    }
    --
    2.19.1
    \
     
     \ /
      Last update: 2019-04-24 16:53    [W:4.291 / U:0.060 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site