Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/ufs/ffs We need to check if the inode is initialized for...



details:   https://anonhg.NetBSD.org/src/rev/0a978293a9b6
branches:  trunk
changeset: 812619:0a978293a9b6
user:      christos <christos%NetBSD.org@localhost>
date:      Wed Dec 23 23:31:28 2015 +0000

description:
We need to check if the inode is initialized for ffsv2 when we translate a
filehandle to a vnode. This can come from nfs and it could be out of range.
In that case we read garbage from the disk, end up trying to free bogus data
when we put the vnode back and we crash.
XXX: pullup-7

diffstat:

 sys/ufs/ffs/ffs_vfsops.c |  61 ++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 54 insertions(+), 7 deletions(-)

diffs (94 lines):

diff -r a6f1400d1ced -r 0a978293a9b6 sys/ufs/ffs/ffs_vfsops.c
--- a/sys/ufs/ffs/ffs_vfsops.c  Wed Dec 23 18:42:23 2015 +0000
+++ b/sys/ufs/ffs/ffs_vfsops.c  Wed Dec 23 23:31:28 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ffs_vfsops.c,v 1.337 2015/11/15 01:39:23 pgoyette Exp $        */
+/*     $NetBSD: ffs_vfsops.c,v 1.338 2015/12/23 23:31:28 christos Exp $        */
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.337 2015/11/15 01:39:23 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.338 2015/12/23 23:31:28 christos Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ffs.h"
@@ -192,6 +192,54 @@
 };
 
 static int
+ffs_checkrange(struct mount *mp, uint32_t ino)
+{
+       struct fs *fs = VFSTOUFS(mp)->um_fs;
+
+       if (ino < UFS_ROOTINO || ino >= fs->fs_ncg * fs->fs_ipg) {
+               DPRINTF("out of range %u\n", ino);
+               return ESTALE;
+       }
+
+       /*
+        * Need to check if inode is initialized because ffsv2 does 
+        * lazy initialization and we can get here from nfs_fhtovp
+        */
+       if (fs->fs_magic != FS_UFS2_MAGIC)
+               return 0;
+
+       struct buf *bp;
+       int cg = ino_to_cg(fs, ino);
+       struct ufsmount *ump = VFSTOUFS(mp);
+
+       int error = bread(ump->um_devvp, FFS_FSBTODB(fs, cgtod(fs, cg)),
+           (int)fs->fs_cgsize, B_MODIFY, &bp);
+       if (error) {
+               DPRINTF("error %d reading cg %d ino %u\n", error, cg, ino);
+               return error;
+       }
+
+       const int needswap = UFS_FSNEEDSWAP(fs);
+
+       struct cg *cgp = (struct cg *)bp->b_data;
+       if (!cg_chkmagic(cgp, needswap)) {
+               brelse(bp, 0);
+               DPRINTF("bad cylinder group magic cg %d ino %u\n", cg, ino);
+               return ESTALE;
+       }
+
+       int32_t initediblk = ufs_rw32(cgp->cg_initediblk, needswap);
+       brelse(bp, 0);
+
+       if (cg * fs->fs_ipg + initediblk < ino) {
+               DPRINTF("cg=%d fs->fs_ipg=%d initediblk=%d ino=%u\n",
+                   cg, fs->fs_ipg, initediblk, ino);
+               return ESTALE;
+       }
+       return 0;
+}
+
+static int
 ffs_snapshot_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
     void *arg0, void *arg1, void *arg2, void *arg3)
 {
@@ -2181,16 +2229,15 @@
 ffs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
 {
        struct ufid ufh;
-       struct fs *fs;
+       int error;
 
        if (fhp->fid_len != sizeof(struct ufid))
                return EINVAL;
 
        memcpy(&ufh, fhp, sizeof(ufh));
-       fs = VFSTOUFS(mp)->um_fs;
-       if (ufh.ufid_ino < UFS_ROOTINO ||
-           ufh.ufid_ino >= fs->fs_ncg * fs->fs_ipg)
-               return (ESTALE);
+       if ((error = ffs_checkrange(mp, ufh.ufid_ino)) != 0)
+               return error;
+
        return (ufs_fhtovp(mp, &ufh, vpp));
 }
 



Home | Main Index | Thread Index | Old Index