aboutsummaryrefslogtreecommitdiffstats
path: root/fs/reiserfs
diff options
context:
space:
mode:
authorHugh Dickins <hughd@google.com>2012-10-07 23:32:51 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-10-09 23:33:55 -0400
commit35c2a7f4908d404c9124c2efc6ada4640ca4d5d5 (patch)
tree4ef3fa1953b939fb4bfff935b3d351f76d97252b /fs/reiserfs
parent8e22cc88d68ca1a46d7d582938f979eb640ed30f (diff)
tmpfs,ceph,gfs2,isofs,reiserfs,xfs: fix fh_len checking
Fuzzing with trinity oopsed on the 1st instruction of shmem_fh_to_dentry(), u64 inum = fid->raw[2]; which is unhelpfully reported as at the end of shmem_alloc_inode(): BUG: unable to handle kernel paging request at ffff880061cd3000 IP: [<ffffffff812190d0>] shmem_alloc_inode+0x40/0x40 Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC Call Trace: [<ffffffff81488649>] ? exportfs_decode_fh+0x79/0x2d0 [<ffffffff812d77c3>] do_handle_open+0x163/0x2c0 [<ffffffff812d792c>] sys_open_by_handle_at+0xc/0x10 [<ffffffff83a5f3f8>] tracesys+0xe1/0xe6 Right, tmpfs is being stupid to access fid->raw[2] before validating that fh_len includes it: the buffer kmalloc'ed by do_sys_name_to_handle() may fall at the end of a page, and the next page not be present. But some other filesystems (ceph, gfs2, isofs, reiserfs, xfs) are being careless about fh_len too, in fh_to_dentry() and/or fh_to_parent(), and could oops in the same way: add the missing fh_len checks to those. Reported-by: Sasha Levin <levinsasha928@gmail.com> Signed-off-by: Hugh Dickins <hughd@google.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Sage Weil <sage@inktank.com> Cc: Steven Whitehouse <swhiteho@redhat.com> Cc: Christoph Hellwig <hch@infradead.org> Cc: stable@vger.kernel.org Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/reiserfs')
-rw-r--r--fs/reiserfs/inode.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 46485557cdc6..f27f01a98aa2 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -1573,8 +1573,10 @@ struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
1573 reiserfs_warning(sb, "reiserfs-13077", 1573 reiserfs_warning(sb, "reiserfs-13077",
1574 "nfsd/reiserfs, fhtype=%d, len=%d - odd", 1574 "nfsd/reiserfs, fhtype=%d, len=%d - odd",
1575 fh_type, fh_len); 1575 fh_type, fh_len);
1576 fh_type = 5; 1576 fh_type = fh_len;
1577 } 1577 }
1578 if (fh_len < 2)
1579 return NULL;
1578 1580
1579 return reiserfs_get_dentry(sb, fid->raw[0], fid->raw[1], 1581 return reiserfs_get_dentry(sb, fid->raw[0], fid->raw[1],
1580 (fh_type == 3 || fh_type >= 5) ? fid->raw[2] : 0); 1582 (fh_type == 3 || fh_type >= 5) ? fid->raw[2] : 0);
@@ -1583,6 +1585,8 @@ struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,
1583struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid, 1585struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid,
1584 int fh_len, int fh_type) 1586 int fh_len, int fh_type)
1585{ 1587{
1588 if (fh_type > fh_len)
1589 fh_type = fh_len;
1586 if (fh_type < 4) 1590 if (fh_type < 4)
1587 return NULL; 1591 return NULL;
1588 1592