diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2008-07-22 09:59:21 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-07-26 20:53:34 -0400 |
commit | 2d8f30380ab8c706f4e0a8f1aaa22b5886e9ac8a (patch) | |
tree | b798097fd831eab39f35c8c2e5a8ccfd7a850ef5 /fs/namespace.c | |
parent | 256984a83880ff7ac78055cb87baea48137f0b77 (diff) |
[PATCH] sanitize __user_walk_fd() et.al.
* do not pass nameidata; struct path is all the callers want.
* switch to new helpers:
user_path_at(dfd, pathname, flags, &path)
user_path(pathname, &path)
user_lpath(pathname, &path)
user_path_dir(pathname, &path) (fail if not a directory)
The last 3 are trivial macro wrappers for the first one.
* remove nameidata in callers.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 74 |
1 files changed, 36 insertions, 38 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 26380f599534..411728c0c8bb 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1130,27 +1130,27 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
1130 | 1130 | ||
1131 | asmlinkage long sys_umount(char __user * name, int flags) | 1131 | asmlinkage long sys_umount(char __user * name, int flags) |
1132 | { | 1132 | { |
1133 | struct nameidata nd; | 1133 | struct path path; |
1134 | int retval; | 1134 | int retval; |
1135 | 1135 | ||
1136 | retval = __user_walk(name, LOOKUP_FOLLOW, &nd); | 1136 | retval = user_path(name, &path); |
1137 | if (retval) | 1137 | if (retval) |
1138 | goto out; | 1138 | goto out; |
1139 | retval = -EINVAL; | 1139 | retval = -EINVAL; |
1140 | if (nd.path.dentry != nd.path.mnt->mnt_root) | 1140 | if (path.dentry != path.mnt->mnt_root) |
1141 | goto dput_and_out; | 1141 | goto dput_and_out; |
1142 | if (!check_mnt(nd.path.mnt)) | 1142 | if (!check_mnt(path.mnt)) |
1143 | goto dput_and_out; | 1143 | goto dput_and_out; |
1144 | 1144 | ||
1145 | retval = -EPERM; | 1145 | retval = -EPERM; |
1146 | if (!capable(CAP_SYS_ADMIN)) | 1146 | if (!capable(CAP_SYS_ADMIN)) |
1147 | goto dput_and_out; | 1147 | goto dput_and_out; |
1148 | 1148 | ||
1149 | retval = do_umount(nd.path.mnt, flags); | 1149 | retval = do_umount(path.mnt, flags); |
1150 | dput_and_out: | 1150 | dput_and_out: |
1151 | /* 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 */ |
1152 | dput(nd.path.dentry); | 1152 | dput(path.dentry); |
1153 | mntput_no_expire(nd.path.mnt); | 1153 | mntput_no_expire(path.mnt); |
1154 | out: | 1154 | out: |
1155 | return retval; | 1155 | return retval; |
1156 | } | 1156 | } |
@@ -2179,28 +2179,26 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
2179 | const char __user * put_old) | 2179 | const char __user * put_old) |
2180 | { | 2180 | { |
2181 | struct vfsmount *tmp; | 2181 | struct vfsmount *tmp; |
2182 | struct nameidata new_nd, old_nd; | 2182 | struct path new, old, parent_path, root_parent, root; |
2183 | struct path parent_path, root_parent, root; | ||
2184 | int error; | 2183 | int error; |
2185 | 2184 | ||
2186 | if (!capable(CAP_SYS_ADMIN)) | 2185 | if (!capable(CAP_SYS_ADMIN)) |
2187 | return -EPERM; | 2186 | return -EPERM; |
2188 | 2187 | ||
2189 | error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, | 2188 | error = user_path_dir(new_root, &new); |
2190 | &new_nd); | ||
2191 | if (error) | 2189 | if (error) |
2192 | goto out0; | 2190 | goto out0; |
2193 | error = -EINVAL; | 2191 | error = -EINVAL; |
2194 | if (!check_mnt(new_nd.path.mnt)) | 2192 | if (!check_mnt(new.mnt)) |
2195 | goto out1; | 2193 | goto out1; |
2196 | 2194 | ||
2197 | error = __user_walk(put_old, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old_nd); | 2195 | error = user_path_dir(put_old, &old); |
2198 | if (error) | 2196 | if (error) |
2199 | goto out1; | 2197 | goto out1; |
2200 | 2198 | ||
2201 | error = security_sb_pivotroot(&old_nd.path, &new_nd.path); | 2199 | error = security_sb_pivotroot(&old, &new); |
2202 | if (error) { | 2200 | if (error) { |
2203 | path_put(&old_nd.path); | 2201 | path_put(&old); |
2204 | goto out1; | 2202 | goto out1; |
2205 | } | 2203 | } |
2206 | 2204 | ||
@@ -2209,69 +2207,69 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
2209 | path_get(¤t->fs->root); | 2207 | path_get(¤t->fs->root); |
2210 | read_unlock(¤t->fs->lock); | 2208 | read_unlock(¤t->fs->lock); |
2211 | down_write(&namespace_sem); | 2209 | down_write(&namespace_sem); |
2212 | mutex_lock(&old_nd.path.dentry->d_inode->i_mutex); | 2210 | mutex_lock(&old.dentry->d_inode->i_mutex); |
2213 | error = -EINVAL; | 2211 | error = -EINVAL; |
2214 | if (IS_MNT_SHARED(old_nd.path.mnt) || | 2212 | if (IS_MNT_SHARED(old.mnt) || |
2215 | IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) || | 2213 | IS_MNT_SHARED(new.mnt->mnt_parent) || |
2216 | IS_MNT_SHARED(root.mnt->mnt_parent)) | 2214 | IS_MNT_SHARED(root.mnt->mnt_parent)) |
2217 | goto out2; | 2215 | goto out2; |
2218 | if (!check_mnt(root.mnt)) | 2216 | if (!check_mnt(root.mnt)) |
2219 | goto out2; | 2217 | goto out2; |
2220 | error = -ENOENT; | 2218 | error = -ENOENT; |
2221 | if (IS_DEADDIR(new_nd.path.dentry->d_inode)) | 2219 | if (IS_DEADDIR(new.dentry->d_inode)) |
2222 | goto out2; | 2220 | goto out2; |
2223 | if (d_unhashed(new_nd.path.dentry) && !IS_ROOT(new_nd.path.dentry)) | 2221 | if (d_unhashed(new.dentry) && !IS_ROOT(new.dentry)) |
2224 | goto out2; | 2222 | goto out2; |
2225 | if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry)) | 2223 | if (d_unhashed(old.dentry) && !IS_ROOT(old.dentry)) |
2226 | goto out2; | 2224 | goto out2; |
2227 | error = -EBUSY; | 2225 | error = -EBUSY; |
2228 | if (new_nd.path.mnt == root.mnt || | 2226 | if (new.mnt == root.mnt || |
2229 | old_nd.path.mnt == root.mnt) | 2227 | old.mnt == root.mnt) |
2230 | goto out2; /* loop, on the same file system */ | 2228 | goto out2; /* loop, on the same file system */ |
2231 | error = -EINVAL; | 2229 | error = -EINVAL; |
2232 | if (root.mnt->mnt_root != root.dentry) | 2230 | if (root.mnt->mnt_root != root.dentry) |
2233 | goto out2; /* not a mountpoint */ | 2231 | goto out2; /* not a mountpoint */ |
2234 | if (root.mnt->mnt_parent == root.mnt) | 2232 | if (root.mnt->mnt_parent == root.mnt) |
2235 | goto out2; /* not attached */ | 2233 | goto out2; /* not attached */ |
2236 | if (new_nd.path.mnt->mnt_root != new_nd.path.dentry) | 2234 | if (new.mnt->mnt_root != new.dentry) |
2237 | goto out2; /* not a mountpoint */ | 2235 | goto out2; /* not a mountpoint */ |
2238 | if (new_nd.path.mnt->mnt_parent == new_nd.path.mnt) | 2236 | if (new.mnt->mnt_parent == new.mnt) |
2239 | goto out2; /* not attached */ | 2237 | goto out2; /* not attached */ |
2240 | /* make sure we can reach put_old from new_root */ | 2238 | /* make sure we can reach put_old from new_root */ |
2241 | tmp = old_nd.path.mnt; | 2239 | tmp = old.mnt; |
2242 | spin_lock(&vfsmount_lock); | 2240 | spin_lock(&vfsmount_lock); |
2243 | if (tmp != new_nd.path.mnt) { | 2241 | if (tmp != new.mnt) { |
2244 | for (;;) { | 2242 | for (;;) { |
2245 | if (tmp->mnt_parent == tmp) | 2243 | if (tmp->mnt_parent == tmp) |
2246 | goto out3; /* already mounted on put_old */ | 2244 | goto out3; /* already mounted on put_old */ |
2247 | if (tmp->mnt_parent == new_nd.path.mnt) | 2245 | if (tmp->mnt_parent == new.mnt) |
2248 | break; | 2246 | break; |
2249 | tmp = tmp->mnt_parent; | 2247 | tmp = tmp->mnt_parent; |
2250 | } | 2248 | } |
2251 | if (!is_subdir(tmp->mnt_mountpoint, new_nd.path.dentry)) | 2249 | if (!is_subdir(tmp->mnt_mountpoint, new.dentry)) |
2252 | goto out3; | 2250 | goto out3; |
2253 | } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) | 2251 | } else if (!is_subdir(old.dentry, new.dentry)) |
2254 | goto out3; | 2252 | goto out3; |
2255 | detach_mnt(new_nd.path.mnt, &parent_path); | 2253 | detach_mnt(new.mnt, &parent_path); |
2256 | detach_mnt(root.mnt, &root_parent); | 2254 | detach_mnt(root.mnt, &root_parent); |
2257 | /* mount old root on put_old */ | 2255 | /* mount old root on put_old */ |
2258 | attach_mnt(root.mnt, &old_nd.path); | 2256 | attach_mnt(root.mnt, &old); |
2259 | /* mount new_root on / */ | 2257 | /* mount new_root on / */ |
2260 | attach_mnt(new_nd.path.mnt, &root_parent); | 2258 | attach_mnt(new.mnt, &root_parent); |
2261 | touch_mnt_namespace(current->nsproxy->mnt_ns); | 2259 | touch_mnt_namespace(current->nsproxy->mnt_ns); |
2262 | spin_unlock(&vfsmount_lock); | 2260 | spin_unlock(&vfsmount_lock); |
2263 | chroot_fs_refs(&root, &new_nd.path); | 2261 | chroot_fs_refs(&root, &new); |
2264 | security_sb_post_pivotroot(&root, &new_nd.path); | 2262 | security_sb_post_pivotroot(&root, &new); |
2265 | error = 0; | 2263 | error = 0; |
2266 | path_put(&root_parent); | 2264 | path_put(&root_parent); |
2267 | path_put(&parent_path); | 2265 | path_put(&parent_path); |
2268 | out2: | 2266 | out2: |
2269 | mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); | 2267 | mutex_unlock(&old.dentry->d_inode->i_mutex); |
2270 | up_write(&namespace_sem); | 2268 | up_write(&namespace_sem); |
2271 | path_put(&root); | 2269 | path_put(&root); |
2272 | path_put(&old_nd.path); | 2270 | path_put(&old); |
2273 | out1: | 2271 | out1: |
2274 | path_put(&new_nd.path); | 2272 | path_put(&new); |
2275 | out0: | 2273 | out0: |
2276 | return error; | 2274 | return error; |
2277 | out3: | 2275 | out3: |