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