]>
Commit | Line | Data |
---|---|---|
489cd451 GKH |
1 | From 399504e21a10be16dd1408ba0147367d9d82a10c Mon Sep 17 00:00:00 2001 |
2 | From: Al Viro <viro@zeniv.linux.org.uk> | |
3 | Date: Sun, 6 Jan 2019 11:41:29 -0500 | |
4 | Subject: fix cgroup_do_mount() handling of failure exits | |
5 | ||
6 | From: Al Viro <viro@zeniv.linux.org.uk> | |
7 | ||
8 | commit 399504e21a10be16dd1408ba0147367d9d82a10c upstream. | |
9 | ||
10 | same story as with last May fixes in sysfs (7b745a4e4051 | |
11 | "unfuck sysfs_mount()"); new_sb is left uninitialized | |
12 | in case of early errors in kernfs_mount_ns() and papering | |
13 | over it by treating any error from kernfs_mount_ns() as | |
14 | equivalent to !new_ns ends up conflating the cases when | |
15 | objects had never been transferred to a superblock with | |
16 | ones when that has happened and resulting new superblock | |
17 | had been dropped. Easily fixed (same way as in sysfs | |
18 | case). Additionally, there's a superblock leak on | |
19 | kernfs_node_dentry() failure *and* a dentry leak inside | |
20 | kernfs_node_dentry() itself - the latter on probably | |
21 | impossible errors, but the former not impossible to trigger | |
22 | (as the matter of fact, injecting allocation failures | |
23 | at that point *does* trigger it). | |
24 | ||
25 | Cc: stable@kernel.org | |
26 | Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> | |
27 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
28 | ||
29 | --- | |
30 | fs/kernfs/mount.c | 8 ++++++-- | |
31 | kernel/cgroup/cgroup.c | 9 ++++++--- | |
32 | 2 files changed, 12 insertions(+), 5 deletions(-) | |
33 | ||
34 | --- a/fs/kernfs/mount.c | |
35 | +++ b/fs/kernfs/mount.c | |
36 | @@ -196,8 +196,10 @@ struct dentry *kernfs_node_dentry(struct | |
37 | return dentry; | |
38 | ||
39 | knparent = find_next_ancestor(kn, NULL); | |
40 | - if (WARN_ON(!knparent)) | |
41 | + if (WARN_ON(!knparent)) { | |
42 | + dput(dentry); | |
43 | return ERR_PTR(-EINVAL); | |
44 | + } | |
45 | ||
46 | do { | |
47 | struct dentry *dtmp; | |
48 | @@ -206,8 +208,10 @@ struct dentry *kernfs_node_dentry(struct | |
49 | if (kn == knparent) | |
50 | return dentry; | |
51 | kntmp = find_next_ancestor(kn, knparent); | |
52 | - if (WARN_ON(!kntmp)) | |
53 | + if (WARN_ON(!kntmp)) { | |
54 | + dput(dentry); | |
55 | return ERR_PTR(-EINVAL); | |
56 | + } | |
57 | dtmp = lookup_one_len_unlocked(kntmp->name, dentry, | |
58 | strlen(kntmp->name)); | |
59 | dput(dentry); | |
60 | --- a/kernel/cgroup/cgroup.c | |
61 | +++ b/kernel/cgroup/cgroup.c | |
62 | @@ -1998,7 +1998,7 @@ struct dentry *cgroup_do_mount(struct fi | |
63 | struct cgroup_namespace *ns) | |
64 | { | |
65 | struct dentry *dentry; | |
66 | - bool new_sb; | |
67 | + bool new_sb = false; | |
68 | ||
69 | dentry = kernfs_mount(fs_type, flags, root->kf_root, magic, &new_sb); | |
70 | ||
71 | @@ -2008,6 +2008,7 @@ struct dentry *cgroup_do_mount(struct fi | |
72 | */ | |
73 | if (!IS_ERR(dentry) && ns != &init_cgroup_ns) { | |
74 | struct dentry *nsdentry; | |
75 | + struct super_block *sb = dentry->d_sb; | |
76 | struct cgroup *cgrp; | |
77 | ||
78 | mutex_lock(&cgroup_mutex); | |
79 | @@ -2018,12 +2019,14 @@ struct dentry *cgroup_do_mount(struct fi | |
80 | spin_unlock_irq(&css_set_lock); | |
81 | mutex_unlock(&cgroup_mutex); | |
82 | ||
83 | - nsdentry = kernfs_node_dentry(cgrp->kn, dentry->d_sb); | |
84 | + nsdentry = kernfs_node_dentry(cgrp->kn, sb); | |
85 | dput(dentry); | |
86 | + if (IS_ERR(nsdentry)) | |
87 | + deactivate_locked_super(sb); | |
88 | dentry = nsdentry; | |
89 | } | |
90 | ||
91 | - if (IS_ERR(dentry) || !new_sb) | |
92 | + if (!new_sb) | |
93 | cgroup_put(&root->cgrp); | |
94 | ||
95 | return dentry; |