[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>

Al Viro 2d8f3038 256984a8

+235 -238
+5 -5
arch/alpha/kernel/osf_sys.c
··· 253 253 } 254 254 255 255 asmlinkage int 256 - osf_statfs(char __user *path, struct osf_statfs __user *buffer, unsigned long bufsiz) 256 + osf_statfs(char __user *pathname, struct osf_statfs __user *buffer, unsigned long bufsiz) 257 257 { 258 - struct nameidata nd; 258 + struct path path; 259 259 int retval; 260 260 261 - retval = user_path_walk(path, &nd); 261 + retval = user_path(pathname, &path); 262 262 if (!retval) { 263 - retval = do_osf_statfs(nd.path.dentry, buffer, bufsiz); 264 - path_put(&nd.path); 263 + retval = do_osf_statfs(path.dentry, buffer, bufsiz); 264 + path_put(&path); 265 265 } 266 266 return retval; 267 267 }
+5 -5
arch/parisc/hpux/sys_hpux.c
··· 210 210 } 211 211 212 212 /* hpux statfs */ 213 - asmlinkage long hpux_statfs(const char __user *path, 213 + asmlinkage long hpux_statfs(const char __user *pathname, 214 214 struct hpux_statfs __user *buf) 215 215 { 216 - struct nameidata nd; 216 + struct path path; 217 217 int error; 218 218 219 - error = user_path_walk(path, &nd); 219 + error = user_path(pathname, &path); 220 220 if (!error) { 221 221 struct hpux_statfs tmp; 222 - error = vfs_statfs_hpux(nd.path.dentry, &tmp); 222 + error = vfs_statfs_hpux(path.dentry, &tmp); 223 223 if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) 224 224 error = -EFAULT; 225 - path_put(&nd.path); 225 + path_put(&path); 226 226 } 227 227 return error; 228 228 }
+7 -7
fs/coda/pioctl.c
··· 49 49 static int coda_pioctl(struct inode * inode, struct file * filp, 50 50 unsigned int cmd, unsigned long user_data) 51 51 { 52 - struct nameidata nd; 52 + struct path path; 53 53 int error; 54 54 struct PioctlData data; 55 55 struct inode *target_inode = NULL; ··· 64 64 * Look up the pathname. Note that the pathname is in 65 65 * user memory, and namei takes care of this 66 66 */ 67 - if ( data.follow ) { 68 - error = user_path_walk(data.path, &nd); 67 + if (data.follow) { 68 + error = user_path(data.path, &path); 69 69 } else { 70 - error = user_path_walk_link(data.path, &nd); 70 + error = user_lpath(data.path, &path); 71 71 } 72 72 73 73 if ( error ) { 74 74 return error; 75 75 } else { 76 - target_inode = nd.path.dentry->d_inode; 76 + target_inode = path.dentry->d_inode; 77 77 } 78 78 79 79 /* return if it is not a Coda inode */ 80 80 if ( target_inode->i_sb != inode->i_sb ) { 81 - path_put(&nd.path); 81 + path_put(&path); 82 82 return -EINVAL; 83 83 } 84 84 ··· 87 87 88 88 error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data); 89 89 90 - path_put(&nd.path); 90 + path_put(&path); 91 91 return error; 92 92 } 93 93
+10 -10
fs/compat.c
··· 234 234 * The following statfs calls are copies of code from fs/open.c and 235 235 * should be checked against those from time to time 236 236 */ 237 - asmlinkage long compat_sys_statfs(const char __user *path, struct compat_statfs __user *buf) 237 + asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf) 238 238 { 239 - struct nameidata nd; 239 + struct path path; 240 240 int error; 241 241 242 - error = user_path_walk(path, &nd); 242 + error = user_path(pathname, &path); 243 243 if (!error) { 244 244 struct kstatfs tmp; 245 - error = vfs_statfs(nd.path.dentry, &tmp); 245 + error = vfs_statfs(path.dentry, &tmp); 246 246 if (!error) 247 247 error = put_compat_statfs(buf, &tmp); 248 - path_put(&nd.path); 248 + path_put(&path); 249 249 } 250 250 return error; 251 251 } ··· 299 299 return 0; 300 300 } 301 301 302 - asmlinkage long compat_sys_statfs64(const char __user *path, compat_size_t sz, struct compat_statfs64 __user *buf) 302 + asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t sz, struct compat_statfs64 __user *buf) 303 303 { 304 - struct nameidata nd; 304 + struct path path; 305 305 int error; 306 306 307 307 if (sz != sizeof(*buf)) 308 308 return -EINVAL; 309 309 310 - error = user_path_walk(path, &nd); 310 + error = user_path(pathname, &path); 311 311 if (!error) { 312 312 struct kstatfs tmp; 313 - error = vfs_statfs(nd.path.dentry, &tmp); 313 + error = vfs_statfs(path.dentry, &tmp); 314 314 if (!error) 315 315 error = put_compat_statfs64(buf, &tmp); 316 - path_put(&nd.path); 316 + path_put(&path); 317 317 } 318 318 return error; 319 319 }
+11 -11
fs/inotify_user.c
··· 354 354 } 355 355 356 356 /* 357 - * find_inode - resolve a user-given path to a specific inode and return a nd 357 + * find_inode - resolve a user-given path to a specific inode 358 358 */ 359 - static int find_inode(const char __user *dirname, struct nameidata *nd, 359 + static int find_inode(const char __user *dirname, struct path *path, 360 360 unsigned flags) 361 361 { 362 362 int error; 363 363 364 - error = __user_walk(dirname, flags, nd); 364 + error = user_path_at(AT_FDCWD, dirname, flags, path); 365 365 if (error) 366 366 return error; 367 367 /* you can only watch an inode if you have read permissions on it */ 368 - error = inode_permission(nd->path.dentry->d_inode, MAY_READ); 368 + error = inode_permission(path->dentry->d_inode, MAY_READ); 369 369 if (error) 370 - path_put(&nd->path); 370 + path_put(path); 371 371 return error; 372 372 } 373 373 ··· 650 650 return sys_inotify_init1(0); 651 651 } 652 652 653 - asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) 653 + asmlinkage long sys_inotify_add_watch(int fd, const char __user *pathname, u32 mask) 654 654 { 655 655 struct inode *inode; 656 656 struct inotify_device *dev; 657 - struct nameidata nd; 657 + struct path path; 658 658 struct file *filp; 659 659 int ret, fput_needed; 660 660 unsigned flags = 0; ··· 674 674 if (mask & IN_ONLYDIR) 675 675 flags |= LOOKUP_DIRECTORY; 676 676 677 - ret = find_inode(path, &nd, flags); 677 + ret = find_inode(pathname, &path, flags); 678 678 if (unlikely(ret)) 679 679 goto fput_and_out; 680 680 681 - /* inode held in place by reference to nd; dev by fget on fd */ 682 - inode = nd.path.dentry->d_inode; 681 + /* inode held in place by reference to path; dev by fget on fd */ 682 + inode = path.dentry->d_inode; 683 683 dev = filp->private_data; 684 684 685 685 mutex_lock(&dev->up_mutex); ··· 688 688 ret = create_watch(dev, inode, mask); 689 689 mutex_unlock(&dev->up_mutex); 690 690 691 - path_put(&nd.path); 691 + path_put(&path); 692 692 fput_and_out: 693 693 fput_light(filp, fput_needed); 694 694 return ret;
+18 -18
fs/namei.c
··· 1334 1334 return __lookup_hash(&this, base, NULL); 1335 1335 } 1336 1336 1337 - int __user_walk_fd(int dfd, const char __user *name, unsigned flags, 1338 - struct nameidata *nd) 1337 + int user_path_at(int dfd, const char __user *name, unsigned flags, 1338 + struct path *path) 1339 1339 { 1340 + struct nameidata nd; 1340 1341 char *tmp = getname(name); 1341 1342 int err = PTR_ERR(tmp); 1342 - 1343 1343 if (!IS_ERR(tmp)) { 1344 - err = do_path_lookup(dfd, tmp, flags, nd); 1344 + 1345 + BUG_ON(flags & LOOKUP_PARENT); 1346 + 1347 + err = do_path_lookup(dfd, tmp, flags, &nd); 1345 1348 putname(tmp); 1349 + if (!err) 1350 + *path = nd.path; 1346 1351 } 1347 1352 return err; 1348 - } 1349 - 1350 - int __user_walk(const char __user *name, unsigned flags, struct nameidata *nd) 1351 - { 1352 - return __user_walk_fd(AT_FDCWD, name, flags, nd); 1353 1353 } 1354 1354 1355 1355 /* ··· 2446 2446 int flags) 2447 2447 { 2448 2448 struct dentry *new_dentry; 2449 - struct nameidata nd, old_nd; 2449 + struct nameidata nd; 2450 + struct path old_path; 2450 2451 int error; 2451 2452 char * to; 2452 2453 ··· 2458 2457 if (IS_ERR(to)) 2459 2458 return PTR_ERR(to); 2460 2459 2461 - error = __user_walk_fd(olddfd, oldname, 2462 - flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0, 2463 - &old_nd); 2460 + error = user_path_at(olddfd, oldname, 2461 + flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0, 2462 + &old_path); 2464 2463 if (error) 2465 2464 goto exit; 2466 2465 error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); 2467 2466 if (error) 2468 2467 goto out; 2469 2468 error = -EXDEV; 2470 - if (old_nd.path.mnt != nd.path.mnt) 2469 + if (old_path.mnt != nd.path.mnt) 2471 2470 goto out_release; 2472 2471 new_dentry = lookup_create(&nd, 0); 2473 2472 error = PTR_ERR(new_dentry); ··· 2476 2475 error = mnt_want_write(nd.path.mnt); 2477 2476 if (error) 2478 2477 goto out_dput; 2479 - error = vfs_link(old_nd.path.dentry, nd.path.dentry->d_inode, new_dentry); 2478 + error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry); 2480 2479 mnt_drop_write(nd.path.mnt); 2481 2480 out_dput: 2482 2481 dput(new_dentry); ··· 2485 2484 out_release: 2486 2485 path_put(&nd.path); 2487 2486 out: 2488 - path_put(&old_nd.path); 2487 + path_put(&old_path); 2489 2488 exit: 2490 2489 putname(to); 2491 2490 ··· 2878 2877 .put_link = page_put_link, 2879 2878 }; 2880 2879 2881 - EXPORT_SYMBOL(__user_walk); 2882 - EXPORT_SYMBOL(__user_walk_fd); 2880 + EXPORT_SYMBOL(user_path_at); 2883 2881 EXPORT_SYMBOL(follow_down); 2884 2882 EXPORT_SYMBOL(follow_up); 2885 2883 EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
+36 -38
fs/namespace.c
··· 1130 1130 1131 1131 asmlinkage long sys_umount(char __user * name, int flags) 1132 1132 { 1133 - struct nameidata nd; 1133 + struct path path; 1134 1134 int retval; 1135 1135 1136 - retval = __user_walk(name, LOOKUP_FOLLOW, &nd); 1136 + retval = user_path(name, &path); 1137 1137 if (retval) 1138 1138 goto out; 1139 1139 retval = -EINVAL; 1140 - if (nd.path.dentry != nd.path.mnt->mnt_root) 1140 + if (path.dentry != path.mnt->mnt_root) 1141 1141 goto dput_and_out; 1142 - if (!check_mnt(nd.path.mnt)) 1142 + if (!check_mnt(path.mnt)) 1143 1143 goto dput_and_out; 1144 1144 1145 1145 retval = -EPERM; 1146 1146 if (!capable(CAP_SYS_ADMIN)) 1147 1147 goto dput_and_out; 1148 1148 1149 - retval = do_umount(nd.path.mnt, flags); 1149 + retval = do_umount(path.mnt, flags); 1150 1150 dput_and_out: 1151 1151 /* we mustn't call path_put() as that would clear mnt_expiry_mark */ 1152 - dput(nd.path.dentry); 1153 - mntput_no_expire(nd.path.mnt); 1152 + dput(path.dentry); 1153 + mntput_no_expire(path.mnt); 1154 1154 out: 1155 1155 return retval; 1156 1156 } ··· 2179 2179 const char __user * put_old) 2180 2180 { 2181 2181 struct vfsmount *tmp; 2182 - struct nameidata new_nd, old_nd; 2183 - struct path parent_path, root_parent, root; 2182 + struct path new, old, parent_path, root_parent, root; 2184 2183 int error; 2185 2184 2186 2185 if (!capable(CAP_SYS_ADMIN)) 2187 2186 return -EPERM; 2188 2187 2189 - error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, 2190 - &new_nd); 2188 + error = user_path_dir(new_root, &new); 2191 2189 if (error) 2192 2190 goto out0; 2193 2191 error = -EINVAL; 2194 - if (!check_mnt(new_nd.path.mnt)) 2192 + if (!check_mnt(new.mnt)) 2195 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 2196 if (error) 2199 2197 goto out1; 2200 2198 2201 - error = security_sb_pivotroot(&old_nd.path, &new_nd.path); 2199 + error = security_sb_pivotroot(&old, &new); 2202 2200 if (error) { 2203 - path_put(&old_nd.path); 2201 + path_put(&old); 2204 2202 goto out1; 2205 2203 } 2206 2204 ··· 2207 2209 path_get(&current->fs->root); 2208 2210 read_unlock(&current->fs->lock); 2209 2211 down_write(&namespace_sem); 2210 - mutex_lock(&old_nd.path.dentry->d_inode->i_mutex); 2212 + mutex_lock(&old.dentry->d_inode->i_mutex); 2211 2213 error = -EINVAL; 2212 - if (IS_MNT_SHARED(old_nd.path.mnt) || 2213 - IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) || 2214 + if (IS_MNT_SHARED(old.mnt) || 2215 + IS_MNT_SHARED(new.mnt->mnt_parent) || 2214 2216 IS_MNT_SHARED(root.mnt->mnt_parent)) 2215 2217 goto out2; 2216 2218 if (!check_mnt(root.mnt)) 2217 2219 goto out2; 2218 2220 error = -ENOENT; 2219 - if (IS_DEADDIR(new_nd.path.dentry->d_inode)) 2221 + if (IS_DEADDIR(new.dentry->d_inode)) 2220 2222 goto out2; 2221 - if (d_unhashed(new_nd.path.dentry) && !IS_ROOT(new_nd.path.dentry)) 2223 + if (d_unhashed(new.dentry) && !IS_ROOT(new.dentry)) 2222 2224 goto out2; 2223 - if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry)) 2225 + if (d_unhashed(old.dentry) && !IS_ROOT(old.dentry)) 2224 2226 goto out2; 2225 2227 error = -EBUSY; 2226 - if (new_nd.path.mnt == root.mnt || 2227 - old_nd.path.mnt == root.mnt) 2228 + if (new.mnt == root.mnt || 2229 + old.mnt == root.mnt) 2228 2230 goto out2; /* loop, on the same file system */ 2229 2231 error = -EINVAL; 2230 2232 if (root.mnt->mnt_root != root.dentry) 2231 2233 goto out2; /* not a mountpoint */ 2232 2234 if (root.mnt->mnt_parent == root.mnt) 2233 2235 goto out2; /* not attached */ 2234 - if (new_nd.path.mnt->mnt_root != new_nd.path.dentry) 2236 + if (new.mnt->mnt_root != new.dentry) 2235 2237 goto out2; /* not a mountpoint */ 2236 - if (new_nd.path.mnt->mnt_parent == new_nd.path.mnt) 2238 + if (new.mnt->mnt_parent == new.mnt) 2237 2239 goto out2; /* not attached */ 2238 2240 /* make sure we can reach put_old from new_root */ 2239 - tmp = old_nd.path.mnt; 2241 + tmp = old.mnt; 2240 2242 spin_lock(&vfsmount_lock); 2241 - if (tmp != new_nd.path.mnt) { 2243 + if (tmp != new.mnt) { 2242 2244 for (;;) { 2243 2245 if (tmp->mnt_parent == tmp) 2244 2246 goto out3; /* already mounted on put_old */ 2245 - if (tmp->mnt_parent == new_nd.path.mnt) 2247 + if (tmp->mnt_parent == new.mnt) 2246 2248 break; 2247 2249 tmp = tmp->mnt_parent; 2248 2250 } 2249 - if (!is_subdir(tmp->mnt_mountpoint, new_nd.path.dentry)) 2251 + if (!is_subdir(tmp->mnt_mountpoint, new.dentry)) 2250 2252 goto out3; 2251 - } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) 2253 + } else if (!is_subdir(old.dentry, new.dentry)) 2252 2254 goto out3; 2253 - detach_mnt(new_nd.path.mnt, &parent_path); 2255 + detach_mnt(new.mnt, &parent_path); 2254 2256 detach_mnt(root.mnt, &root_parent); 2255 2257 /* mount old root on put_old */ 2256 - attach_mnt(root.mnt, &old_nd.path); 2258 + attach_mnt(root.mnt, &old); 2257 2259 /* mount new_root on / */ 2258 - attach_mnt(new_nd.path.mnt, &root_parent); 2260 + attach_mnt(new.mnt, &root_parent); 2259 2261 touch_mnt_namespace(current->nsproxy->mnt_ns); 2260 2262 spin_unlock(&vfsmount_lock); 2261 - chroot_fs_refs(&root, &new_nd.path); 2262 - security_sb_post_pivotroot(&root, &new_nd.path); 2263 + chroot_fs_refs(&root, &new); 2264 + security_sb_post_pivotroot(&root, &new); 2263 2265 error = 0; 2264 2266 path_put(&root_parent); 2265 2267 path_put(&parent_path); 2266 2268 out2: 2267 - mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); 2269 + mutex_unlock(&old.dentry->d_inode->i_mutex); 2268 2270 up_write(&namespace_sem); 2269 2271 path_put(&root); 2270 - path_put(&old_nd.path); 2272 + path_put(&old); 2271 2273 out1: 2272 - path_put(&new_nd.path); 2274 + path_put(&new); 2273 2275 out0: 2274 2276 return error; 2275 2277 out3:
+62 -62
fs/open.c
··· 122 122 return 0; 123 123 } 124 124 125 - asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf) 125 + asmlinkage long sys_statfs(const char __user *pathname, struct statfs __user * buf) 126 126 { 127 - struct nameidata nd; 127 + struct path path; 128 128 int error; 129 129 130 - error = user_path_walk(path, &nd); 130 + error = user_path(pathname, &path); 131 131 if (!error) { 132 132 struct statfs tmp; 133 - error = vfs_statfs_native(nd.path.dentry, &tmp); 133 + error = vfs_statfs_native(path.dentry, &tmp); 134 134 if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) 135 135 error = -EFAULT; 136 - path_put(&nd.path); 136 + path_put(&path); 137 137 } 138 138 return error; 139 139 } 140 140 141 141 142 - asmlinkage long sys_statfs64(const char __user *path, size_t sz, struct statfs64 __user *buf) 142 + asmlinkage long sys_statfs64(const char __user *pathname, size_t sz, struct statfs64 __user *buf) 143 143 { 144 - struct nameidata nd; 144 + struct path path; 145 145 long error; 146 146 147 147 if (sz != sizeof(*buf)) 148 148 return -EINVAL; 149 - error = user_path_walk(path, &nd); 149 + error = user_path(pathname, &path); 150 150 if (!error) { 151 151 struct statfs64 tmp; 152 - error = vfs_statfs64(nd.path.dentry, &tmp); 152 + error = vfs_statfs64(path.dentry, &tmp); 153 153 if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) 154 154 error = -EFAULT; 155 - path_put(&nd.path); 155 + path_put(&path); 156 156 } 157 157 return error; 158 158 } ··· 223 223 return err; 224 224 } 225 225 226 - static long do_sys_truncate(const char __user * path, loff_t length) 226 + static long do_sys_truncate(const char __user *pathname, loff_t length) 227 227 { 228 - struct nameidata nd; 229 - struct inode * inode; 228 + struct path path; 229 + struct inode *inode; 230 230 int error; 231 231 232 232 error = -EINVAL; 233 233 if (length < 0) /* sorry, but loff_t says... */ 234 234 goto out; 235 235 236 - error = user_path_walk(path, &nd); 236 + error = user_path(pathname, &path); 237 237 if (error) 238 238 goto out; 239 - inode = nd.path.dentry->d_inode; 239 + inode = path.dentry->d_inode; 240 240 241 241 /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ 242 242 error = -EISDIR; ··· 247 247 if (!S_ISREG(inode->i_mode)) 248 248 goto dput_and_out; 249 249 250 - error = mnt_want_write(nd.path.mnt); 250 + error = mnt_want_write(path.mnt); 251 251 if (error) 252 252 goto dput_and_out; 253 253 ··· 274 274 error = locks_verify_truncate(inode, NULL, length); 275 275 if (!error) { 276 276 DQUOT_INIT(inode); 277 - error = do_truncate(nd.path.dentry, length, 0, NULL); 277 + error = do_truncate(path.dentry, length, 0, NULL); 278 278 } 279 279 280 280 put_write_and_out: 281 281 put_write_access(inode); 282 282 mnt_drop_write_and_out: 283 - mnt_drop_write(nd.path.mnt); 283 + mnt_drop_write(path.mnt); 284 284 dput_and_out: 285 - path_put(&nd.path); 285 + path_put(&path); 286 286 out: 287 287 return error; 288 288 } ··· 425 425 */ 426 426 asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) 427 427 { 428 - struct nameidata nd; 428 + struct path path; 429 429 struct inode *inode; 430 430 int old_fsuid, old_fsgid; 431 431 kernel_cap_t uninitialized_var(old_cap); /* !SECURE_NO_SETUID_FIXUP */ ··· 449 449 * FIXME: There is a race here against sys_capset. The 450 450 * capabilities can change yet we will restore the old 451 451 * value below. We should hold task_capabilities_lock, 452 - * but we cannot because user_path_walk can sleep. 452 + * but we cannot because user_path_at can sleep. 453 453 */ 454 454 #endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */ 455 455 if (current->uid) ··· 458 458 old_cap = cap_set_effective(current->cap_permitted); 459 459 } 460 460 461 - res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); 461 + res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); 462 462 if (res) 463 463 goto out; 464 464 465 - inode = nd.path.dentry->d_inode; 465 + inode = path.dentry->d_inode; 466 466 467 467 if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) { 468 468 /* ··· 470 470 * with the "noexec" flag. 471 471 */ 472 472 res = -EACCES; 473 - if (nd.path.mnt->mnt_flags & MNT_NOEXEC) 473 + if (path.mnt->mnt_flags & MNT_NOEXEC) 474 474 goto out_path_release; 475 475 } 476 476 ··· 488 488 * inherently racy and know that the fs may change 489 489 * state before we even see this result. 490 490 */ 491 - if (__mnt_is_readonly(nd.path.mnt)) 491 + if (__mnt_is_readonly(path.mnt)) 492 492 res = -EROFS; 493 493 494 494 out_path_release: 495 - path_put(&nd.path); 495 + path_put(&path); 496 496 out: 497 497 current->fsuid = old_fsuid; 498 498 current->fsgid = old_fsgid; ··· 510 510 511 511 asmlinkage long sys_chdir(const char __user * filename) 512 512 { 513 - struct nameidata nd; 513 + struct path path; 514 514 int error; 515 515 516 - error = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd); 516 + error = user_path_dir(filename, &path); 517 517 if (error) 518 518 goto out; 519 519 520 - error = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_ACCESS); 520 + error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS); 521 521 if (error) 522 522 goto dput_and_out; 523 523 524 - set_fs_pwd(current->fs, &nd.path); 524 + set_fs_pwd(current->fs, &path); 525 525 526 526 dput_and_out: 527 - path_put(&nd.path); 527 + path_put(&path); 528 528 out: 529 529 return error; 530 530 } ··· 557 557 558 558 asmlinkage long sys_chroot(const char __user * filename) 559 559 { 560 - struct nameidata nd; 560 + struct path path; 561 561 int error; 562 562 563 - error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd); 563 + error = user_path_dir(filename, &path); 564 564 if (error) 565 565 goto out; 566 566 567 - error = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_ACCESS); 567 + error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_ACCESS); 568 568 if (error) 569 569 goto dput_and_out; 570 570 ··· 572 572 if (!capable(CAP_SYS_CHROOT)) 573 573 goto dput_and_out; 574 574 575 - set_fs_root(current->fs, &nd.path); 575 + set_fs_root(current->fs, &path); 576 576 error = 0; 577 577 dput_and_out: 578 - path_put(&nd.path); 578 + path_put(&path); 579 579 out: 580 580 return error; 581 581 } ··· 617 617 asmlinkage long sys_fchmodat(int dfd, const char __user *filename, 618 618 mode_t mode) 619 619 { 620 - struct nameidata nd; 621 - struct inode * inode; 620 + struct path path; 621 + struct inode *inode; 622 622 int error; 623 623 struct iattr newattrs; 624 624 625 - error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); 625 + error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); 626 626 if (error) 627 627 goto out; 628 - inode = nd.path.dentry->d_inode; 628 + inode = path.dentry->d_inode; 629 629 630 - error = mnt_want_write(nd.path.mnt); 630 + error = mnt_want_write(path.mnt); 631 631 if (error) 632 632 goto dput_and_out; 633 633 mutex_lock(&inode->i_mutex); ··· 635 635 mode = inode->i_mode; 636 636 newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); 637 637 newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; 638 - error = notify_change(nd.path.dentry, &newattrs); 638 + error = notify_change(path.dentry, &newattrs); 639 639 mutex_unlock(&inode->i_mutex); 640 - mnt_drop_write(nd.path.mnt); 640 + mnt_drop_write(path.mnt); 641 641 dput_and_out: 642 - path_put(&nd.path); 642 + path_put(&path); 643 643 out: 644 644 return error; 645 645 } ··· 676 676 677 677 asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group) 678 678 { 679 - struct nameidata nd; 679 + struct path path; 680 680 int error; 681 681 682 - error = user_path_walk(filename, &nd); 682 + error = user_path(filename, &path); 683 683 if (error) 684 684 goto out; 685 - error = mnt_want_write(nd.path.mnt); 685 + error = mnt_want_write(path.mnt); 686 686 if (error) 687 687 goto out_release; 688 - error = chown_common(nd.path.dentry, user, group); 689 - mnt_drop_write(nd.path.mnt); 688 + error = chown_common(path.dentry, user, group); 689 + mnt_drop_write(path.mnt); 690 690 out_release: 691 - path_put(&nd.path); 691 + path_put(&path); 692 692 out: 693 693 return error; 694 694 } ··· 696 696 asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, 697 697 gid_t group, int flag) 698 698 { 699 - struct nameidata nd; 699 + struct path path; 700 700 int error = -EINVAL; 701 701 int follow; 702 702 ··· 704 704 goto out; 705 705 706 706 follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; 707 - error = __user_walk_fd(dfd, filename, follow, &nd); 707 + error = user_path_at(dfd, filename, follow, &path); 708 708 if (error) 709 709 goto out; 710 - error = mnt_want_write(nd.path.mnt); 710 + error = mnt_want_write(path.mnt); 711 711 if (error) 712 712 goto out_release; 713 - error = chown_common(nd.path.dentry, user, group); 714 - mnt_drop_write(nd.path.mnt); 713 + error = chown_common(path.dentry, user, group); 714 + mnt_drop_write(path.mnt); 715 715 out_release: 716 - path_put(&nd.path); 716 + path_put(&path); 717 717 out: 718 718 return error; 719 719 } 720 720 721 721 asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group) 722 722 { 723 - struct nameidata nd; 723 + struct path path; 724 724 int error; 725 725 726 - error = user_path_walk_link(filename, &nd); 726 + error = user_lpath(filename, &path); 727 727 if (error) 728 728 goto out; 729 - error = mnt_want_write(nd.path.mnt); 729 + error = mnt_want_write(path.mnt); 730 730 if (error) 731 731 goto out_release; 732 - error = chown_common(nd.path.dentry, user, group); 733 - mnt_drop_write(nd.path.mnt); 732 + error = chown_common(path.dentry, user, group); 733 + mnt_drop_write(path.mnt); 734 734 out_release: 735 - path_put(&nd.path); 735 + path_put(&path); 736 736 out: 737 737 return error; 738 738 }
+16 -16
fs/stat.c
··· 57 57 58 58 int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat) 59 59 { 60 - struct nameidata nd; 60 + struct path path; 61 61 int error; 62 62 63 - error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd); 63 + error = user_path_at(dfd, name, LOOKUP_FOLLOW, &path); 64 64 if (!error) { 65 - error = vfs_getattr(nd.path.mnt, nd.path.dentry, stat); 66 - path_put(&nd.path); 65 + error = vfs_getattr(path.mnt, path.dentry, stat); 66 + path_put(&path); 67 67 } 68 68 return error; 69 69 } ··· 77 77 78 78 int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat) 79 79 { 80 - struct nameidata nd; 80 + struct path path; 81 81 int error; 82 82 83 - error = __user_walk_fd(dfd, name, 0, &nd); 83 + error = user_path_at(dfd, name, 0, &path); 84 84 if (!error) { 85 - error = vfs_getattr(nd.path.mnt, nd.path.dentry, stat); 86 - path_put(&nd.path); 85 + error = vfs_getattr(path.mnt, path.dentry, stat); 86 + path_put(&path); 87 87 } 88 88 return error; 89 89 } ··· 291 291 return error; 292 292 } 293 293 294 - asmlinkage long sys_readlinkat(int dfd, const char __user *path, 294 + asmlinkage long sys_readlinkat(int dfd, const char __user *pathname, 295 295 char __user *buf, int bufsiz) 296 296 { 297 - struct nameidata nd; 297 + struct path path; 298 298 int error; 299 299 300 300 if (bufsiz <= 0) 301 301 return -EINVAL; 302 302 303 - error = __user_walk_fd(dfd, path, 0, &nd); 303 + error = user_path_at(dfd, pathname, 0, &path); 304 304 if (!error) { 305 - struct inode *inode = nd.path.dentry->d_inode; 305 + struct inode *inode = path.dentry->d_inode; 306 306 307 307 error = -EINVAL; 308 308 if (inode->i_op && inode->i_op->readlink) { 309 - error = security_inode_readlink(nd.path.dentry); 309 + error = security_inode_readlink(path.dentry); 310 310 if (!error) { 311 - touch_atime(nd.path.mnt, nd.path.dentry); 312 - error = inode->i_op->readlink(nd.path.dentry, 311 + touch_atime(path.mnt, path.dentry); 312 + error = inode->i_op->readlink(path.dentry, 313 313 buf, bufsiz); 314 314 } 315 315 } 316 - path_put(&nd.path); 316 + path_put(&path); 317 317 } 318 318 return error; 319 319 }
+4 -4
fs/utimes.c
··· 152 152 error = utimes_common(&file->f_path, times); 153 153 fput(file); 154 154 } else { 155 - struct nameidata nd; 155 + struct path path; 156 156 int lookup_flags = 0; 157 157 158 158 if (!(flags & AT_SYMLINK_NOFOLLOW)) 159 159 lookup_flags |= LOOKUP_FOLLOW; 160 160 161 - error = __user_walk_fd(dfd, filename, lookup_flags, &nd); 161 + error = user_path_at(dfd, filename, lookup_flags, &path); 162 162 if (error) 163 163 goto out; 164 164 165 - error = utimes_common(&nd.path, times); 166 - path_put(&nd.path); 165 + error = utimes_common(&path, times); 166 + path_put(&path); 167 167 } 168 168 169 169 out:
+48 -48
fs/xattr.c
··· 252 252 } 253 253 254 254 asmlinkage long 255 - sys_setxattr(const char __user *path, const char __user *name, 255 + sys_setxattr(const char __user *pathname, const char __user *name, 256 256 const void __user *value, size_t size, int flags) 257 257 { 258 - struct nameidata nd; 258 + struct path path; 259 259 int error; 260 260 261 - error = user_path_walk(path, &nd); 261 + error = user_path(pathname, &path); 262 262 if (error) 263 263 return error; 264 - error = mnt_want_write(nd.path.mnt); 264 + error = mnt_want_write(path.mnt); 265 265 if (!error) { 266 - error = setxattr(nd.path.dentry, name, value, size, flags); 267 - mnt_drop_write(nd.path.mnt); 266 + error = setxattr(path.dentry, name, value, size, flags); 267 + mnt_drop_write(path.mnt); 268 268 } 269 - path_put(&nd.path); 269 + path_put(&path); 270 270 return error; 271 271 } 272 272 273 273 asmlinkage long 274 - sys_lsetxattr(const char __user *path, const char __user *name, 274 + sys_lsetxattr(const char __user *pathname, const char __user *name, 275 275 const void __user *value, size_t size, int flags) 276 276 { 277 - struct nameidata nd; 277 + struct path path; 278 278 int error; 279 279 280 - error = user_path_walk_link(path, &nd); 280 + error = user_lpath(pathname, &path); 281 281 if (error) 282 282 return error; 283 - error = mnt_want_write(nd.path.mnt); 283 + error = mnt_want_write(path.mnt); 284 284 if (!error) { 285 - error = setxattr(nd.path.dentry, name, value, size, flags); 286 - mnt_drop_write(nd.path.mnt); 285 + error = setxattr(path.dentry, name, value, size, flags); 286 + mnt_drop_write(path.mnt); 287 287 } 288 - path_put(&nd.path); 288 + path_put(&path); 289 289 return error; 290 290 } 291 291 ··· 350 350 } 351 351 352 352 asmlinkage ssize_t 353 - sys_getxattr(const char __user *path, const char __user *name, 353 + sys_getxattr(const char __user *pathname, const char __user *name, 354 354 void __user *value, size_t size) 355 355 { 356 - struct nameidata nd; 356 + struct path path; 357 357 ssize_t error; 358 358 359 - error = user_path_walk(path, &nd); 359 + error = user_path(pathname, &path); 360 360 if (error) 361 361 return error; 362 - error = getxattr(nd.path.dentry, name, value, size); 363 - path_put(&nd.path); 362 + error = getxattr(path.dentry, name, value, size); 363 + path_put(&path); 364 364 return error; 365 365 } 366 366 367 367 asmlinkage ssize_t 368 - sys_lgetxattr(const char __user *path, const char __user *name, void __user *value, 368 + sys_lgetxattr(const char __user *pathname, const char __user *name, void __user *value, 369 369 size_t size) 370 370 { 371 - struct nameidata nd; 371 + struct path path; 372 372 ssize_t error; 373 373 374 - error = user_path_walk_link(path, &nd); 374 + error = user_lpath(pathname, &path); 375 375 if (error) 376 376 return error; 377 - error = getxattr(nd.path.dentry, name, value, size); 378 - path_put(&nd.path); 377 + error = getxattr(path.dentry, name, value, size); 378 + path_put(&path); 379 379 return error; 380 380 } 381 381 ··· 425 425 } 426 426 427 427 asmlinkage ssize_t 428 - sys_listxattr(const char __user *path, char __user *list, size_t size) 428 + sys_listxattr(const char __user *pathname, char __user *list, size_t size) 429 429 { 430 - struct nameidata nd; 430 + struct path path; 431 431 ssize_t error; 432 432 433 - error = user_path_walk(path, &nd); 433 + error = user_path(pathname, &path); 434 434 if (error) 435 435 return error; 436 - error = listxattr(nd.path.dentry, list, size); 437 - path_put(&nd.path); 436 + error = listxattr(path.dentry, list, size); 437 + path_put(&path); 438 438 return error; 439 439 } 440 440 441 441 asmlinkage ssize_t 442 - sys_llistxattr(const char __user *path, char __user *list, size_t size) 442 + sys_llistxattr(const char __user *pathname, char __user *list, size_t size) 443 443 { 444 - struct nameidata nd; 444 + struct path path; 445 445 ssize_t error; 446 446 447 - error = user_path_walk_link(path, &nd); 447 + error = user_lpath(pathname, &path); 448 448 if (error) 449 449 return error; 450 - error = listxattr(nd.path.dentry, list, size); 451 - path_put(&nd.path); 450 + error = listxattr(path.dentry, list, size); 451 + path_put(&path); 452 452 return error; 453 453 } 454 454 ··· 486 486 } 487 487 488 488 asmlinkage long 489 - sys_removexattr(const char __user *path, const char __user *name) 489 + sys_removexattr(const char __user *pathname, const char __user *name) 490 490 { 491 - struct nameidata nd; 491 + struct path path; 492 492 int error; 493 493 494 - error = user_path_walk(path, &nd); 494 + error = user_path(pathname, &path); 495 495 if (error) 496 496 return error; 497 - error = mnt_want_write(nd.path.mnt); 497 + error = mnt_want_write(path.mnt); 498 498 if (!error) { 499 - error = removexattr(nd.path.dentry, name); 500 - mnt_drop_write(nd.path.mnt); 499 + error = removexattr(path.dentry, name); 500 + mnt_drop_write(path.mnt); 501 501 } 502 - path_put(&nd.path); 502 + path_put(&path); 503 503 return error; 504 504 } 505 505 506 506 asmlinkage long 507 - sys_lremovexattr(const char __user *path, const char __user *name) 507 + sys_lremovexattr(const char __user *pathname, const char __user *name) 508 508 { 509 - struct nameidata nd; 509 + struct path path; 510 510 int error; 511 511 512 - error = user_path_walk_link(path, &nd); 512 + error = user_lpath(pathname, &path); 513 513 if (error) 514 514 return error; 515 - error = mnt_want_write(nd.path.mnt); 515 + error = mnt_want_write(path.mnt); 516 516 if (!error) { 517 - error = removexattr(nd.path.dentry, name); 518 - mnt_drop_write(nd.path.mnt); 517 + error = removexattr(path.dentry, name); 518 + mnt_drop_write(path.mnt); 519 519 } 520 - path_put(&nd.path); 520 + path_put(&path); 521 521 return error; 522 522 } 523 523
+6 -8
fs/xfs/linux-2.6/xfs_ioctl.c
··· 84 84 switch (cmd) { 85 85 case XFS_IOC_PATH_TO_FSHANDLE: 86 86 case XFS_IOC_PATH_TO_HANDLE: { 87 - struct nameidata nd; 88 - int error; 89 - 90 - error = user_path_walk_link((const char __user *)hreq.path, &nd); 87 + struct path path; 88 + int error = user_lpath((const char __user *)hreq.path, &path); 91 89 if (error) 92 90 return error; 93 91 94 - ASSERT(nd.path.dentry); 95 - ASSERT(nd.path.dentry->d_inode); 96 - inode = igrab(nd.path.dentry->d_inode); 97 - path_put(&nd.path); 92 + ASSERT(path.dentry); 93 + ASSERT(path.dentry->d_inode); 94 + inode = igrab(path.dentry->d_inode); 95 + path_put(&path); 98 96 break; 99 97 } 100 98
+7 -6
include/linux/namei.h
··· 54 54 #define LOOKUP_OPEN (0x0100) 55 55 #define LOOKUP_CREATE (0x0200) 56 56 57 - extern int __user_walk(const char __user *, unsigned, struct nameidata *); 58 - extern int __user_walk_fd(int dfd, const char __user *, unsigned, struct nameidata *); 59 - #define user_path_walk(name,nd) \ 60 - __user_walk_fd(AT_FDCWD, name, LOOKUP_FOLLOW, nd) 61 - #define user_path_walk_link(name,nd) \ 62 - __user_walk_fd(AT_FDCWD, name, 0, nd) 57 + extern int user_path_at(int, const char __user *, unsigned, struct path *); 58 + 59 + #define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path) 60 + #define user_lpath(name, path) user_path_at(AT_FDCWD, name, 0, path) 61 + #define user_path_dir(name, path) \ 62 + user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, path) 63 + 63 64 extern int path_lookup(const char *, unsigned, struct nameidata *); 64 65 extern int vfs_path_lookup(struct dentry *, struct vfsmount *, 65 66 const char *, unsigned int, struct nameidata *);