From owner-svn-src-head@freebsd.org Wed Jan 27 21:27:07 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 2B1B0A705B1; Wed, 27 Jan 2016 21:27:07 +0000 (UTC) (envelope-from mckusick@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id D3ED117E8; Wed, 27 Jan 2016 21:27:06 +0000 (UTC) (envelope-from mckusick@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u0RLR5AA002053; Wed, 27 Jan 2016 21:27:05 GMT (envelope-from mckusick@FreeBSD.org) Received: (from mckusick@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u0RLR5Ef002052; Wed, 27 Jan 2016 21:27:05 GMT (envelope-from mckusick@FreeBSD.org) Message-Id: <201601272127.u0RLR5Ef002052@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mckusick set sender to mckusick@FreeBSD.org using -f From: Kirk McKusick Date: Wed, 27 Jan 2016 21:27:05 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r294956 - head/sys/ufs/ffs X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 27 Jan 2016 21:27:07 -0000 Author: mckusick Date: Wed Jan 27 21:27:05 2016 New Revision: 294956 URL: https://svnweb.freebsd.org/changeset/base/294956 Log: This fixes a bug in UFS2 exported NFS volumes. An NFS client can crash a server that has exported UFS2 by presenting a filehandle with an inode number that references an uninitialized inode in a cylinder group. The problem is that UFS2 only initializes blocks of inodes as they are first allocated and ffs_fhtovp() does not validate that the inode is in a range of inodes that have been initialized. Attempting to read an uninitialized inode gets random data from the disk. When the kernel tries to interpret it as an inode, panics often arise. Reported by: Christos Zoulas (from NetBSD) Reviewed by: kib Modified: head/sys/ufs/ffs/ffs_vfsops.c Modified: head/sys/ufs/ffs/ffs_vfsops.c ============================================================================== --- head/sys/ufs/ffs/ffs_vfsops.c Wed Jan 27 21:24:45 2016 (r294955) +++ head/sys/ufs/ffs/ffs_vfsops.c Wed Jan 27 21:27:05 2016 (r294956) @@ -1797,6 +1797,7 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags * * Have to be really careful about stale file handles: * - check that the inode number is valid + * - for UFS2 check that the inode number is initialized * - call ffs_vget() to get the locked inode * - check for an unallocated inode (i_mode == 0) * - check that the given client host has export rights and return @@ -1810,13 +1811,37 @@ ffs_fhtovp(mp, fhp, flags, vpp) struct vnode **vpp; { struct ufid *ufhp; + struct ufsmount *ump; struct fs *fs; + struct cg *cgp; + struct buf *bp; + ino_t ino; + u_int cg; + int error; ufhp = (struct ufid *)fhp; - fs = VFSTOUFS(mp)->um_fs; - if (ufhp->ufid_ino < ROOTINO || - ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) + ino = ufhp->ufid_ino; + ump = VFSTOUFS(mp); + fs = ump->um_fs; + if (ino < ROOTINO || ino >= fs->fs_ncg * fs->fs_ipg) + return (ESTALE); + /* + * Need to check if inode is initialized because UFS2 does lazy + * initialization and nfs_fhtovp can offer arbitrary inode numbers. + */ + if (fs->fs_magic != FS_UFS2_MAGIC) + return (ufs_fhtovp(mp, ufhp, flags, vpp)); + cg = ino_to_cg(fs, ino); + error = bread(ump->um_devvp, fsbtodb(fs, cgtod(fs, cg)), + (int)fs->fs_cgsize, NOCRED, &bp); + if (error) + return (error); + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic(cgp) || ino >= cg * fs->fs_ipg + cgp->cg_initediblk) { + brelse(bp); return (ESTALE); + } + brelse(bp); return (ufs_fhtovp(mp, ufhp, flags, vpp)); }