Commit 39ee059affaf57a152c64cd3a0adc3f48f02ed71
Committed by
Linus Torvalds
1 parent
6ad84acab9
Exists in
master
and in
7 other branches
[PATCH] fuse: check file type in lookup
Previously invalid types were quietly changed to regular files, but at revalidation the inode was changed to bad. This was rather inconsistent behavior. Now check if the type is valid on initial lookup, and return -EIO if not. Signed-off-by: Miklos Szeredi <miklos@szeredi.hu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 2 changed files with 22 additions and 13 deletions Side-by-side Diff
fs/fuse/dir.c
... | ... | @@ -166,6 +166,12 @@ |
166 | 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 | 175 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, |
170 | 176 | struct nameidata *nd) |
171 | 177 | { |
... | ... | @@ -185,7 +191,8 @@ |
185 | 191 | fuse_lookup_init(req, dir, entry, &outarg); |
186 | 192 | request_send(fc, req); |
187 | 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 | 196 | err = -EIO; |
190 | 197 | if (!err && outarg.nodeid) { |
191 | 198 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
... | ... | @@ -328,10 +335,13 @@ |
328 | 335 | fuse_put_request(fc, req); |
329 | 336 | return err; |
330 | 337 | } |
331 | - if (invalid_nodeid(outarg.nodeid)) { | |
332 | - fuse_put_request(fc, req); | |
333 | - return -EIO; | |
334 | - } | |
338 | + err = -EIO; | |
339 | + if (invalid_nodeid(outarg.nodeid)) | |
340 | + goto out_put_request; | |
341 | + | |
342 | + if ((outarg.attr.mode ^ mode) & S_IFMT) | |
343 | + goto out_put_request; | |
344 | + | |
335 | 345 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
336 | 346 | &outarg.attr); |
337 | 347 | if (!inode) { |
... | ... | @@ -340,8 +350,7 @@ |
340 | 350 | } |
341 | 351 | fuse_put_request(fc, req); |
342 | 352 | |
343 | - /* Don't allow userspace to do really stupid things... */ | |
344 | - if (((inode->i_mode ^ mode) & S_IFMT) || dir_alias(inode)) { | |
353 | + if (dir_alias(inode)) { | |
345 | 354 | iput(inode); |
346 | 355 | return -EIO; |
347 | 356 | } |
... | ... | @@ -350,6 +359,10 @@ |
350 | 359 | fuse_change_timeout(entry, &outarg); |
351 | 360 | fuse_invalidate_attr(dir); |
352 | 361 | return 0; |
362 | + | |
363 | + out_put_request: | |
364 | + fuse_put_request(fc, req); | |
365 | + return err; | |
353 | 366 | } |
354 | 367 | |
355 | 368 | static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode, |
fs/fuse/inode.c
... | ... | @@ -135,12 +135,8 @@ |
135 | 135 | fuse_init_common(inode); |
136 | 136 | init_special_inode(inode, inode->i_mode, |
137 | 137 | new_decode_dev(attr->rdev)); |
138 | - } else { | |
139 | - /* Don't let user create weird files */ | |
140 | - inode->i_mode = S_IFREG; | |
141 | - fuse_init_common(inode); | |
142 | - fuse_init_file_inode(inode); | |
143 | - } | |
138 | + } else | |
139 | + BUG(); | |
144 | 140 | } |
145 | 141 | |
146 | 142 | static int fuse_inode_eq(struct inode *inode, void *_nodeidp) |