diff options
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index f156392d019e..417bcee466f6 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -166,6 +166,12 @@ static struct dentry_operations fuse_dentry_operations = { | |||
166 | .d_revalidate = fuse_dentry_revalidate, | 166 | .d_revalidate = fuse_dentry_revalidate, |
167 | }; | 167 | }; |
168 | 168 | ||
169 | static inline int valid_mode(int m) | ||
170 | { | ||
171 | return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) || | ||
172 | S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); | ||
173 | } | ||
174 | |||
169 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | 175 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, |
170 | struct nameidata *nd) | 176 | struct nameidata *nd) |
171 | { | 177 | { |
@@ -185,7 +191,8 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
185 | fuse_lookup_init(req, dir, entry, &outarg); | 191 | fuse_lookup_init(req, dir, entry, &outarg); |
186 | request_send(fc, req); | 192 | request_send(fc, req); |
187 | err = req->out.h.error; | 193 | err = req->out.h.error; |
188 | if (!err && outarg.nodeid && invalid_nodeid(outarg.nodeid)) | 194 | if (!err && ((outarg.nodeid && invalid_nodeid(outarg.nodeid)) || |
195 | !valid_mode(outarg.attr.mode))) | ||
189 | err = -EIO; | 196 | err = -EIO; |
190 | if (!err && outarg.nodeid) { | 197 | if (!err && outarg.nodeid) { |
191 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 198 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
@@ -328,10 +335,13 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
328 | fuse_put_request(fc, req); | 335 | fuse_put_request(fc, req); |
329 | return err; | 336 | return err; |
330 | } | 337 | } |
331 | if (invalid_nodeid(outarg.nodeid)) { | 338 | err = -EIO; |
332 | fuse_put_request(fc, req); | 339 | if (invalid_nodeid(outarg.nodeid)) |
333 | return -EIO; | 340 | goto out_put_request; |
334 | } | 341 | |
342 | if ((outarg.attr.mode ^ mode) & S_IFMT) | ||
343 | goto out_put_request; | ||
344 | |||
335 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 345 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
336 | &outarg.attr); | 346 | &outarg.attr); |
337 | if (!inode) { | 347 | if (!inode) { |
@@ -340,8 +350,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
340 | } | 350 | } |
341 | fuse_put_request(fc, req); | 351 | fuse_put_request(fc, req); |
342 | 352 | ||
343 | /* Don't allow userspace to do really stupid things... */ | 353 | if (dir_alias(inode)) { |
344 | if (((inode->i_mode ^ mode) & S_IFMT) || dir_alias(inode)) { | ||
345 | iput(inode); | 354 | iput(inode); |
346 | return -EIO; | 355 | return -EIO; |
347 | } | 356 | } |
@@ -350,6 +359,10 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
350 | fuse_change_timeout(entry, &outarg); | 359 | fuse_change_timeout(entry, &outarg); |
351 | fuse_invalidate_attr(dir); | 360 | fuse_invalidate_attr(dir); |
352 | return 0; | 361 | return 0; |
362 | |||
363 | out_put_request: | ||
364 | fuse_put_request(fc, req); | ||
365 | return err; | ||
353 | } | 366 | } |
354 | 367 | ||
355 | static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, | 368 | static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, |