Patch "tmpfs,ceph,gfs2,isofs,reiserfs,xfs: fix fh_len checking" has been added to the 3.0-stable tree
Subsystems (7)
This is a note to let you know that I've just added the patch titled
tmpfs,ceph,gfs2,isofs,reiserfs,xfs: fix fh_len checking
to the 3.0-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
tmpfs-ceph-gfs2-isofs-reiserfs-xfs-fix-fh_len-checking.patch
and it can be found in the queue-3.0 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
35c2a7f4908d404c9124c2efc6ada4640ca4d5d5Mon Sep 17 00:00:00 2001
From: Hugh Dickins <[email protected]>
Date: Sun, 7 Oct 2012 20:32:51 -0700
Subject: tmpfs,ceph,gfs2,isofs,reiserfs,xfs: fix fh_len checking
From: Hugh Dickins <[email protected]>
commit 35c2a7f4908d404c9124c2efc6ada4640ca4d5d5 upstream.
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.
--- fs/ceph/export.c | 18 ++++++++++++++---- fs/gfs2/export.c | 4 ++++ fs/isofs/export.c | 2 +- fs/reiserfs/inode.c | 6 +++++- fs/xfs/linux-2.6/xfs_export.c | 3 +++ mm/shmem.c | 6 ++++-- 6 files changed, 31 insertions(+), 8 deletions(-)
fs/ceph/export.c +14 -4
@@ -84,7 +84,7 @@ static int ceph_encode_fh(struct dentry* FIXME: we should try harder by querying the mds for the ino. */ static struct dentry *__fh_to_dentry (struct super_block *sb, -struct ceph_nfs_fh *fh) +struct ceph_nfs_fh *fh,int fh_len) {struct ceph_mds_client *mdsc =ceph_sb_to_client (sb)->mdsc;struct inode *inode;
@@ -92,6 +92,9 @@ static struct dentry *__fh_to_dentry(strstruct ceph_vino vino;int err; +if (fh_len <sizeof (*fh) /4 ) +return ERR_PTR (-ESTALE ); +dout ("__fh_to_dentry %llx\n" , fh->ino); vino.ino = fh->ino; vino.snap =CEPH_NOSNAP ;
@@ -136,7 +139,7 @@ static struct dentry *__fh_to_dentry(str* convert connectable fh to dentry */ static struct dentry *__cfh_to_dentry (struct super_block *sb, -struct ceph_nfs_confh *cfh) +struct ceph_nfs_confh *cfh,int fh_len) {struct ceph_mds_client *mdsc =ceph_sb_to_client (sb)->mdsc;struct inode *inode;
@@ -144,6 +147,9 @@ static struct dentry *__cfh_to_dentry(ststruct ceph_vino vino;int err; +if (fh_len <sizeof (*cfh) /4 ) +return ERR_PTR (-ESTALE ); +dout ("__cfh_to_dentry %llx (%llx/%x)\n" , cfh->ino, cfh->parent_ino, cfh->parent_name_hash);
@@ -193,9 +199,11 @@ static struct dentry *ceph_fh_to_dentry( int fh_len, int fh_type) {if (fh_type ==1 ) -return __fh_to_dentry (sb, (struct ceph_nfs_fh *)fid->raw); +return __fh_to_dentry (sb, (struct ceph_nfs_fh *)fid->raw, + fh_len);else -return __cfh_to_dentry (sb, (struct ceph_nfs_confh *)fid->raw); +return __cfh_to_dentry (sb, (struct ceph_nfs_confh *)fid->raw, + fh_len); }/*
@@ -216,6 +224,8 @@ static struct dentry *ceph_fh_to_parent(if (fh_type ==1 )return ERR_PTR (-ESTALE ); +if (fh_len <sizeof (*cfh) /4 ) +return ERR_PTR (-ESTALE );pr_debug ("fh_to_parent %llx/%d\n" , cfh->parent_ino, cfh->parent_name_hash);
fs/gfs2/export.c +4 -0
@@ -167,6 +167,8 @@ static struct dentry *gfs2_fh_to_dentry(case GFS2_SMALL_FH_SIZE :case GFS2_LARGE_FH_SIZE :case GFS2_OLD_FH_SIZE : +if (fh_len <GFS2_SMALL_FH_SIZE ) +return NULL ; this.no_formal_ino = ((u64 )be32_to_cpu (fh[0 ])) <<32 ; this.no_formal_ino |=be32_to_cpu (fh[1 ]); this.no_addr = ((u64 )be32_to_cpu (fh[2 ])) <<32 ;
@@ -186,6 +188,8 @@ static struct dentry *gfs2_fh_to_parent(switch (fh_type) {case GFS2_LARGE_FH_SIZE :case GFS2_OLD_FH_SIZE : +if (fh_len <GFS2_LARGE_FH_SIZE ) +return NULL ; parent.no_formal_ino = ((u64 )be32_to_cpu (fh[4 ])) <<32 ; parent.no_formal_ino |=be32_to_cpu (fh[5 ]); parent.no_addr = ((u64 )be32_to_cpu (fh[6 ])) <<32 ;
fs/isofs/export.c +1 -1
@@ -179,7 +179,7 @@ static struct dentry *isofs_fh_to_parent {struct isofs_fid *ifid = (struct isofs_fid *)fid; -if (fh_type !=2 ) +if (fh_len <2 || fh_type !=2 )return NULL ; return isofs_export_iget(sb,
fs/reiserfs/inode.c +5 -1
@@ -1568,8 +1568,10 @@ struct dentry *reiserfs_fh_to_dentry(strreiserfs_warning (sb,"reiserfs-13077" ,"nfsd/reiserfs, fhtype=%d, len=%d - odd" , fh_type, fh_len); - fh_type =5 ; + fh_type = fh_len; } +if (fh_len <2 ) +return NULL ;return reiserfs_get_dentry (sb, fid->raw[0 ], fid->raw[1 ], (fh_type ==3 || fh_type >=5 ) ? fid->raw[2 ] :0 );
@@ -1578,6 +1580,8 @@ struct dentry *reiserfs_fh_to_dentry(strstruct dentry *reiserfs_fh_to_parent (struct super_block *sb,struct fid *fid,int fh_len,int fh_type) { +if (fh_type > fh_len) + fh_type = fh_len;if (fh_type <4 )return NULL ;
fs/xfs/linux-2.6/xfs_export.c +3 -0
@@ -195,6 +195,9 @@ xfs_fs_fh_to_parent(struct super_block *struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid;struct inode *inode =NULL ; +if (fh_len <xfs_fileid_length (fileid_type)) +return NULL ; +switch (fileid_type) {case FILEID_INO32_GEN_PARENT : inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino,
mm/shmem.c +4 -2
@@ -2348,12 +2348,14 @@ static struct dentry *shmem_fh_to_dentry {struct inode *inode;struct dentry *dentry =NULL ; -u64 inum = fid->raw[2 ]; - inum = (inum <<32 ) | fid->raw[1 ]; +u64 inum;if (fh_len <3 )return NULL ; + inum = fid->raw[2 ]; + inum = (inum <<32 ) | fid->raw[1 ]; + inode =ilookup5 (sb, (unsigned long )(inum + fid->raw[0 ]), shmem_match, fid->raw);if (inode) {
Patches currently in stable-queue which might be from [email protected] are
queue-3.0/tmpfs-ceph-gfs2-isofs-reiserfs-xfs-fix-fh_len-checking.patch