svn commit: r350460 - in stable/12: sbin/fsck_ffs sbin/mount sys/sys sys/ufs/ffs sys/ufs/ufs
Kirk McKusick
mckusick at FreeBSD.org
Wed Jul 31 00:16:16 UTC 2019
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)
More information about the svn-src-all
mailing list