diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 109 |
1 files changed, 51 insertions, 58 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 4f6f7635b59c..411728c0c8bb 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -112,9 +112,13 @@ struct vfsmount *alloc_vfsmnt(const char *name) | |||
112 | int err; | 112 | int err; |
113 | 113 | ||
114 | err = mnt_alloc_id(mnt); | 114 | err = mnt_alloc_id(mnt); |
115 | if (err) { | 115 | if (err) |
116 | kmem_cache_free(mnt_cache, mnt); | 116 | goto out_free_cache; |
117 | return NULL; | 117 | |
118 | if (name) { | ||
119 | mnt->mnt_devname = kstrdup(name, GFP_KERNEL); | ||
120 | if (!mnt->mnt_devname) | ||
121 | goto out_free_id; | ||
118 | } | 122 | } |
119 | 123 | ||
120 | atomic_set(&mnt->mnt_count, 1); | 124 | atomic_set(&mnt->mnt_count, 1); |
@@ -127,16 +131,14 @@ struct vfsmount *alloc_vfsmnt(const char *name) | |||
127 | INIT_LIST_HEAD(&mnt->mnt_slave_list); | 131 | INIT_LIST_HEAD(&mnt->mnt_slave_list); |
128 | INIT_LIST_HEAD(&mnt->mnt_slave); | 132 | INIT_LIST_HEAD(&mnt->mnt_slave); |
129 | atomic_set(&mnt->__mnt_writers, 0); | 133 | atomic_set(&mnt->__mnt_writers, 0); |
130 | if (name) { | ||
131 | int size = strlen(name) + 1; | ||
132 | char *newname = kmalloc(size, GFP_KERNEL); | ||
133 | if (newname) { | ||
134 | memcpy(newname, name, size); | ||
135 | mnt->mnt_devname = newname; | ||
136 | } | ||
137 | } | ||
138 | } | 134 | } |
139 | return mnt; | 135 | return mnt; |
136 | |||
137 | out_free_id: | ||
138 | mnt_free_id(mnt); | ||
139 | out_free_cache: | ||
140 | kmem_cache_free(mnt_cache, mnt); | ||
141 | return NULL; | ||
140 | } | 142 | } |
141 | 143 | ||
142 | /* | 144 | /* |
@@ -309,10 +311,9 @@ static void handle_write_count_underflow(struct vfsmount *mnt) | |||
309 | */ | 311 | */ |
310 | if ((atomic_read(&mnt->__mnt_writers) < 0) && | 312 | if ((atomic_read(&mnt->__mnt_writers) < 0) && |
311 | !(mnt->mnt_flags & MNT_IMBALANCED_WRITE_COUNT)) { | 313 | !(mnt->mnt_flags & MNT_IMBALANCED_WRITE_COUNT)) { |
312 | printk(KERN_DEBUG "leak detected on mount(%p) writers " | 314 | WARN(1, KERN_DEBUG "leak detected on mount(%p) writers " |
313 | "count: %d\n", | 315 | "count: %d\n", |
314 | mnt, atomic_read(&mnt->__mnt_writers)); | 316 | mnt, atomic_read(&mnt->__mnt_writers)); |
315 | WARN_ON(1); | ||
316 | /* use the flag to keep the dmesg spam down */ | 317 | /* use the flag to keep the dmesg spam down */ |
317 | mnt->mnt_flags |= MNT_IMBALANCED_WRITE_COUNT; | 318 | mnt->mnt_flags |= MNT_IMBALANCED_WRITE_COUNT; |
318 | } | 319 | } |
@@ -1129,27 +1130,27 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
1129 | 1130 | ||
1130 | asmlinkage long sys_umount(char __user * name, int flags) | 1131 | asmlinkage long sys_umount(char __user * name, int flags) |
1131 | { | 1132 | { |
1132 | struct nameidata nd; | 1133 | struct path path; |
1133 | int retval; | 1134 | int retval; |
1134 | 1135 | ||
1135 | retval = __user_walk(name, LOOKUP_FOLLOW, &nd); | 1136 | retval = user_path(name, &path); |
1136 | if (retval) | 1137 | if (retval) |
1137 | goto out; | 1138 | goto out; |
1138 | retval = -EINVAL; | 1139 | retval = -EINVAL; |
1139 | if (nd.path.dentry != nd.path.mnt->mnt_root) | 1140 | if (path.dentry != path.mnt->mnt_root) |
1140 | goto dput_and_out; | 1141 | goto dput_and_out; |
1141 | if (!check_mnt(nd.path.mnt)) | 1142 | if (!check_mnt(path.mnt)) |
1142 | goto dput_and_out; | 1143 | goto dput_and_out; |
1143 | 1144 | ||
1144 | retval = -EPERM; | 1145 | retval = -EPERM; |
1145 | if (!capable(CAP_SYS_ADMIN)) | 1146 | if (!capable(CAP_SYS_ADMIN)) |
1146 | goto dput_and_out; | 1147 | goto dput_and_out; |
1147 | 1148 | ||
1148 | retval = do_umount(nd.path.mnt, flags); | 1149 | retval = do_umount(path.mnt, flags); |
1149 | dput_and_out: | 1150 | dput_and_out: |
1150 | /* we mustn't call path_put() as that would clear mnt_expiry_mark */ | 1151 | /* we mustn't call path_put() as that would clear mnt_expiry_mark */ |
1151 | dput(nd.path.dentry); | 1152 | dput(path.dentry); |
1152 | mntput_no_expire(nd.path.mnt); | 1153 | mntput_no_expire(path.mnt); |
1153 | out: | 1154 | out: |
1154 | return retval; | 1155 | return retval; |
1155 | } | 1156 | } |
@@ -1973,7 +1974,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
1973 | struct fs_struct *fs) | 1974 | struct fs_struct *fs) |
1974 | { | 1975 | { |
1975 | struct mnt_namespace *new_ns; | 1976 | struct mnt_namespace *new_ns; |
1976 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; | 1977 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; |
1977 | struct vfsmount *p, *q; | 1978 | struct vfsmount *p, *q; |
1978 | 1979 | ||
1979 | new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); | 1980 | new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); |
@@ -2016,10 +2017,6 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2016 | pwdmnt = p; | 2017 | pwdmnt = p; |
2017 | fs->pwd.mnt = mntget(q); | 2018 | fs->pwd.mnt = mntget(q); |
2018 | } | 2019 | } |
2019 | if (p == fs->altroot.mnt) { | ||
2020 | altrootmnt = p; | ||
2021 | fs->altroot.mnt = mntget(q); | ||
2022 | } | ||
2023 | } | 2020 | } |
2024 | p = next_mnt(p, mnt_ns->root); | 2021 | p = next_mnt(p, mnt_ns->root); |
2025 | q = next_mnt(q, new_ns->root); | 2022 | q = next_mnt(q, new_ns->root); |
@@ -2030,8 +2027,6 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2030 | mntput(rootmnt); | 2027 | mntput(rootmnt); |
2031 | if (pwdmnt) | 2028 | if (pwdmnt) |
2032 | mntput(pwdmnt); | 2029 | mntput(pwdmnt); |
2033 | if (altrootmnt) | ||
2034 | mntput(altrootmnt); | ||
2035 | 2030 | ||
2036 | return new_ns; | 2031 | return new_ns; |
2037 | } | 2032 | } |
@@ -2184,28 +2179,26 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
2184 | const char __user * put_old) | 2179 | const char __user * put_old) |
2185 | { | 2180 | { |
2186 | struct vfsmount *tmp; | 2181 | struct vfsmount *tmp; |
2187 | struct nameidata new_nd, old_nd; | 2182 | struct path new, old, parent_path, root_parent, root; |
2188 | struct path parent_path, root_parent, root; | ||
2189 | int error; | 2183 | int error; |
2190 | 2184 | ||
2191 | if (!capable(CAP_SYS_ADMIN)) | 2185 | if (!capable(CAP_SYS_ADMIN)) |
2192 | return -EPERM; | 2186 | return -EPERM; |
2193 | 2187 | ||
2194 | error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, | 2188 | error = user_path_dir(new_root, &new); |
2195 | &new_nd); | ||
2196 | if (error) | 2189 | if (error) |
2197 | goto out0; | 2190 | goto out0; |
2198 | error = -EINVAL; | 2191 | error = -EINVAL; |
2199 | if (!check_mnt(new_nd.path.mnt)) | 2192 | if (!check_mnt(new.mnt)) |
2200 | goto out1; | 2193 | goto out1; |
2201 | 2194 | ||
2202 | error = __user_walk(put_old, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old_nd); | 2195 | error = user_path_dir(put_old, &old); |
2203 | if (error) | 2196 | if (error) |
2204 | goto out1; | 2197 | goto out1; |
2205 | 2198 | ||
2206 | error = security_sb_pivotroot(&old_nd.path, &new_nd.path); | 2199 | error = security_sb_pivotroot(&old, &new); |
2207 | if (error) { | 2200 | if (error) { |
2208 | path_put(&old_nd.path); | 2201 | path_put(&old); |
2209 | goto out1; | 2202 | goto out1; |
2210 | } | 2203 | } |
2211 | 2204 | ||
@@ -2214,69 +2207,69 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
2214 | path_get(¤t->fs->root); | 2207 | path_get(¤t->fs->root); |
2215 | read_unlock(¤t->fs->lock); | 2208 | read_unlock(¤t->fs->lock); |
2216 | down_write(&namespace_sem); | 2209 | down_write(&namespace_sem); |
2217 | mutex_lock(&old_nd.path.dentry->d_inode->i_mutex); | 2210 | mutex_lock(&old.dentry->d_inode->i_mutex); |
2218 | error = -EINVAL; | 2211 | error = -EINVAL; |
2219 | if (IS_MNT_SHARED(old_nd.path.mnt) || | 2212 | if (IS_MNT_SHARED(old.mnt) || |
2220 | IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) || | 2213 | IS_MNT_SHARED(new.mnt->mnt_parent) || |
2221 | IS_MNT_SHARED(root.mnt->mnt_parent)) | 2214 | IS_MNT_SHARED(root.mnt->mnt_parent)) |
2222 | goto out2; | 2215 | goto out2; |
2223 | if (!check_mnt(root.mnt)) | 2216 | if (!check_mnt(root.mnt)) |
2224 | goto out2; | 2217 | goto out2; |
2225 | error = -ENOENT; | 2218 | error = -ENOENT; |
2226 | if (IS_DEADDIR(new_nd.path.dentry->d_inode)) | 2219 | if (IS_DEADDIR(new.dentry->d_inode)) |
2227 | goto out2; | 2220 | goto out2; |
2228 | if (d_unhashed(new_nd.path.dentry) && !IS_ROOT(new_nd.path.dentry)) | 2221 | if (d_unhashed(new.dentry) && !IS_ROOT(new.dentry)) |
2229 | goto out2; | 2222 | goto out2; |
2230 | if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry)) | 2223 | if (d_unhashed(old.dentry) && !IS_ROOT(old.dentry)) |
2231 | goto out2; | 2224 | goto out2; |
2232 | error = -EBUSY; | 2225 | error = -EBUSY; |
2233 | if (new_nd.path.mnt == root.mnt || | 2226 | if (new.mnt == root.mnt || |
2234 | old_nd.path.mnt == root.mnt) | 2227 | old.mnt == root.mnt) |
2235 | goto out2; /* loop, on the same file system */ | 2228 | goto out2; /* loop, on the same file system */ |
2236 | error = -EINVAL; | 2229 | error = -EINVAL; |
2237 | if (root.mnt->mnt_root != root.dentry) | 2230 | if (root.mnt->mnt_root != root.dentry) |
2238 | goto out2; /* not a mountpoint */ | 2231 | goto out2; /* not a mountpoint */ |
2239 | if (root.mnt->mnt_parent == root.mnt) | 2232 | if (root.mnt->mnt_parent == root.mnt) |
2240 | goto out2; /* not attached */ | 2233 | goto out2; /* not attached */ |
2241 | if (new_nd.path.mnt->mnt_root != new_nd.path.dentry) | 2234 | if (new.mnt->mnt_root != new.dentry) |
2242 | goto out2; /* not a mountpoint */ | 2235 | goto out2; /* not a mountpoint */ |
2243 | if (new_nd.path.mnt->mnt_parent == new_nd.path.mnt) | 2236 | if (new.mnt->mnt_parent == new.mnt) |
2244 | goto out2; /* not attached */ | 2237 | goto out2; /* not attached */ |
2245 | /* make sure we can reach put_old from new_root */ | 2238 | /* make sure we can reach put_old from new_root */ |
2246 | tmp = old_nd.path.mnt; | 2239 | tmp = old.mnt; |
2247 | spin_lock(&vfsmount_lock); | 2240 | spin_lock(&vfsmount_lock); |
2248 | if (tmp != new_nd.path.mnt) { | 2241 | if (tmp != new.mnt) { |
2249 | for (;;) { | 2242 | for (;;) { |
2250 | if (tmp->mnt_parent == tmp) | 2243 | if (tmp->mnt_parent == tmp) |
2251 | goto out3; /* already mounted on put_old */ | 2244 | goto out3; /* already mounted on put_old */ |
2252 | if (tmp->mnt_parent == new_nd.path.mnt) | 2245 | if (tmp->mnt_parent == new.mnt) |
2253 | break; | 2246 | break; |
2254 | tmp = tmp->mnt_parent; | 2247 | tmp = tmp->mnt_parent; |
2255 | } | 2248 | } |
2256 | if (!is_subdir(tmp->mnt_mountpoint, new_nd.path.dentry)) | 2249 | if (!is_subdir(tmp->mnt_mountpoint, new.dentry)) |
2257 | goto out3; | 2250 | goto out3; |
2258 | } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) | 2251 | } else if (!is_subdir(old.dentry, new.dentry)) |
2259 | goto out3; | 2252 | goto out3; |
2260 | detach_mnt(new_nd.path.mnt, &parent_path); | 2253 | detach_mnt(new.mnt, &parent_path); |
2261 | detach_mnt(root.mnt, &root_parent); | 2254 | detach_mnt(root.mnt, &root_parent); |
2262 | /* mount old root on put_old */ | 2255 | /* mount old root on put_old */ |
2263 | attach_mnt(root.mnt, &old_nd.path); | 2256 | attach_mnt(root.mnt, &old); |
2264 | /* mount new_root on / */ | 2257 | /* mount new_root on / */ |
2265 | attach_mnt(new_nd.path.mnt, &root_parent); | 2258 | attach_mnt(new.mnt, &root_parent); |
2266 | touch_mnt_namespace(current->nsproxy->mnt_ns); | 2259 | touch_mnt_namespace(current->nsproxy->mnt_ns); |
2267 | spin_unlock(&vfsmount_lock); | 2260 | spin_unlock(&vfsmount_lock); |
2268 | chroot_fs_refs(&root, &new_nd.path); | 2261 | chroot_fs_refs(&root, &new); |
2269 | security_sb_post_pivotroot(&root, &new_nd.path); | 2262 | security_sb_post_pivotroot(&root, &new); |
2270 | error = 0; | 2263 | error = 0; |
2271 | path_put(&root_parent); | 2264 | path_put(&root_parent); |
2272 | path_put(&parent_path); | 2265 | path_put(&parent_path); |
2273 | out2: | 2266 | out2: |
2274 | mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); | 2267 | mutex_unlock(&old.dentry->d_inode->i_mutex); |
2275 | up_write(&namespace_sem); | 2268 | up_write(&namespace_sem); |
2276 | path_put(&root); | 2269 | path_put(&root); |
2277 | path_put(&old_nd.path); | 2270 | path_put(&old); |
2278 | out1: | 2271 | out1: |
2279 | path_put(&new_nd.path); | 2272 | path_put(&new); |
2280 | out0: | 2273 | out0: |
2281 | return error; | 2274 | return error; |
2282 | out3: | 2275 | out3: |