aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r--fs/fuse/dir.c37
1 files changed, 25 insertions, 12 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index c045cc70c749..51f5da652771 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -74,6 +74,24 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
74 return 1; 74 return 1;
75} 75}
76 76
77static int dir_alias(struct inode *inode)
78{
79 if (S_ISDIR(inode->i_mode)) {
80 /* Don't allow creating an alias to a directory */
81 struct dentry *alias = d_find_alias(inode);
82 if (alias) {
83 dput(alias);
84 return 1;
85 }
86 }
87 return 0;
88}
89
90static inline int invalid_nodeid(u64 nodeid)
91{
92 return !nodeid || nodeid == FUSE_ROOT_ID;
93}
94
77static struct dentry_operations fuse_dentry_operations = { 95static struct dentry_operations fuse_dentry_operations = {
78 .d_revalidate = fuse_dentry_revalidate, 96 .d_revalidate = fuse_dentry_revalidate,
79}; 97};
@@ -97,7 +115,7 @@ static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
97 fuse_lookup_init(req, dir, entry, &outarg); 115 fuse_lookup_init(req, dir, entry, &outarg);
98 request_send(fc, req); 116 request_send(fc, req);
99 err = req->out.h.error; 117 err = req->out.h.error;
100 if (!err && (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID)) 118 if (!err && invalid_nodeid(outarg.nodeid))
101 err = -EIO; 119 err = -EIO;
102 if (!err) { 120 if (!err) {
103 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 121 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
@@ -193,7 +211,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
193 } 211 }
194 212
195 err = -EIO; 213 err = -EIO;
196 if (!S_ISREG(outentry.attr.mode)) 214 if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
197 goto out_free_ff; 215 goto out_free_ff;
198 216
199 inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, 217 inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
@@ -250,7 +268,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
250 fuse_put_request(fc, req); 268 fuse_put_request(fc, req);
251 return err; 269 return err;
252 } 270 }
253 if (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID) { 271 if (invalid_nodeid(outarg.nodeid)) {
254 fuse_put_request(fc, req); 272 fuse_put_request(fc, req);
255 return -EIO; 273 return -EIO;
256 } 274 }
@@ -263,7 +281,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
263 fuse_put_request(fc, req); 281 fuse_put_request(fc, req);
264 282
265 /* Don't allow userspace to do really stupid things... */ 283 /* Don't allow userspace to do really stupid things... */
266 if ((inode->i_mode ^ mode) & S_IFMT) { 284 if (((inode->i_mode ^ mode) & S_IFMT) || dir_alias(inode)) {
267 iput(inode); 285 iput(inode);
268 return -EIO; 286 return -EIO;
269 } 287 }
@@ -874,14 +892,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
874 err = fuse_lookup_iget(dir, entry, &inode); 892 err = fuse_lookup_iget(dir, entry, &inode);
875 if (err) 893 if (err)
876 return ERR_PTR(err); 894 return ERR_PTR(err);
877 if (inode && S_ISDIR(inode->i_mode)) { 895 if (inode && dir_alias(inode)) {
878 /* Don't allow creating an alias to a directory */ 896 iput(inode);
879 struct dentry *alias = d_find_alias(inode); 897 return ERR_PTR(-EIO);
880 if (alias) {
881 dput(alias);
882 iput(inode);
883 return ERR_PTR(-EIO);
884 }
885 } 898 }
886 d_add(entry, inode); 899 d_add(entry, inode);
887 return NULL; 900 return NULL;