[PATCH] knfsd: Have ext2 reject file handles with bad inode numbers early
authorNeilBrown <neilb@suse.de>
Sat, 16 Sep 2006 19:15:37 +0000 (12:15 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Sat, 16 Sep 2006 19:54:30 +0000 (12:54 -0700)
This prevents bad inode numbers from triggering errors in ext2_get_inode.

[akpm@osdl.org: speedup, cleanup]
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/ext2/super.c

index 681dea8f9532ee744932bdc6fa9762360d892b45..ca5bfb6914d269afa7106c5a569a3aa80f666f72 100644 (file)
@@ -251,6 +251,44 @@ static struct super_operations ext2_sops = {
 #endif
 };
 
+static struct dentry *ext2_get_dentry(struct super_block *sb, void *vobjp)
+{
+       __u32 *objp = vobjp;
+       unsigned long ino = objp[0];
+       __u32 generation = objp[1];
+       struct inode *inode;
+       struct dentry *result;
+
+       if (ino < EXT2_FIRST_INO(sb) && ino != EXT2_ROOT_INO)
+               return ERR_PTR(-ESTALE);
+       if (ino > le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count))
+               return ERR_PTR(-ESTALE);
+
+       /* iget isn't really right if the inode is currently unallocated!!
+        * ext2_read_inode currently does appropriate checks, but
+        * it might be "neater" to call ext2_get_inode first and check
+        * if the inode is valid.....
+        */
+       inode = iget(sb, ino);
+       if (inode == NULL)
+               return ERR_PTR(-ENOMEM);
+       if (is_bad_inode(inode) ||
+           (generation && inode->i_generation != generation)) {
+               /* we didn't find the right inode.. */
+               iput(inode);
+               return ERR_PTR(-ESTALE);
+       }
+       /* now to find a dentry.
+        * If possible, get a well-connected one
+        */
+       result = d_alloc_anon(inode);
+       if (!result) {
+               iput(inode);
+               return ERR_PTR(-ENOMEM);
+       }
+       return result;
+}
+
 /* Yes, most of these are left as NULL!!
  * A NULL value implies the default, which works with ext2-like file
  * systems, but can be improved upon.
@@ -258,6 +296,7 @@ static struct super_operations ext2_sops = {
  */
 static struct export_operations ext2_export_ops = {
        .get_parent = ext2_get_parent,
+       .get_dentry = ext2_get_dentry,
 };
 
 static unsigned long get_sb_block(void **data)