Author: mckusick
Date: Wed Jul 31 00:16:12 2019
New Revision: 350460
URL: https://svnweb.freebsd.org/changeset/base/350460

Log:
  MFC of 349589, 350070, 350071, 350096, and 350187
  
  Make filesystem-full messages limited per filesystem rather than systemwide
  Add "untrusted" option to mount command
  FS-14-UFS-3: when untrusted, valididate block pointers
  In fsck_ffs, treat any inode with bad content as unknown

Modified:
  stable/12/sbin/fsck_ffs/pass1.c
  stable/12/sbin/mount/mntopts.h
  stable/12/sbin/mount/mount.8
  stable/12/sbin/mount/mount.c
  stable/12/sys/sys/mount.h
  stable/12/sys/ufs/ffs/ffs_alloc.c
  stable/12/sys/ufs/ffs/ffs_balloc.c
  stable/12/sys/ufs/ffs/ffs_extern.h
  stable/12/sys/ufs/ffs/ffs_softdep.c
  stable/12/sys/ufs/ffs/ffs_subr.c
  stable/12/sys/ufs/ffs/ffs_vfsops.c
  stable/12/sys/ufs/ufs/ufs_bmap.c
  stable/12/sys/ufs/ufs/ufsmount.h
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sbin/fsck_ffs/pass1.c
==============================================================================
--- stable/12/sbin/fsck_ffs/pass1.c     Tue Jul 30 23:50:49 2019        
(r350459)
+++ stable/12/sbin/fsck_ffs/pass1.c     Wed Jul 31 00:16:12 2019        
(r350460)
@@ -251,7 +251,7 @@ checkinode(ino_t inumber, struct inodesc *idesc, int r
        int j, ret, offset;
 
        if ((dp = getnextinode(inumber, rebuildcg)) == NULL)
-               return (0);
+               goto unknown;
        mode = DIP(dp, di_mode) & IFMT;
        if (mode == 0) {
                if ((sblock.fs_magic == FS_UFS1_MAGIC &&

Modified: stable/12/sbin/mount/mntopts.h
==============================================================================
--- stable/12/sbin/mount/mntopts.h      Tue Jul 30 23:50:49 2019        
(r350459)
+++ stable/12/sbin/mount/mntopts.h      Wed Jul 31 00:16:12 2019        
(r350460)
@@ -58,6 +58,7 @@ struct mntopt {
 #define MOPT_ACLS              { "acls",       0, MNT_ACLS, 0 }
 #define MOPT_NFS4ACLS          { "nfsv4acls",  0, MNT_NFS4ACLS, 0 }
 #define MOPT_AUTOMOUNTED       { "automounted",0, MNT_AUTOMOUNTED, 0 }
+#define MOPT_UNTRUSTED         { "untrusted",  0, MNT_UNTRUSTED, 0 }
 
 /* Control flags. */
 #define MOPT_FORCE             { "force",      0, MNT_FORCE, 0 }
@@ -93,7 +94,8 @@ struct mntopt {
        MOPT_MULTILABEL,                                                \
        MOPT_ACLS,                                                      \
        MOPT_NFS4ACLS,                                                  \
-       MOPT_AUTOMOUNTED
+       MOPT_AUTOMOUNTED,                                               \
+       MOPT_UNTRUSTED
 
 void getmntopts(const char *, const struct mntopt *, int *, int *);
 void rmslashes(char *, char *);

Modified: stable/12/sbin/mount/mount.8
==============================================================================
--- stable/12/sbin/mount/mount.8        Tue Jul 30 23:50:49 2019        
(r350459)
+++ stable/12/sbin/mount/mount.8        Wed Jul 31 00:16:12 2019        
(r350460)
@@ -355,6 +355,12 @@ Lookups will be done in the mounted file system first.
 If those operations fail due to a non-existent file the underlying
 directory is then accessed.
 All creates are done in the mounted file system.
+.It Cm untrusted
+The file system is untrusted and the kernel should use more
+extensive checks on the file-system's metadata before using it.
+This option is intended to be used when mounting file systems
+from untrusted media such as USB memory sticks or other
+externally-provided media.
 .El
 .Pp
 Any additional options specific to a file system type that is not

Modified: stable/12/sbin/mount/mount.c
==============================================================================
--- stable/12/sbin/mount/mount.c        Tue Jul 30 23:50:49 2019        
(r350459)
+++ stable/12/sbin/mount/mount.c        Wed Jul 31 00:16:12 2019        
(r350460)
@@ -118,6 +118,7 @@ static struct opt {
        { MNT_GJOURNAL,         "gjournal" },
        { MNT_AUTOMOUNTED,      "automounted" },
        { MNT_VERIFIED,         "verified" },
+       { MNT_UNTRUSTED,        "untrusted" },
        { 0, NULL }
 };
 
@@ -972,6 +973,7 @@ flags2opts(int flags)
        if (flags & MNT_MULTILABEL)     res = catopt(res, "multilabel");
        if (flags & MNT_ACLS)           res = catopt(res, "acls");
        if (flags & MNT_NFS4ACLS)       res = catopt(res, "nfsv4acls");
+       if (flags & MNT_UNTRUSTED)      res = catopt(res, "untrusted");
 
        return (res);
 }

Modified: stable/12/sys/sys/mount.h
==============================================================================
--- stable/12/sys/sys/mount.h   Tue Jul 30 23:50:49 2019        (r350459)
+++ stable/12/sys/sys/mount.h   Wed Jul 31 00:16:12 2019        (r350460)
@@ -296,6 +296,7 @@ void          __mnt_vnode_markerfree_active(struct vno
 #define        MNT_NOCLUSTERW  0x0000000080000000ULL /* disable cluster write 
*/
 #define        MNT_SUJ         0x0000000100000000ULL /* using journaled soft 
updates */
 #define        MNT_AUTOMOUNTED 0x0000000200000000ULL /* mounted by 
automountd(8) */
+#define        MNT_UNTRUSTED   0x0000000800000000ULL /* filesys metadata 
untrusted */
 
 /*
  * NFS export related mount flags.
@@ -333,7 +334,8 @@ void          __mnt_vnode_markerfree_active(struct vno
                        MNT_NOCLUSTERW  | MNT_SUIDDIR   | MNT_SOFTDEP   | \
                        MNT_IGNORE      | MNT_EXPUBLIC  | MNT_NOSYMFOLLOW | \
                        MNT_GJOURNAL    | MNT_MULTILABEL | MNT_ACLS     | \
-                       MNT_NFS4ACLS    | MNT_AUTOMOUNTED | MNT_VERIFIED)
+                       MNT_NFS4ACLS    | MNT_AUTOMOUNTED | MNT_VERIFIED | \
+                       MNT_UNTRUSTED)
 
 /* Mask of flags that can be updated. */
 #define        MNT_UPDATEMASK (MNT_NOSUID      | MNT_NOEXEC    | \
@@ -342,7 +344,7 @@ void          __mnt_vnode_markerfree_active(struct vno
                        MNT_NOSYMFOLLOW | MNT_IGNORE    | \
                        MNT_NOCLUSTERR  | MNT_NOCLUSTERW | MNT_SUIDDIR  | \
                        MNT_ACLS        | MNT_USER      | MNT_NFS4ACLS  | \
-                       MNT_AUTOMOUNTED)
+                       MNT_AUTOMOUNTED | MNT_UNTRUSTED)
 
 /*
  * External filesystem command modifier flags.

Modified: stable/12/sys/ufs/ffs/ffs_alloc.c
==============================================================================
--- stable/12/sys/ufs/ffs/ffs_alloc.c   Tue Jul 30 23:50:49 2019        
(r350459)
+++ stable/12/sys/ufs/ffs/ffs_alloc.c   Wed Jul 31 00:16:12 2019        
(r350460)
@@ -157,8 +157,6 @@ ffs_alloc(ip, lbn, bpref, size, flags, cred, bnp)
        struct ufsmount *ump;
        ufs2_daddr_t bno;
        u_int cg, reclaimed;
-       static struct timeval lastfail;
-       static int curfail;
        int64_t delta;
 #ifdef QUOTA
        int error;
@@ -223,11 +221,14 @@ nospace:
                softdep_request_cleanup(fs, ITOV(ip), cred, FLUSH_BLOCKS_WAIT);
                goto retry;
        }
-       UFS_UNLOCK(ump);
-       if (reclaimed > 0 && ppsratecheck(&lastfail, &curfail, 1)) {
+       if (reclaimed > 0 &&
+           ppsratecheck(&ump->um_last_fullmsg, &ump->um_secs_fullmsg, 1)) {
+               UFS_UNLOCK(ump);
                ffs_fserr(fs, ip->i_number, "filesystem full");
                uprintf("\n%s: write failed, filesystem is full\n",
                    fs->fs_fsmnt);
+       } else {
+               UFS_UNLOCK(ump);
        }
        return (ENOSPC);
 }
@@ -257,8 +258,6 @@ ffs_realloccg(ip, lbprev, bprev, bpref, osize, nsize, 
        u_int cg, request, reclaimed;
        int error, gbflags;
        ufs2_daddr_t bno;
-       static struct timeval lastfail;
-       static int curfail;
        int64_t delta;
 
        vp = ITOV(ip);
@@ -448,14 +447,17 @@ nospace:
                softdep_request_cleanup(fs, vp, cred, FLUSH_BLOCKS_WAIT);
                goto retry;
        }
-       UFS_UNLOCK(ump);
-       if (bp)
-               brelse(bp);
-       if (reclaimed > 0 && ppsratecheck(&lastfail, &curfail, 1)) {
+       if (reclaimed > 0 &&
+           ppsratecheck(&ump->um_last_fullmsg, &ump->um_secs_fullmsg, 1)) {
+               UFS_UNLOCK(ump);
                ffs_fserr(fs, ip->i_number, "filesystem full");
                uprintf("\n%s: write failed, filesystem is full\n",
                    fs->fs_fsmnt);
+       } else {
+               UFS_UNLOCK(ump);
        }
+       if (bp)
+               brelse(bp);
        return (ENOSPC);
 }
 
@@ -1098,8 +1100,6 @@ ffs_valloc(pvp, mode, cred, vpp)
        ino_t ino, ipref;
        u_int cg;
        int error, error1, reclaimed;
-       static struct timeval lastfail;
-       static int curfail;
 
        *vpp = NULL;
        pip = VTOI(pvp);
@@ -1190,11 +1190,13 @@ noinodes:
                softdep_request_cleanup(fs, pvp, cred, FLUSH_INODES_WAIT);
                goto retry;
        }
-       UFS_UNLOCK(ump);
-       if (ppsratecheck(&lastfail, &curfail, 1)) {
+       if (ppsratecheck(&ump->um_last_fullmsg, &ump->um_secs_fullmsg, 1)) {
+               UFS_UNLOCK(ump);
                ffs_fserr(fs, pip->i_number, "out of inodes");
                uprintf("\n%s: create/symlink failed, no inodes free\n",
                    fs->fs_fsmnt);
+       } else {
+               UFS_UNLOCK(ump);
        }
        return (ENOSPC);
 }
@@ -1369,7 +1371,7 @@ ffs_blkpref_ufs1(ip, lbn, indx, bap)
        struct fs *fs;
        u_int cg, inocg;
        u_int avgbfree, startcg;
-       ufs2_daddr_t pref;
+       ufs2_daddr_t pref, prevbn;
 
        KASSERT(indx <= 0 || bap != NULL, ("need non-NULL bap"));
        mtx_assert(UFS_MTX(ITOUMP(ip)), MA_OWNED);
@@ -1419,7 +1421,15 @@ ffs_blkpref_ufs1(ip, lbn, indx, bap)
         * have a block allocated immediately preceding us, then we need
         * to decide where to start allocating new blocks.
         */
-       if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
+       if (indx ==  0) {
+               prevbn = 0;
+       } else {
+               prevbn = bap[indx - 1];
+               if (UFS_CHECK_BLKNO(ITOVFS(ip), ip->i_number, prevbn,
+                   fs->fs_bsize) != 0)
+                       prevbn = 0;
+       }
+       if (indx % fs->fs_maxbpg == 0 || prevbn == 0) {
                /*
                 * If we are allocating a directory data block, we want
                 * to place it in the metadata area.
@@ -1437,10 +1447,10 @@ ffs_blkpref_ufs1(ip, lbn, indx, bap)
                 * Find a cylinder with greater than average number of
                 * unused data blocks.
                 */
-               if (indx == 0 || bap[indx - 1] == 0)
+               if (indx == 0 || prevbn == 0)
                        startcg = inocg + lbn / fs->fs_maxbpg;
                else
-                       startcg = dtog(fs, bap[indx - 1]) + 1;
+                       startcg = dtog(fs, prevbn) + 1;
                startcg %= fs->fs_ncg;
                avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
                for (cg = startcg; cg < fs->fs_ncg; cg++)
@@ -1458,7 +1468,7 @@ ffs_blkpref_ufs1(ip, lbn, indx, bap)
        /*
         * Otherwise, we just always try to lay things out contiguously.
         */
-       return (bap[indx - 1] + fs->fs_frag);
+       return (prevbn + fs->fs_frag);
 }
 
 /*
@@ -1474,7 +1484,7 @@ ffs_blkpref_ufs2(ip, lbn, indx, bap)
        struct fs *fs;
        u_int cg, inocg;
        u_int avgbfree, startcg;
-       ufs2_daddr_t pref;
+       ufs2_daddr_t pref, prevbn;
 
        KASSERT(indx <= 0 || bap != NULL, ("need non-NULL bap"));
        mtx_assert(UFS_MTX(ITOUMP(ip)), MA_OWNED);
@@ -1524,7 +1534,15 @@ ffs_blkpref_ufs2(ip, lbn, indx, bap)
         * have a block allocated immediately preceding us, then we need
         * to decide where to start allocating new blocks.
         */
-       if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) {
+       if (indx ==  0) {
+               prevbn = 0;
+       } else {
+               prevbn = bap[indx - 1];
+               if (UFS_CHECK_BLKNO(ITOVFS(ip), ip->i_number, prevbn,
+                   fs->fs_bsize) != 0)
+                       prevbn = 0;
+       }
+       if (indx % fs->fs_maxbpg == 0 || prevbn == 0) {
                /*
                 * If we are allocating a directory data block, we want
                 * to place it in the metadata area.
@@ -1542,10 +1560,10 @@ ffs_blkpref_ufs2(ip, lbn, indx, bap)
                 * Find a cylinder with greater than average number of
                 * unused data blocks.
                 */
-               if (indx == 0 || bap[indx - 1] == 0)
+               if (indx == 0 || prevbn == 0)
                        startcg = inocg + lbn / fs->fs_maxbpg;
                else
-                       startcg = dtog(fs, bap[indx - 1]) + 1;
+                       startcg = dtog(fs, prevbn) + 1;
                startcg %= fs->fs_ncg;
                avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
                for (cg = startcg; cg < fs->fs_ncg; cg++)
@@ -1563,7 +1581,7 @@ ffs_blkpref_ufs2(ip, lbn, indx, bap)
        /*
         * Otherwise, we just always try to lay things out contiguously.
         */
-       return (bap[indx - 1] + fs->fs_frag);
+       return (prevbn + fs->fs_frag);
 }
 
 /*

Modified: stable/12/sys/ufs/ffs/ffs_balloc.c
==============================================================================
--- stable/12/sys/ufs/ffs/ffs_balloc.c  Tue Jul 30 23:50:49 2019        
(r350459)
+++ stable/12/sys/ufs/ffs/ffs_balloc.c  Wed Jul 31 00:16:12 2019        
(r350460)
@@ -99,6 +99,7 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, i
        struct fs *fs;
        ufs1_daddr_t nb;
        struct buf *bp, *nbp;
+       struct mount *mp;
        struct ufsmount *ump;
        struct indir indirs[UFS_NIADDR + 2];
        int deallocated, osize, nsize, num, i, error;
@@ -108,13 +109,12 @@ ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, i
        ufs2_daddr_t *lbns_remfree, lbns[UFS_NIADDR + 1];
        int unwindidx = -1;
        int saved_inbdflush;
-       static struct timeval lastfail;
-       static int curfail;
        int gbflags, reclaimed;
 
        ip = VTOI(vp);
        dp = ip->i_din1;
        fs = ITOFS(ip);
+       mp = ITOVFS(ip);
        ump = ITOUMP(ip);
        lbn = lblkno(fs, startoffset);
        size = blkoff(fs, startoffset) + size;
@@ -297,6 +297,11 @@ retry:
                }
                bap = (ufs1_daddr_t *)bp->b_data;
                nb = bap[indirs[i].in_off];
+               if ((error = UFS_CHECK_BLKNO(mp, ip->i_number, nb,
+                   fs->fs_bsize)) != 0) {
+                       brelse(bp);
+                       goto fail;
+               }
                if (i == num)
                        break;
                i += 1;
@@ -315,17 +320,21 @@ retry:
                if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
                    flags | IO_BUFLOCKED, cred, &newb)) != 0) {
                        brelse(bp);
+                       UFS_LOCK(ump);
                        if (DOINGSOFTDEP(vp) && ++reclaimed == 1) {
-                               UFS_LOCK(ump);
                                softdep_request_cleanup(fs, vp, cred,
                                    FLUSH_BLOCKS_WAIT);
                                UFS_UNLOCK(ump);
                                goto retry;
                        }
-                       if (ppsratecheck(&lastfail, &curfail, 1)) {
+                       if (ppsratecheck(&ump->um_last_fullmsg,
+                           &ump->um_secs_fullmsg, 1)) {
+                               UFS_UNLOCK(ump);
                                ffs_fserr(fs, ip->i_number, "filesystem full");
                                uprintf("\n%s: write failed, filesystem "
                                    "is full\n", fs->fs_fsmnt);
+                       } else {
+                               UFS_UNLOCK(ump);
                        }
                        goto fail;
                }
@@ -394,17 +403,21 @@ retry:
                    flags | IO_BUFLOCKED, cred, &newb);
                if (error) {
                        brelse(bp);
+                       UFS_LOCK(ump);
                        if (DOINGSOFTDEP(vp) && ++reclaimed == 1) {
-                               UFS_LOCK(ump);
                                softdep_request_cleanup(fs, vp, cred,
                                    FLUSH_BLOCKS_WAIT);
                                UFS_UNLOCK(ump);
                                goto retry;
                        }
-                       if (ppsratecheck(&lastfail, &curfail, 1)) {
+                       if (ppsratecheck(&ump->um_last_fullmsg,
+                           &ump->um_secs_fullmsg, 1)) {
+                               UFS_UNLOCK(ump);
                                ffs_fserr(fs, ip->i_number, "filesystem full");
                                uprintf("\n%s: write failed, filesystem "
                                    "is full\n", fs->fs_fsmnt);
+                       } else {
+                               UFS_UNLOCK(ump);
                        }
                        goto fail;
                }
@@ -574,6 +587,7 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, i
        ufs_lbn_t lbn, lastlbn;
        struct fs *fs;
        struct buf *bp, *nbp;
+       struct mount *mp;
        struct ufsmount *ump;
        struct indir indirs[UFS_NIADDR + 2];
        ufs2_daddr_t nb, newb, *bap, pref;
@@ -582,13 +596,12 @@ ffs_balloc_ufs2(struct vnode *vp, off_t startoffset, i
        int deallocated, osize, nsize, num, i, error;
        int unwindidx = -1;
        int saved_inbdflush;
-       static struct timeval lastfail;
-       static int curfail;
        int gbflags, reclaimed;
 
        ip = VTOI(vp);
        dp = ip->i_din2;
        fs = ITOFS(ip);
+       mp = ITOVFS(ip);
        ump = ITOUMP(ip);
        lbn = lblkno(fs, startoffset);
        size = blkoff(fs, startoffset) + size;
@@ -884,6 +897,11 @@ retry:
                }
                bap = (ufs2_daddr_t *)bp->b_data;
                nb = bap[indirs[i].in_off];
+               if ((error = UFS_CHECK_BLKNO(mp, ip->i_number, nb,
+                   fs->fs_bsize)) != 0) {
+                       brelse(bp);
+                       goto fail;
+               }
                if (i == num)
                        break;
                i += 1;
@@ -902,17 +920,21 @@ retry:
                if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize,
                    flags | IO_BUFLOCKED, cred, &newb)) != 0) {
                        brelse(bp);
+                       UFS_LOCK(ump);
                        if (DOINGSOFTDEP(vp) && ++reclaimed == 1) {
-                               UFS_LOCK(ump);
                                softdep_request_cleanup(fs, vp, cred,
                                    FLUSH_BLOCKS_WAIT);
                                UFS_UNLOCK(ump);
                                goto retry;
                        }
-                       if (ppsratecheck(&lastfail, &curfail, 1)) {
+                       if (ppsratecheck(&ump->um_last_fullmsg,
+                           &ump->um_secs_fullmsg, 1)) {
+                               UFS_UNLOCK(ump);
                                ffs_fserr(fs, ip->i_number, "filesystem full");
                                uprintf("\n%s: write failed, filesystem "
                                    "is full\n", fs->fs_fsmnt);
+                       } else {
+                               UFS_UNLOCK(ump);
                        }
                        goto fail;
                }
@@ -982,17 +1004,21 @@ retry:
                    flags | IO_BUFLOCKED, cred, &newb);
                if (error) {
                        brelse(bp);
+                       UFS_LOCK(ump);
                        if (DOINGSOFTDEP(vp) && ++reclaimed == 1) {
-                               UFS_LOCK(ump);
                                softdep_request_cleanup(fs, vp, cred,
                                    FLUSH_BLOCKS_WAIT);
                                UFS_UNLOCK(ump);
                                goto retry;
                        }
-                       if (ppsratecheck(&lastfail, &curfail, 1)) {
+                       if (ppsratecheck(&ump->um_last_fullmsg,
+                           &ump->um_secs_fullmsg, 1)) {
+                               UFS_UNLOCK(ump);
                                ffs_fserr(fs, ip->i_number, "filesystem full");
                                uprintf("\n%s: write failed, filesystem "
                                    "is full\n", fs->fs_fsmnt);
+                       } else {
+                               UFS_UNLOCK(ump);
                        }
                        goto fail;
                }

Modified: stable/12/sys/ufs/ffs/ffs_extern.h
==============================================================================
--- stable/12/sys/ufs/ffs/ffs_extern.h  Tue Jul 30 23:50:49 2019        
(r350459)
+++ stable/12/sys/ufs/ffs/ffs_extern.h  Wed Jul 31 00:16:12 2019        
(r350460)
@@ -68,6 +68,7 @@ ufs2_daddr_t ffs_blkpref_ufs1(struct inode *, ufs_lbn_
 ufs2_daddr_t ffs_blkpref_ufs2(struct inode *, ufs_lbn_t, int, ufs2_daddr_t *);
 void   ffs_blkrelease_finish(struct ufsmount *, u_long);
 u_long ffs_blkrelease_start(struct ufsmount *, struct vnode *, ino_t);
+int    ffs_check_blkno(struct mount *, ino_t, ufs2_daddr_t, int);
 int    ffs_checkfreefile(struct fs *, struct vnode *, ino_t);
 void   ffs_clrblock(struct fs *, u_char *, ufs1_daddr_t);
 void   ffs_clusteracct(struct fs *, struct cg *, ufs1_daddr_t, int);

Modified: stable/12/sys/ufs/ffs/ffs_softdep.c
==============================================================================
--- stable/12/sys/ufs/ffs/ffs_softdep.c Tue Jul 30 23:50:49 2019        
(r350459)
+++ stable/12/sys/ufs/ffs/ffs_softdep.c Wed Jul 31 00:16:12 2019        
(r350460)
@@ -8109,6 +8109,7 @@ indir_trunc(freework, dbn, lbn)
        struct buf *bp;
        struct fs *fs;
        struct indirdep *indirdep;
+       struct mount *mp;
        struct ufsmount *ump;
        ufs1_daddr_t *bap1;
        ufs2_daddr_t nb, nnb, *bap2;
@@ -8118,7 +8119,8 @@ indir_trunc(freework, dbn, lbn)
        int goingaway, freedeps, needj, level, cnt, i;
 
        freeblks = freework->fw_freeblks;
-       ump = VFSTOUFS(freeblks->fb_list.wk_mp);
+       mp = freeblks->fb_list.wk_mp;
+       ump = VFSTOUFS(mp);
        fs = ump->um_fs;
        /*
         * Get buffer of block pointers to be freed.  There are three cases:
@@ -8211,6 +8213,9 @@ indir_trunc(freework, dbn, lbn)
         */
        key = ffs_blkrelease_start(ump, freeblks->fb_devvp, freeblks->fb_inum);
        for (i = freework->fw_off; i < NINDIR(fs); i++, nb = nnb) {
+               if (UFS_CHECK_BLKNO(mp, freeblks->fb_inum, nb,
+                   fs->fs_bsize) != 0)
+                       nb = 0;
                if (i != NINDIR(fs) - 1) {
                        if (ufs1fmt)
                                nnb = bap1[i+1];

Modified: stable/12/sys/ufs/ffs/ffs_subr.c
==============================================================================
--- stable/12/sys/ufs/ffs/ffs_subr.c    Tue Jul 30 23:50:49 2019        
(r350459)
+++ stable/12/sys/ufs/ffs/ffs_subr.c    Wed Jul 31 00:16:12 2019        
(r350460)
@@ -133,7 +133,56 @@ ffs_load_inode(struct buf *bp, struct inode *ip, struc
                ip->i_gid = ip->i_din2->di_gid;
        }
 }
-#endif /* KERNEL */
+
+/*
+ * Verify that a filesystem block number is a valid data block.
+ * This routine is only called on untrusted filesystems.
+ */
+int
+ffs_check_blkno(struct mount *mp, ino_t inum, ufs2_daddr_t daddr, int blksize)
+{
+       struct fs *fs;
+       struct ufsmount *ump;
+       ufs2_daddr_t end_daddr;
+       int cg, havemtx;
+
+       KASSERT((mp->mnt_flag & MNT_UNTRUSTED) != 0,
+           ("ffs_check_blkno called on a trusted file system"));
+       ump = VFSTOUFS(mp);
+       fs = ump->um_fs;
+       cg = dtog(fs, daddr);
+       end_daddr = daddr + numfrags(fs, blksize);
+       /*
+        * Verify that the block number is a valid data block. Also check
+        * that it does not point to an inode block or a superblock. Accept
+        * blocks that are unalloacted (0) or part of snapshot metadata
+        * (BLK_NOCOPY or BLK_SNAP).
+        *
+        * Thus, the block must be in a valid range for the filesystem and
+        * either in the space before a backup superblock (except the first
+        * cylinder group where that space is used by the bootstrap code) or
+        * after the inode blocks and before the end of the cylinder group.
+        */
+       if ((uint64_t)daddr <= BLK_SNAP ||
+           ((uint64_t)end_daddr <= fs->fs_size &&
+           ((cg > 0 && end_daddr <= cgsblock(fs, cg)) ||
+           (daddr >= cgdmin(fs, cg) &&
+           end_daddr <= cgbase(fs, cg) + fs->fs_fpg))))
+               return (0);
+       if ((havemtx = mtx_owned(UFS_MTX(ump))) == 0)
+               UFS_LOCK(ump);
+       if (ppsratecheck(&ump->um_last_integritymsg,
+           &ump->um_secs_integritymsg, 1)) {
+               UFS_UNLOCK(ump);
+               uprintf("\n%s: inode %jd, out-of-range indirect block "
+                   "number %jd\n", mp->mnt_stat.f_mntonname, inum, daddr);
+               if (havemtx)
+                       UFS_LOCK(ump);
+       } else if (!havemtx)
+               UFS_UNLOCK(ump);
+       return (EIO);
+}
+#endif /* _KERNEL */
 
 /*
  * These are the low-level functions that actually read and write

Modified: stable/12/sys/ufs/ffs/ffs_vfsops.c
==============================================================================
--- stable/12/sys/ufs/ffs/ffs_vfsops.c  Tue Jul 30 23:50:49 2019        
(r350459)
+++ stable/12/sys/ufs/ffs/ffs_vfsops.c  Wed Jul 31 00:16:12 2019        
(r350460)
@@ -143,7 +143,7 @@ static struct buf_ops ffs_ops = {
 static const char *ffs_opts[] = { "acls", "async", "noatime", "noclusterr",
     "noclusterw", "noexec", "export", "force", "from", "groupquota",
     "multilabel", "nfsv4acls", "fsckpid", "snapshot", "nosuid", "suiddir",
-    "nosymfollow", "sync", "union", "userquota", NULL };
+    "nosymfollow", "sync", "union", "userquota", "untrusted", NULL };
 
 static int
 ffs_mount(struct mount *mp)
@@ -182,6 +182,9 @@ ffs_mount(struct mount *mp)
                return (error);
 
        mntorflags = 0;
+       if (vfs_getopt(mp->mnt_optnew, "untrusted", NULL, NULL) == 0)
+               mntorflags |= MNT_UNTRUSTED;
+
        if (vfs_getopt(mp->mnt_optnew, "acls", NULL, NULL) == 0)
                mntorflags |= MNT_ACLS;
 
@@ -911,6 +914,10 @@ ffs_mountfs(devvp, mp, td)
        ump->um_ifree = ffs_ifree;
        ump->um_rdonly = ffs_rdonly;
        ump->um_snapgone = ffs_snapgone;
+       if ((mp->mnt_flag & MNT_UNTRUSTED) != 0)
+               ump->um_check_blkno = ffs_check_blkno;
+       else
+               ump->um_check_blkno = NULL;
        mtx_init(UFS_MTX(ump), "FFS", "FFS Lock", MTX_DEF);
        ffs_oldfscompat_read(fs, ump, fs->fs_sblockloc);
        fs->fs_ronly = ronly;

Modified: stable/12/sys/ufs/ufs/ufs_bmap.c
==============================================================================
--- stable/12/sys/ufs/ufs/ufs_bmap.c    Tue Jul 30 23:50:49 2019        
(r350459)
+++ stable/12/sys/ufs/ufs/ufs_bmap.c    Wed Jul 31 00:16:12 2019        
(r350460)
@@ -264,8 +264,16 @@ ufs_bmaparray(vp, bn, bnp, nbp, runp, runb)
                if (error != 0)
                        return (error);
 
-               if (I_IS_UFS1(ip)) {
+               if (I_IS_UFS1(ip))
                        daddr = ((ufs1_daddr_t *)bp->b_data)[ap->in_off];
+               else
+                       daddr = ((ufs2_daddr_t *)bp->b_data)[ap->in_off];
+               if ((error = UFS_CHECK_BLKNO(mp, ip->i_number, daddr,
+                    mp->mnt_stat.f_iosize)) != 0) {
+                       bqrelse(bp);
+                       return (error);
+               }
+               if (I_IS_UFS1(ip)) {
                        if (num == 1 && daddr && runp) {
                                for (bn = ap->in_off + 1;
                                    bn < MNINDIR(ump) && *runp < maxrun &&
@@ -284,7 +292,6 @@ ufs_bmaparray(vp, bn, bnp, nbp, runp, runb)
                        }
                        continue;
                }
-               daddr = ((ufs2_daddr_t *)bp->b_data)[ap->in_off];
                if (num == 1 && daddr && runp) {
                        for (bn = ap->in_off + 1;
                            bn < MNINDIR(ump) && *runp < maxrun &&

Modified: stable/12/sys/ufs/ufs/ufsmount.h
==============================================================================
--- stable/12/sys/ufs/ufs/ufsmount.h    Tue Jul 30 23:50:49 2019        
(r350459)
+++ stable/12/sys/ufs/ufs/ufsmount.h    Wed Jul 31 00:16:12 2019        
(r350460)
@@ -100,6 +100,10 @@ struct ufsmount {
        char    um_qflags[MAXQUOTAS];           /* (i) quota specific flags */
        int64_t um_savedmaxfilesize;            /* (c) track maxfilesize */
        u_int   um_flags;                       /* (i) filesystem flags */
+       struct  timeval um_last_fullmsg;        /* (i) last full msg time */
+       int     um_secs_fullmsg;                /* (i) seconds since full msg */
+       struct  timeval um_last_integritymsg;   /* (i) last integrity msg */
+       int     um_secs_integritymsg;           /* (i) secs since integ msg */
        u_int   um_trim_inflight;               /* (i) outstanding trim count */
        u_int   um_trim_inflight_blks;          /* (i) outstanding trim blks */
        u_long  um_trim_total;                  /* (i) total trim count */
@@ -119,6 +123,7 @@ struct ufsmount {
        void    (*um_ifree)(struct ufsmount *, struct inode *);
        int     (*um_rdonly)(struct inode *);
        void    (*um_snapgone)(struct inode *);
+       int     (*um_check_blkno)(struct mount *, ino_t, daddr_t, int);
 };
 
 /*
@@ -130,15 +135,22 @@ struct ufsmount {
 /*
  * function prototypes
  */
-#define        UFS_BALLOC(aa, bb, cc, dd, ee, ff) 
VFSTOUFS((aa)->v_mount)->um_balloc(aa, bb, cc, dd, ee, ff)
-#define        UFS_BLKATOFF(aa, bb, cc, dd) 
VFSTOUFS((aa)->v_mount)->um_blkatoff(aa, bb, cc, dd)
-#define        UFS_TRUNCATE(aa, bb, cc, dd) 
VFSTOUFS((aa)->v_mount)->um_truncate(aa, bb, cc, dd)
+#define        UFS_BALLOC(aa, bb, cc, dd, ee, ff) \
+       VFSTOUFS((aa)->v_mount)->um_balloc(aa, bb, cc, dd, ee, ff)
+#define        UFS_BLKATOFF(aa, bb, cc, dd) \
+       VFSTOUFS((aa)->v_mount)->um_blkatoff(aa, bb, cc, dd)
+#define        UFS_TRUNCATE(aa, bb, cc, dd) \
+       VFSTOUFS((aa)->v_mount)->um_truncate(aa, bb, cc, dd)
 #define        UFS_UPDATE(aa, bb) VFSTOUFS((aa)->v_mount)->um_update(aa, bb)
-#define        UFS_VALLOC(aa, bb, cc, dd) 
VFSTOUFS((aa)->v_mount)->um_valloc(aa, bb, cc, dd)
+#define        UFS_VALLOC(aa, bb, cc, dd) \
+       VFSTOUFS((aa)->v_mount)->um_valloc(aa, bb, cc, dd)
 #define        UFS_VFREE(aa, bb, cc) VFSTOUFS((aa)->v_mount)->um_vfree(aa, bb, 
cc)
 #define        UFS_IFREE(aa, bb) ((aa)->um_ifree(aa, bb))
 #define        UFS_RDONLY(aa) (ITOUMP(aa)->um_rdonly(aa))
 #define        UFS_SNAPGONE(aa) (ITOUMP(aa)->um_snapgone(aa))
+#define        UFS_CHECK_BLKNO(aa, bb, cc, dd)                 \
+       (VFSTOUFS(aa)->um_check_blkno == NULL ? 0 :     \
+        VFSTOUFS(aa)->um_check_blkno(aa, bb, cc, dd))
 
 #define        UFS_LOCK(aa)    mtx_lock(&(aa)->um_lock)
 #define        UFS_UNLOCK(aa)  mtx_unlock(&(aa)->um_lock)
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to