aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-03-13 16:42:14 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2011-03-15 02:21:45 -0400
commitbcda76524cd1fa32af748536f27f674a13e56700 (patch)
tree37dbc7fb50b515f3dff820e14d92e768fb1cda31 /fs/namei.c
parent1abf0c718f15a56a0a435588d1b104c7a37dc9bd (diff)
Allow O_PATH for symlinks
At that point we can't do almost nothing with them. They can be opened with O_PATH, we can manipulate such descriptors with dup(), etc. and we can see them in /proc/*/{fd,fdinfo}/*. We can't (and won't be able to) follow /proc/*/fd/* symlinks for those; there's simply not enough information for pathname resolution to go on from such point - to resolve a symlink we need to know which directory does it live in. We will be able to do useful things with them after the next commit, though - readlinkat() and fchownat() will be possible to use with dfd being an O_PATH-opened symlink and empty relative pathname. Combined with open_by_handle() it'll give us a way to do realink-by-handle and lchown-by-handle without messing with more redundant syscalls. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/fs/namei.c b/fs/namei.c
index e1d9f90d9776..9d4f32700179 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -766,8 +766,14 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p)
766 error = 0; 766 error = 0;
767 if (s) 767 if (s)
768 error = __vfs_follow_link(nd, s); 768 error = __vfs_follow_link(nd, s);
769 else if (nd->last_type == LAST_BIND) 769 else if (nd->last_type == LAST_BIND) {
770 nd->flags |= LOOKUP_JUMPED; 770 nd->flags |= LOOKUP_JUMPED;
771 if (nd->path.dentry->d_inode->i_op->follow_link) {
772 /* stepped on a _really_ weird one */
773 path_put(&nd->path);
774 error = -ELOOP;
775 }
776 }
771 } 777 }
772 return error; 778 return error;
773} 779}
@@ -1954,6 +1960,10 @@ static int may_open(struct path *path, int acc_mode, int flag)
1954 struct inode *inode = dentry->d_inode; 1960 struct inode *inode = dentry->d_inode;
1955 int error; 1961 int error;
1956 1962
1963 /* O_PATH? */
1964 if (!acc_mode)
1965 return 0;
1966
1957 if (!inode) 1967 if (!inode)
1958 return -ENOENT; 1968 return -ENOENT;
1959 1969
@@ -2056,7 +2066,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
2056 int open_flag = op->open_flag; 2066 int open_flag = op->open_flag;
2057 int will_truncate = open_flag & O_TRUNC; 2067 int will_truncate = open_flag & O_TRUNC;
2058 int want_write = 0; 2068 int want_write = 0;
2059 int skip_perm = 0; 2069 int acc_mode = op->acc_mode;
2060 struct file *filp; 2070 struct file *filp;
2061 struct inode *inode; 2071 struct inode *inode;
2062 int error; 2072 int error;
@@ -2095,8 +2105,11 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
2095 } 2105 }
2096 2106
2097 if (!(open_flag & O_CREAT)) { 2107 if (!(open_flag & O_CREAT)) {
2108 int symlink_ok = 0;
2098 if (nd->last.name[nd->last.len]) 2109 if (nd->last.name[nd->last.len])
2099 nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; 2110 nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
2111 if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW))
2112 symlink_ok = 1;
2100 /* we _can_ be in RCU mode here */ 2113 /* we _can_ be in RCU mode here */
2101 error = do_lookup(nd, &nd->last, path, &inode); 2114 error = do_lookup(nd, &nd->last, path, &inode);
2102 if (error) { 2115 if (error) {
@@ -2108,7 +2121,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
2108 terminate_walk(nd); 2121 terminate_walk(nd);
2109 return ERR_PTR(-ENOENT); 2122 return ERR_PTR(-ENOENT);
2110 } 2123 }
2111 if (unlikely(inode->i_op->follow_link)) { 2124 if (unlikely(inode->i_op->follow_link && !symlink_ok)) {
2112 /* We drop rcu-walk here */ 2125 /* We drop rcu-walk here */
2113 if (nameidata_dentry_drop_rcu_maybe(nd, path->dentry)) 2126 if (nameidata_dentry_drop_rcu_maybe(nd, path->dentry))
2114 return ERR_PTR(-ECHILD); 2127 return ERR_PTR(-ECHILD);
@@ -2175,7 +2188,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
2175 /* Don't check for write permission, don't truncate */ 2188 /* Don't check for write permission, don't truncate */
2176 open_flag &= ~O_TRUNC; 2189 open_flag &= ~O_TRUNC;
2177 will_truncate = 0; 2190 will_truncate = 0;
2178 skip_perm = 1; 2191 acc_mode = MAY_OPEN;
2179 error = security_path_mknod(&nd->path, dentry, mode, 0); 2192 error = security_path_mknod(&nd->path, dentry, mode, 0);
2180 if (error) 2193 if (error)
2181 goto exit_mutex_unlock; 2194 goto exit_mutex_unlock;
@@ -2225,7 +2238,7 @@ ok:
2225 want_write = 1; 2238 want_write = 1;
2226 } 2239 }
2227common: 2240common:
2228 error = may_open(&nd->path, skip_perm ? 0 : op->acc_mode, open_flag); 2241 error = may_open(&nd->path, acc_mode, open_flag);
2229 if (error) 2242 if (error)
2230 goto exit; 2243 goto exit;
2231 filp = nameidata_to_filp(nd); 2244 filp = nameidata_to_filp(nd);
@@ -2358,7 +2371,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
2358 2371
2359 flags |= LOOKUP_ROOT; 2372 flags |= LOOKUP_ROOT;
2360 2373
2361 if (dentry->d_inode->i_op->follow_link) 2374 if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN)
2362 return ERR_PTR(-ELOOP); 2375 return ERR_PTR(-ELOOP);
2363 2376
2364 file = path_openat(-1, name, &nd, op, flags | LOOKUP_RCU); 2377 file = path_openat(-1, name, &nd, op, flags | LOOKUP_RCU);