diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 106 |
1 files changed, 50 insertions, 56 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index f30b11e2240e..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 | /* |
@@ -1128,27 +1130,27 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
1128 | 1130 | ||
1129 | asmlinkage long sys_umount(char __user * name, int flags) | 1131 | asmlinkage long sys_umount(char __user * name, int flags) |
1130 | { | 1132 | { |
1131 | struct nameidata nd; | 1133 | struct path path; |
1132 | int retval; | 1134 | int retval; |
1133 | 1135 | ||
1134 | retval = __user_walk(name, LOOKUP_FOLLOW, &nd); | 1136 | retval = user_path(name, &path); |
1135 | if (retval) | 1137 | if (retval) |
1136 | goto out; | 1138 | goto out; |
1137 | retval = -EINVAL; | 1139 | retval = -EINVAL; |
1138 | if (nd.path.dentry != nd.path.mnt->mnt_root) | 1140 | if (path.dentry != path.mnt->mnt_root) |
1139 | goto dput_and_out; | 1141 | goto dput_and_out; |
1140 | if (!check_mnt(nd.path.mnt)) | 1142 | if (!check_mnt(path.mnt)) |
1141 | goto dput_and_out; | 1143 | goto dput_and_out; |
1142 | 1144 | ||
1143 | retval = -EPERM; | 1145 | retval = -EPERM; |
1144 | if (!capable(CAP_SYS_ADMIN)) | 1146 | if (!capable(CAP_SYS_ADMIN)) |
1145 | goto dput_and_out; | 1147 | goto dput_and_out; |
1146 | 1148 | ||
1147 | retval = do_umount(nd.path.mnt, flags); | 1149 | retval = do_umount(path.mnt, flags); |
1148 | dput_and_out: | 1150 | dput_and_out: |
1149 | /* 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 */ |
1150 | dput(nd.path.dentry); | 1152 | dput(path.dentry); |
1151 | mntput_no_expire(nd.path.mnt); | 1153 | mntput_no_expire(path.mnt); |
1152 | out: | 1154 | out: |
1153 | return retval; | 1155 | return retval; |
1154 | } | 1156 | } |
@@ -1972,7 +1974,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
1972 | struct fs_struct *fs) | 1974 | struct fs_struct *fs) |
1973 | { | 1975 | { |
1974 | struct mnt_namespace *new_ns; | 1976 | struct mnt_namespace *new_ns; |
1975 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; | 1977 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; |
1976 | struct vfsmount *p, *q; | 1978 | struct vfsmount *p, *q; |
1977 | 1979 | ||
1978 | new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); | 1980 | new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); |
@@ -2015,10 +2017,6 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2015 | pwdmnt = p; | 2017 | pwdmnt = p; |
2016 | fs->pwd.mnt = mntget(q); | 2018 | fs->pwd.mnt = mntget(q); |
2017 | } | 2019 | } |
2018 | if (p == fs->altroot.mnt) { | ||
2019 | altrootmnt = p; | ||
2020 | fs->altroot.mnt = mntget(q); | ||
2021 | } | ||
2022 | } | 2020 | } |
2023 | p = next_mnt(p, mnt_ns->root); | 2021 | p = next_mnt(p, mnt_ns->root); |
2024 | q = next_mnt(q, new_ns->root); | 2022 | q = next_mnt(q, new_ns->root); |
@@ -2029,8 +2027,6 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2029 | mntput(rootmnt); | 2027 | mntput(rootmnt); |
2030 | if (pwdmnt) | 2028 | if (pwdmnt) |
2031 | mntput(pwdmnt); | 2029 | mntput(pwdmnt); |
2032 | if (altrootmnt) | ||
2033 | mntput(altrootmnt); | ||
2034 | 2030 | ||
2035 | return new_ns; | 2031 | return new_ns; |
2036 | } | 2032 | } |
@@ -2183,28 +2179,26 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
2183 | const char __user * put_old) | 2179 | const char __user * put_old) |
2184 | { | 2180 | { |
2185 | struct vfsmount *tmp; | 2181 | struct vfsmount *tmp; |
2186 | struct nameidata new_nd, old_nd; | 2182 | struct path new, old, parent_path, root_parent, root; |
2187 | struct path parent_path, root_parent, root; | ||
2188 | int error; | 2183 | int error; |
2189 | 2184 | ||
2190 | if (!capable(CAP_SYS_ADMIN)) | 2185 | if (!capable(CAP_SYS_ADMIN)) |
2191 | return -EPERM; | 2186 | return -EPERM; |
2192 | 2187 | ||
2193 | error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, | 2188 | error = user_path_dir(new_root, &new); |
2194 | &new_nd); | ||
2195 | if (error) | 2189 | if (error) |
2196 | goto out0; | 2190 | goto out0; |
2197 | error = -EINVAL; | 2191 | error = -EINVAL; |
2198 | if (!check_mnt(new_nd.path.mnt)) | 2192 | if (!check_mnt(new.mnt)) |
2199 | goto out1; | 2193 | goto out1; |
2200 | 2194 | ||
2201 | error = __user_walk(put_old, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old_nd); | 2195 | error = user_path_dir(put_old, &old); |
2202 | if (error) | 2196 | if (error) |
2203 | goto out1; | 2197 | goto out1; |
2204 | 2198 | ||
2205 | error = security_sb_pivotroot(&old_nd.path, &new_nd.path); | 2199 | error = security_sb_pivotroot(&old, &new); |
2206 | if (error) { | 2200 | if (error) { |
2207 | path_put(&old_nd.path); | 2201 | path_put(&old); |
2208 | goto out1; | 2202 | goto out1; |
2209 | } | 2203 | } |
2210 | 2204 | ||
@@ -2213,69 +2207,69 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
2213 | path_get(¤t->fs->root); | 2207 | path_get(¤t->fs->root); |
2214 | read_unlock(¤t->fs->lock); | 2208 | read_unlock(¤t->fs->lock); |
2215 | down_write(&namespace_sem); | 2209 | down_write(&namespace_sem); |
2216 | mutex_lock(&old_nd.path.dentry->d_inode->i_mutex); | 2210 | mutex_lock(&old.dentry->d_inode->i_mutex); |
2217 | error = -EINVAL; | 2211 | error = -EINVAL; |
2218 | if (IS_MNT_SHARED(old_nd.path.mnt) || | 2212 | if (IS_MNT_SHARED(old.mnt) || |
2219 | IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) || | 2213 | IS_MNT_SHARED(new.mnt->mnt_parent) || |
2220 | IS_MNT_SHARED(root.mnt->mnt_parent)) | 2214 | IS_MNT_SHARED(root.mnt->mnt_parent)) |
2221 | goto out2; | 2215 | goto out2; |
2222 | if (!check_mnt(root.mnt)) | 2216 | if (!check_mnt(root.mnt)) |
2223 | goto out2; | 2217 | goto out2; |
2224 | error = -ENOENT; | 2218 | error = -ENOENT; |
2225 | if (IS_DEADDIR(new_nd.path.dentry->d_inode)) | 2219 | if (IS_DEADDIR(new.dentry->d_inode)) |
2226 | goto out2; | 2220 | goto out2; |
2227 | if (d_unhashed(new_nd.path.dentry) && !IS_ROOT(new_nd.path.dentry)) | 2221 | if (d_unhashed(new.dentry) && !IS_ROOT(new.dentry)) |
2228 | goto out2; | 2222 | goto out2; |
2229 | if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry)) | 2223 | if (d_unhashed(old.dentry) && !IS_ROOT(old.dentry)) |
2230 | goto out2; | 2224 | goto out2; |
2231 | error = -EBUSY; | 2225 | error = -EBUSY; |
2232 | if (new_nd.path.mnt == root.mnt || | 2226 | if (new.mnt == root.mnt || |
2233 | old_nd.path.mnt == root.mnt) | 2227 | old.mnt == root.mnt) |
2234 | goto out2; /* loop, on the same file system */ | 2228 | goto out2; /* loop, on the same file system */ |
2235 | error = -EINVAL; | 2229 | error = -EINVAL; |
2236 | if (root.mnt->mnt_root != root.dentry) | 2230 | if (root.mnt->mnt_root != root.dentry) |
2237 | goto out2; /* not a mountpoint */ | 2231 | goto out2; /* not a mountpoint */ |
2238 | if (root.mnt->mnt_parent == root.mnt) | 2232 | if (root.mnt->mnt_parent == root.mnt) |
2239 | goto out2; /* not attached */ | 2233 | goto out2; /* not attached */ |
2240 | if (new_nd.path.mnt->mnt_root != new_nd.path.dentry) | 2234 | if (new.mnt->mnt_root != new.dentry) |
2241 | goto out2; /* not a mountpoint */ | 2235 | goto out2; /* not a mountpoint */ |
2242 | if (new_nd.path.mnt->mnt_parent == new_nd.path.mnt) | 2236 | if (new.mnt->mnt_parent == new.mnt) |
2243 | goto out2; /* not attached */ | 2237 | goto out2; /* not attached */ |
2244 | /* make sure we can reach put_old from new_root */ | 2238 | /* make sure we can reach put_old from new_root */ |
2245 | tmp = old_nd.path.mnt; | 2239 | tmp = old.mnt; |
2246 | spin_lock(&vfsmount_lock); | 2240 | spin_lock(&vfsmount_lock); |
2247 | if (tmp != new_nd.path.mnt) { | 2241 | if (tmp != new.mnt) { |
2248 | for (;;) { | 2242 | for (;;) { |
2249 | if (tmp->mnt_parent == tmp) | 2243 | if (tmp->mnt_parent == tmp) |
2250 | goto out3; /* already mounted on put_old */ | 2244 | goto out3; /* already mounted on put_old */ |
2251 | if (tmp->mnt_parent == new_nd.path.mnt) | 2245 | if (tmp->mnt_parent == new.mnt) |
2252 | break; | 2246 | break; |
2253 | tmp = tmp->mnt_parent; | 2247 | tmp = tmp->mnt_parent; |
2254 | } | 2248 | } |
2255 | if (!is_subdir(tmp->mnt_mountpoint, new_nd.path.dentry)) | 2249 | if (!is_subdir(tmp->mnt_mountpoint, new.dentry)) |
2256 | goto out3; | 2250 | goto out3; |
2257 | } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) | 2251 | } else if (!is_subdir(old.dentry, new.dentry)) |
2258 | goto out3; | 2252 | goto out3; |
2259 | detach_mnt(new_nd.path.mnt, &parent_path); | 2253 | detach_mnt(new.mnt, &parent_path); |
2260 | detach_mnt(root.mnt, &root_parent); | 2254 | detach_mnt(root.mnt, &root_parent); |
2261 | /* mount old root on put_old */ | 2255 | /* mount old root on put_old */ |
2262 | attach_mnt(root.mnt, &old_nd.path); | 2256 | attach_mnt(root.mnt, &old); |
2263 | /* mount new_root on / */ | 2257 | /* mount new_root on / */ |
2264 | attach_mnt(new_nd.path.mnt, &root_parent); | 2258 | attach_mnt(new.mnt, &root_parent); |
2265 | touch_mnt_namespace(current->nsproxy->mnt_ns); | 2259 | touch_mnt_namespace(current->nsproxy->mnt_ns); |
2266 | spin_unlock(&vfsmount_lock); | 2260 | spin_unlock(&vfsmount_lock); |
2267 | chroot_fs_refs(&root, &new_nd.path); | 2261 | chroot_fs_refs(&root, &new); |
2268 | security_sb_post_pivotroot(&root, &new_nd.path); | 2262 | security_sb_post_pivotroot(&root, &new); |
2269 | error = 0; | 2263 | error = 0; |
2270 | path_put(&root_parent); | 2264 | path_put(&root_parent); |
2271 | path_put(&parent_path); | 2265 | path_put(&parent_path); |
2272 | out2: | 2266 | out2: |
2273 | mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); | 2267 | mutex_unlock(&old.dentry->d_inode->i_mutex); |
2274 | up_write(&namespace_sem); | 2268 | up_write(&namespace_sem); |
2275 | path_put(&root); | 2269 | path_put(&root); |
2276 | path_put(&old_nd.path); | 2270 | path_put(&old); |
2277 | out1: | 2271 | out1: |
2278 | path_put(&new_nd.path); | 2272 | path_put(&new); |
2279 | out0: | 2273 | out0: |
2280 | return error; | 2274 | return error; |
2281 | out3: | 2275 | out3: |