]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-5.0/hugetlbfs-fix-memory-leak-for-resv_map.patch
Linux 4.19.41
[thirdparty/kernel/stable-queue.git] / queue-5.0 / hugetlbfs-fix-memory-leak-for-resv_map.patch
1 From dde1a87702117a783e5157251893a18997544113 Mon Sep 17 00:00:00 2001
2 From: Mike Kravetz <mike.kravetz@oracle.com>
3 Date: Fri, 5 Apr 2019 18:39:06 -0700
4 Subject: hugetlbfs: fix memory leak for resv_map
5
6 [ Upstream commit 58b6e5e8f1addd44583d61b0a03c0f5519527e35 ]
7
8 When mknod is used to create a block special file in hugetlbfs, it will
9 allocate an inode and kmalloc a 'struct resv_map' via resv_map_alloc().
10 inode->i_mapping->private_data will point the newly allocated resv_map.
11 However, when the device special file is opened bd_acquire() will set
12 inode->i_mapping to bd_inode->i_mapping. Thus the pointer to the
13 allocated resv_map is lost and the structure is leaked.
14
15 Programs to reproduce:
16 mount -t hugetlbfs nodev hugetlbfs
17 mknod hugetlbfs/dev b 0 0
18 exec 30<> hugetlbfs/dev
19 umount hugetlbfs/
20
21 resv_map structures are only needed for inodes which can have associated
22 page allocations. To fix the leak, only allocate resv_map for those
23 inodes which could possibly be associated with page allocations.
24
25 Link: http://lkml.kernel.org/r/20190401213101.16476-1-mike.kravetz@oracle.com
26 Signed-off-by: Mike Kravetz <mike.kravetz@oracle.com>
27 Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
28 Reported-by: Yufen Yu <yuyufen@huawei.com>
29 Suggested-by: Yufen Yu <yuyufen@huawei.com>
30 Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
31 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
32 Signed-off-by: Sasha Levin (Microsoft) <sashal@kernel.org>
33 ---
34 fs/hugetlbfs/inode.c | 20 ++++++++++++++------
35 1 file changed, 14 insertions(+), 6 deletions(-)
36
37 diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
38 index a7fa037b876b..a3a3d256fb0e 100644
39 --- a/fs/hugetlbfs/inode.c
40 +++ b/fs/hugetlbfs/inode.c
41 @@ -741,11 +741,17 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
42 umode_t mode, dev_t dev)
43 {
44 struct inode *inode;
45 - struct resv_map *resv_map;
46 + struct resv_map *resv_map = NULL;
47
48 - resv_map = resv_map_alloc();
49 - if (!resv_map)
50 - return NULL;
51 + /*
52 + * Reserve maps are only needed for inodes that can have associated
53 + * page allocations.
54 + */
55 + if (S_ISREG(mode) || S_ISLNK(mode)) {
56 + resv_map = resv_map_alloc();
57 + if (!resv_map)
58 + return NULL;
59 + }
60
61 inode = new_inode(sb);
62 if (inode) {
63 @@ -780,8 +786,10 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
64 break;
65 }
66 lockdep_annotate_inode_mutex_key(inode);
67 - } else
68 - kref_put(&resv_map->refs, resv_map_release);
69 + } else {
70 + if (resv_map)
71 + kref_put(&resv_map->refs, resv_map_release);
72 + }
73
74 return inode;
75 }
76 --
77 2.20.1
78