Commit 39ee059affaf57a152c64cd3a0adc3f48f02ed71

Authored by Miklos Szeredi
Committed by Linus Torvalds
1 parent 6ad84acab9

[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

... ... @@ -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,
... ... @@ -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)