diff options
| -rw-r--r-- | fs/namei.c | 137 |
1 files changed, 57 insertions, 80 deletions
diff --git a/fs/namei.c b/fs/namei.c index edb5e973f9b3..38ceb6e06eba 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -1352,6 +1352,24 @@ int user_path_at(int dfd, const char __user *name, unsigned flags, | |||
| 1352 | return err; | 1352 | return err; |
| 1353 | } | 1353 | } |
| 1354 | 1354 | ||
| 1355 | static int user_path_parent(int dfd, const char __user *path, | ||
| 1356 | struct nameidata *nd, char **name) | ||
| 1357 | { | ||
| 1358 | char *s = getname(path); | ||
| 1359 | int error; | ||
| 1360 | |||
| 1361 | if (IS_ERR(s)) | ||
| 1362 | return PTR_ERR(s); | ||
| 1363 | |||
| 1364 | error = do_path_lookup(dfd, s, LOOKUP_PARENT, nd); | ||
| 1365 | if (error) | ||
| 1366 | putname(s); | ||
| 1367 | else | ||
| 1368 | *name = s; | ||
| 1369 | |||
| 1370 | return error; | ||
| 1371 | } | ||
| 1372 | |||
| 1355 | /* | 1373 | /* |
| 1356 | * It's inline, so penalty for filesystems that don't use sticky bit is | 1374 | * It's inline, so penalty for filesystems that don't use sticky bit is |
| 1357 | * minimal. | 1375 | * minimal. |
| @@ -1989,20 +2007,18 @@ static int may_mknod(mode_t mode) | |||
| 1989 | asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, | 2007 | asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, |
| 1990 | unsigned dev) | 2008 | unsigned dev) |
| 1991 | { | 2009 | { |
| 1992 | int error = 0; | 2010 | int error; |
| 1993 | char * tmp; | 2011 | char *tmp; |
| 1994 | struct dentry * dentry; | 2012 | struct dentry *dentry; |
| 1995 | struct nameidata nd; | 2013 | struct nameidata nd; |
| 1996 | 2014 | ||
| 1997 | if (S_ISDIR(mode)) | 2015 | if (S_ISDIR(mode)) |
| 1998 | return -EPERM; | 2016 | return -EPERM; |
| 1999 | tmp = getname(filename); | ||
| 2000 | if (IS_ERR(tmp)) | ||
| 2001 | return PTR_ERR(tmp); | ||
| 2002 | 2017 | ||
| 2003 | error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); | 2018 | error = user_path_parent(dfd, filename, &nd, &tmp); |
| 2004 | if (error) | 2019 | if (error) |
| 2005 | goto out; | 2020 | return error; |
| 2021 | |||
| 2006 | dentry = lookup_create(&nd, 0); | 2022 | dentry = lookup_create(&nd, 0); |
| 2007 | if (IS_ERR(dentry)) { | 2023 | if (IS_ERR(dentry)) { |
| 2008 | error = PTR_ERR(dentry); | 2024 | error = PTR_ERR(dentry); |
| @@ -2034,7 +2050,6 @@ out_dput: | |||
| 2034 | out_unlock: | 2050 | out_unlock: |
| 2035 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 2051 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); |
| 2036 | path_put(&nd.path); | 2052 | path_put(&nd.path); |
| 2037 | out: | ||
| 2038 | putname(tmp); | 2053 | putname(tmp); |
| 2039 | 2054 | ||
| 2040 | return error; | 2055 | return error; |
| @@ -2074,14 +2089,10 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode) | |||
| 2074 | struct dentry *dentry; | 2089 | struct dentry *dentry; |
| 2075 | struct nameidata nd; | 2090 | struct nameidata nd; |
| 2076 | 2091 | ||
| 2077 | tmp = getname(pathname); | 2092 | error = user_path_parent(dfd, pathname, &nd, &tmp); |
| 2078 | error = PTR_ERR(tmp); | 2093 | if (error) |
| 2079 | if (IS_ERR(tmp)) | ||
| 2080 | goto out_err; | 2094 | goto out_err; |
| 2081 | 2095 | ||
| 2082 | error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); | ||
| 2083 | if (error) | ||
| 2084 | goto out; | ||
| 2085 | dentry = lookup_create(&nd, 1); | 2096 | dentry = lookup_create(&nd, 1); |
| 2086 | error = PTR_ERR(dentry); | 2097 | error = PTR_ERR(dentry); |
| 2087 | if (IS_ERR(dentry)) | 2098 | if (IS_ERR(dentry)) |
| @@ -2099,7 +2110,6 @@ out_dput: | |||
| 2099 | out_unlock: | 2110 | out_unlock: |
| 2100 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 2111 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); |
| 2101 | path_put(&nd.path); | 2112 | path_put(&nd.path); |
| 2102 | out: | ||
| 2103 | putname(tmp); | 2113 | putname(tmp); |
| 2104 | out_err: | 2114 | out_err: |
| 2105 | return error; | 2115 | return error; |
| @@ -2177,13 +2187,9 @@ static long do_rmdir(int dfd, const char __user *pathname) | |||
| 2177 | struct dentry *dentry; | 2187 | struct dentry *dentry; |
| 2178 | struct nameidata nd; | 2188 | struct nameidata nd; |
| 2179 | 2189 | ||
| 2180 | name = getname(pathname); | 2190 | error = user_path_parent(dfd, pathname, &nd, &name); |
| 2181 | if(IS_ERR(name)) | ||
| 2182 | return PTR_ERR(name); | ||
| 2183 | |||
| 2184 | error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd); | ||
| 2185 | if (error) | 2191 | if (error) |
| 2186 | goto exit; | 2192 | return error; |
| 2187 | 2193 | ||
| 2188 | switch(nd.last_type) { | 2194 | switch(nd.last_type) { |
| 2189 | case LAST_DOTDOT: | 2195 | case LAST_DOTDOT: |
| @@ -2212,7 +2218,6 @@ exit2: | |||
| 2212 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 2218 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); |
| 2213 | exit1: | 2219 | exit1: |
| 2214 | path_put(&nd.path); | 2220 | path_put(&nd.path); |
| 2215 | exit: | ||
| 2216 | putname(name); | 2221 | putname(name); |
| 2217 | return error; | 2222 | return error; |
| 2218 | } | 2223 | } |
| @@ -2261,19 +2266,16 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 2261 | */ | 2266 | */ |
| 2262 | static long do_unlinkat(int dfd, const char __user *pathname) | 2267 | static long do_unlinkat(int dfd, const char __user *pathname) |
| 2263 | { | 2268 | { |
| 2264 | int error = 0; | 2269 | int error; |
| 2265 | char * name; | 2270 | char *name; |
| 2266 | struct dentry *dentry; | 2271 | struct dentry *dentry; |
| 2267 | struct nameidata nd; | 2272 | struct nameidata nd; |
| 2268 | struct inode *inode = NULL; | 2273 | struct inode *inode = NULL; |
| 2269 | 2274 | ||
| 2270 | name = getname(pathname); | 2275 | error = user_path_parent(dfd, pathname, &nd, &name); |
| 2271 | if(IS_ERR(name)) | ||
| 2272 | return PTR_ERR(name); | ||
| 2273 | |||
| 2274 | error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd); | ||
| 2275 | if (error) | 2276 | if (error) |
| 2276 | goto exit; | 2277 | return error; |
| 2278 | |||
| 2277 | error = -EISDIR; | 2279 | error = -EISDIR; |
| 2278 | if (nd.last_type != LAST_NORM) | 2280 | if (nd.last_type != LAST_NORM) |
| 2279 | goto exit1; | 2281 | goto exit1; |
| @@ -2300,7 +2302,6 @@ static long do_unlinkat(int dfd, const char __user *pathname) | |||
| 2300 | iput(inode); /* truncate the inode here */ | 2302 | iput(inode); /* truncate the inode here */ |
| 2301 | exit1: | 2303 | exit1: |
| 2302 | path_put(&nd.path); | 2304 | path_put(&nd.path); |
| 2303 | exit: | ||
| 2304 | putname(name); | 2305 | putname(name); |
| 2305 | return error; | 2306 | return error; |
| 2306 | 2307 | ||
| @@ -2350,23 +2351,20 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) | |||
| 2350 | asmlinkage long sys_symlinkat(const char __user *oldname, | 2351 | asmlinkage long sys_symlinkat(const char __user *oldname, |
| 2351 | int newdfd, const char __user *newname) | 2352 | int newdfd, const char __user *newname) |
| 2352 | { | 2353 | { |
| 2353 | int error = 0; | 2354 | int error; |
| 2354 | char * from; | 2355 | char *from; |
| 2355 | char * to; | 2356 | char *to; |
| 2356 | struct dentry *dentry; | 2357 | struct dentry *dentry; |
| 2357 | struct nameidata nd; | 2358 | struct nameidata nd; |
| 2358 | 2359 | ||
| 2359 | from = getname(oldname); | 2360 | from = getname(oldname); |
| 2360 | if(IS_ERR(from)) | 2361 | if (IS_ERR(from)) |
| 2361 | return PTR_ERR(from); | 2362 | return PTR_ERR(from); |
| 2362 | to = getname(newname); | ||
| 2363 | error = PTR_ERR(to); | ||
| 2364 | if (IS_ERR(to)) | ||
| 2365 | goto out_putname; | ||
| 2366 | 2363 | ||
| 2367 | error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); | 2364 | error = user_path_parent(newdfd, newname, &nd, &to); |
| 2368 | if (error) | 2365 | if (error) |
| 2369 | goto out; | 2366 | goto out_putname; |
| 2367 | |||
| 2370 | dentry = lookup_create(&nd, 0); | 2368 | dentry = lookup_create(&nd, 0); |
| 2371 | error = PTR_ERR(dentry); | 2369 | error = PTR_ERR(dentry); |
| 2372 | if (IS_ERR(dentry)) | 2370 | if (IS_ERR(dentry)) |
| @@ -2382,7 +2380,6 @@ out_dput: | |||
| 2382 | out_unlock: | 2380 | out_unlock: |
| 2383 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 2381 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); |
| 2384 | path_put(&nd.path); | 2382 | path_put(&nd.path); |
| 2385 | out: | ||
| 2386 | putname(to); | 2383 | putname(to); |
| 2387 | out_putname: | 2384 | out_putname: |
| 2388 | putname(from); | 2385 | putname(from); |
| @@ -2449,21 +2446,18 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname, | |||
| 2449 | struct nameidata nd; | 2446 | struct nameidata nd; |
| 2450 | struct path old_path; | 2447 | struct path old_path; |
| 2451 | int error; | 2448 | int error; |
| 2452 | char * to; | 2449 | char *to; |
| 2453 | 2450 | ||
| 2454 | if ((flags & ~AT_SYMLINK_FOLLOW) != 0) | 2451 | if ((flags & ~AT_SYMLINK_FOLLOW) != 0) |
| 2455 | return -EINVAL; | 2452 | return -EINVAL; |
| 2456 | 2453 | ||
| 2457 | to = getname(newname); | ||
| 2458 | if (IS_ERR(to)) | ||
| 2459 | return PTR_ERR(to); | ||
| 2460 | |||
| 2461 | error = user_path_at(olddfd, oldname, | 2454 | error = user_path_at(olddfd, oldname, |
| 2462 | flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0, | 2455 | flags & AT_SYMLINK_FOLLOW ? LOOKUP_FOLLOW : 0, |
| 2463 | &old_path); | 2456 | &old_path); |
| 2464 | if (error) | 2457 | if (error) |
| 2465 | goto exit; | 2458 | return error; |
| 2466 | error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); | 2459 | |
| 2460 | error = user_path_parent(newdfd, newname, &nd, &to); | ||
| 2467 | if (error) | 2461 | if (error) |
| 2468 | goto out; | 2462 | goto out; |
| 2469 | error = -EXDEV; | 2463 | error = -EXDEV; |
| @@ -2484,10 +2478,9 @@ out_unlock: | |||
| 2484 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | 2478 | mutex_unlock(&nd.path.dentry->d_inode->i_mutex); |
| 2485 | out_release: | 2479 | out_release: |
| 2486 | path_put(&nd.path); | 2480 | path_put(&nd.path); |
| 2481 | putname(to); | ||
| 2487 | out: | 2482 | out: |
| 2488 | path_put(&old_path); | 2483 | path_put(&old_path); |
| 2489 | exit: | ||
| 2490 | putname(to); | ||
| 2491 | 2484 | ||
| 2492 | return error; | 2485 | return error; |
| 2493 | } | 2486 | } |
| @@ -2643,20 +2636,22 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2643 | return error; | 2636 | return error; |
| 2644 | } | 2637 | } |
| 2645 | 2638 | ||
| 2646 | static int do_rename(int olddfd, const char *oldname, | 2639 | asmlinkage long sys_renameat(int olddfd, const char __user *oldname, |
| 2647 | int newdfd, const char *newname) | 2640 | int newdfd, const char __user *newname) |
| 2648 | { | 2641 | { |
| 2649 | int error = 0; | 2642 | struct dentry *old_dir, *new_dir; |
| 2650 | struct dentry * old_dir, * new_dir; | 2643 | struct dentry *old_dentry, *new_dentry; |
| 2651 | struct dentry * old_dentry, *new_dentry; | 2644 | struct dentry *trap; |
| 2652 | struct dentry * trap; | ||
| 2653 | struct nameidata oldnd, newnd; | 2645 | struct nameidata oldnd, newnd; |
| 2646 | char *from; | ||
| 2647 | char *to; | ||
| 2648 | int error; | ||
| 2654 | 2649 | ||
| 2655 | error = do_path_lookup(olddfd, oldname, LOOKUP_PARENT, &oldnd); | 2650 | error = user_path_parent(olddfd, oldname, &oldnd, &from); |
| 2656 | if (error) | 2651 | if (error) |
| 2657 | goto exit; | 2652 | goto exit; |
| 2658 | 2653 | ||
| 2659 | error = do_path_lookup(newdfd, newname, LOOKUP_PARENT, &newnd); | 2654 | error = user_path_parent(newdfd, newname, &newnd, &to); |
| 2660 | if (error) | 2655 | if (error) |
| 2661 | goto exit1; | 2656 | goto exit1; |
| 2662 | 2657 | ||
| @@ -2718,29 +2713,11 @@ exit3: | |||
| 2718 | unlock_rename(new_dir, old_dir); | 2713 | unlock_rename(new_dir, old_dir); |
| 2719 | exit2: | 2714 | exit2: |
| 2720 | path_put(&newnd.path); | 2715 | path_put(&newnd.path); |
| 2716 | putname(to); | ||
| 2721 | exit1: | 2717 | exit1: |
| 2722 | path_put(&oldnd.path); | 2718 | path_put(&oldnd.path); |
| 2723 | exit: | ||
| 2724 | return error; | ||
| 2725 | } | ||
| 2726 | |||
| 2727 | asmlinkage long sys_renameat(int olddfd, const char __user *oldname, | ||
| 2728 | int newdfd, const char __user *newname) | ||
| 2729 | { | ||
| 2730 | int error; | ||
| 2731 | char * from; | ||
| 2732 | char * to; | ||
| 2733 | |||
| 2734 | from = getname(oldname); | ||
| 2735 | if(IS_ERR(from)) | ||
| 2736 | return PTR_ERR(from); | ||
| 2737 | to = getname(newname); | ||
| 2738 | error = PTR_ERR(to); | ||
| 2739 | if (!IS_ERR(to)) { | ||
| 2740 | error = do_rename(olddfd, from, newdfd, to); | ||
| 2741 | putname(to); | ||
| 2742 | } | ||
| 2743 | putname(from); | 2719 | putname(from); |
| 2720 | exit: | ||
| 2744 | return error; | 2721 | return error; |
| 2745 | } | 2722 | } |
| 2746 | 2723 | ||
