diff options
Diffstat (limited to 'fs/namespace.c')
| -rw-r--r-- | fs/namespace.c | 125 |
1 files changed, 59 insertions, 66 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 4f6f7635b59c..6e283c93b50d 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 | } |
| @@ -1666,31 +1667,31 @@ static noinline int do_new_mount(struct nameidata *nd, char *type, int flags, | |||
| 1666 | if (IS_ERR(mnt)) | 1667 | if (IS_ERR(mnt)) |
| 1667 | return PTR_ERR(mnt); | 1668 | return PTR_ERR(mnt); |
| 1668 | 1669 | ||
| 1669 | return do_add_mount(mnt, nd, mnt_flags, NULL); | 1670 | return do_add_mount(mnt, &nd->path, mnt_flags, NULL); |
| 1670 | } | 1671 | } |
| 1671 | 1672 | ||
| 1672 | /* | 1673 | /* |
| 1673 | * add a mount into a namespace's mount tree | 1674 | * add a mount into a namespace's mount tree |
| 1674 | * - provide the option of adding the new mount to an expiration list | 1675 | * - provide the option of adding the new mount to an expiration list |
| 1675 | */ | 1676 | */ |
| 1676 | int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, | 1677 | int do_add_mount(struct vfsmount *newmnt, struct path *path, |
| 1677 | int mnt_flags, struct list_head *fslist) | 1678 | int mnt_flags, struct list_head *fslist) |
| 1678 | { | 1679 | { |
| 1679 | int err; | 1680 | int err; |
| 1680 | 1681 | ||
| 1681 | down_write(&namespace_sem); | 1682 | down_write(&namespace_sem); |
| 1682 | /* Something was mounted here while we slept */ | 1683 | /* Something was mounted here while we slept */ |
| 1683 | while (d_mountpoint(nd->path.dentry) && | 1684 | while (d_mountpoint(path->dentry) && |
| 1684 | follow_down(&nd->path.mnt, &nd->path.dentry)) | 1685 | follow_down(&path->mnt, &path->dentry)) |
| 1685 | ; | 1686 | ; |
| 1686 | err = -EINVAL; | 1687 | err = -EINVAL; |
| 1687 | if (!check_mnt(nd->path.mnt)) | 1688 | if (!check_mnt(path->mnt)) |
| 1688 | goto unlock; | 1689 | goto unlock; |
| 1689 | 1690 | ||
| 1690 | /* Refuse the same filesystem on the same mount point */ | 1691 | /* Refuse the same filesystem on the same mount point */ |
| 1691 | err = -EBUSY; | 1692 | err = -EBUSY; |
| 1692 | if (nd->path.mnt->mnt_sb == newmnt->mnt_sb && | 1693 | if (path->mnt->mnt_sb == newmnt->mnt_sb && |
| 1693 | nd->path.mnt->mnt_root == nd->path.dentry) | 1694 | path->mnt->mnt_root == path->dentry) |
| 1694 | goto unlock; | 1695 | goto unlock; |
| 1695 | 1696 | ||
| 1696 | err = -EINVAL; | 1697 | err = -EINVAL; |
| @@ -1698,7 +1699,7 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, | |||
| 1698 | goto unlock; | 1699 | goto unlock; |
| 1699 | 1700 | ||
| 1700 | newmnt->mnt_flags = mnt_flags; | 1701 | newmnt->mnt_flags = mnt_flags; |
| 1701 | if ((err = graft_tree(newmnt, &nd->path))) | 1702 | if ((err = graft_tree(newmnt, path))) |
| 1702 | goto unlock; | 1703 | goto unlock; |
| 1703 | 1704 | ||
| 1704 | if (fslist) /* add to the specified expiration list */ | 1705 | if (fslist) /* add to the specified expiration list */ |
| @@ -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: |
