diff options
Diffstat (limited to 'fs/namei.c')
-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 | ||